[
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: BUG报告\ntitle: \"[BUG] 请填写简短易读的标题\"\ndescription: \"使用过程中遇到了BUG\"\nassignees: SlotSun\nlabels:\n  - \"bug\"\nbody:\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: 提交前确认\n      description: 在提交前，请确认以下内容\n      options:\n        - label: 先去Issues列表中查找下是否存在相似的Issue，如果有了就不要重复发了\n          required: true\n        - label: 我正在使用最新版本的 Slive\n          required: true\n\n  - type: textarea\n    id: description\n    validations:\n      required: true\n    attributes:\n      label: BUG内容\n      description: 请详细描述你遇到的问题\n\n  - type: textarea\n    id: steps\n    validations:\n      required: true\n    attributes:\n      label: 重现步骤\n      render: plain text\n      description: 请详细描述重现步骤\n      placeholder: |\n        1. xxxx\n        2. xxxx\n        3. xxxx\n\n  - type: textarea\n    id: screenshots\n    attributes:\n      label: 截图或视频\n      description: 请上传BUG截图、或视频\n\n  - type: textarea\n    id: logs\n    attributes:\n      label: 日志\n      description: 请上传日志文件\n      placeholder: |\n        可以在[其他设置]-[开启日志记录]后获取日志文件\n \n  - type: dropdown\n    id: release-type\n    validations:\n      required: true\n    attributes:\n      label: 使用版本来源\n      description: 使用的是什么版本，从哪里下载的\n      options:\n        - 正式版(Releases)\n        - 开发版(Actions)\n        - 上游仓库(xiaoyaocz)\n      default: 0\n\n  - type: dropdown\n    id: platform\n    validations:\n      required: true\n    attributes:\n      label: 运行平台\n      description: 选择你当前运行应用的平台\n      multiple: false\n      options:\n        - Windows\n        - macOS\n        - Linux\n        - Android\n        - iOS\n\n  - type: input\n    id: os-version\n    attributes:\n      label: 操作系统信息\n      description: 请填写你的操作系统信息版本\n      placeholder: ex. Windows 10 21H1 / MIUI 15 Android 12\n    validations:\n      required: true\n\n  - type: input\n    id: device\n    attributes:\n      label: 设备信息\n      description: 请填写你的设备信息\n      placeholder: ex. PC / iPhone 12 Pro Max\n    validations:\n      required: true\n\n  - type: textarea\n    id: remark\n    attributes:\n      label: 备注\n      description: 其他信息\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature.yml",
    "content": "name: 功能请求\r\ntitle: \"[Feature] 请填写简短易读的标题\"\r\ndescription: \"请求开发新的功能/优化某项功能\"\r\nassignees: SlotSun\r\nlabels:\r\n  - \"enhancement\"\r\nbody:\r\n  - type: markdown\r\n    attributes:\r\n      value: |\r\n        你的Issue大概率会搁置很久，除非是那种我能随手解决的。\r\n        暂时不会添加新的平台支持（因为我自己用不上）。如果你有开发能力，建议的自行开发后提交个PR。\r\n\r\n  - type: checkboxes\r\n    id: terms\r\n    attributes:\r\n      label: 非重复的Issue\r\n      description: 先去Issues列表中查找下是否存在相似的Issue，如果有了就不要重复发了\r\n      options:\r\n        - label: 已确认没有相似的Issue\r\n          required: true\r\n\r\n  - type: textarea\r\n    id: description\r\n    validations:\r\n      required: true\r\n    attributes:\r\n      label: 功能描述\r\n      description: 请填写功能描述，如果你有多个建议、请求，请分开提交Issue\r\n\r\n  - type: checkboxes\r\n    id: platform\r\n    attributes:\r\n      label: 平台\r\n      description: 这个功能针对什么平台\r\n      options:\r\n        - label: Android\r\n        - label: iOS\r\n        - label: MacOS\r\n        - label: Windows\r\n        - label: Linux\r\n\r\n  - type: textarea\r\n    id: additional\r\n    attributes:\r\n      label: 附加信息\r\n      description: 可以附加相关截图、视频或链接（好让我知道要我抄哪个APP）\r\n\r\n"
  },
  {
    "path": ".github/workflows/docs-deploy.yaml",
    "content": "﻿name: docs-deploy\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - 'master'\n    paths:\n      - 'docs/**'\n\n# 设置 GITHUB_TOKEN 的权限，以允许部署到 GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# 只允许同时进行一次部署，跳过正在运行和最新队列之间的运行队列\n# 但是，不要取消正在进行的运行，因为我们希望允许这些生产部署完成\nconcurrency:\n  group: pages\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - uses: pnpm/action-setup@v3\n        with:\n          version: latest\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n          cache: pnpm\n          cache-dependency-path: docs/pnpm-lock.yaml\n\n      - name: Setup Pages\n        uses: actions/configure-pages@v5\n\n      - name: start build\n        run: |\n          pnpm install\n          pnpm docs:build\n        working-directory: docs\n\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: docs/.vitepress/dist\n\n  # 部署工作\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    needs: build\n    runs-on: ubuntu-latest\n    name: Deploy\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4"
  },
  {
    "path": ".github/workflows/pr.yaml",
    "content": "name: PR Check\n\non:\n  pull_request:\n    branches:\n      - main\n      - dev\n\njobs:\n  build-mac-ios-android:\n    runs-on: macos-latest\n    steps:\n      - name: Checkout PR code\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: \"21\"\n          cache: \"gradle\"\n\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-macos-desktop\n\n      - name: Restore packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n\n      - name: Install appdmg\n        run: npm install -g appdmg\n\n      - name: Install fast-forge\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n\n      - name: Setup Xcode\n        uses: maxim-lobanov/setup-xcode@v1\n        with:\n          xcode-version: latest-stable\n\n      - name: Build APK\n        run: |\n          cd simple_live_app\n          flutter build apk --debug\n\n      - name: Build IPA\n        run: |\n          cd simple_live_app\n          flutter build ios --no-codesign\n\n      - name: Build MacOS\n        run: |\n          cd simple_live_app\n          fastforge package --platform macos --targets dmg,zip --skip-clean\n\n  build-linux:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    steps:\n      - name: Checkout PR code\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          channel: master\n\n      - name: Install Dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y clang cmake libgtk-3-dev unzip libasound2-dev gcc g++ autoconf automake \\\n              debhelper glslang-dev ladspa-sdk xutils-dev libasound2-dev libarchive-dev libbluray-dev \\\n              libdav1d-dev libdvdnav-dev libegl1-mesa-dev libepoxy-dev libfontconfig-dev libfreetype6-dev \\\n              libfribidi-dev libgl1-mesa-dev libgbm-dev libgme-dev libgsm1-dev libharfbuzz-dev libjpeg-dev \\\n              libbrotli-dev liblcms2-dev libmodplug-dev libmp3lame-dev libopenal-dev \\\n              libopus-dev libopencore-amrnb-dev libopencore-amrwb-dev libpulse-dev librtmp-dev \\\n              libsdl2-dev libsixel-dev libssh-dev libsoxr-dev libspeex-dev libtool \\\n              libv4l-dev libva-dev libvdpau-dev libvorbis-dev libvo-amrwbenc-dev \\\n              libunwind-dev libvpx-dev libwayland-dev libx11-dev libxext-dev libdrm-dev \\\n              libxkbcommon-dev libxrandr-dev libxss-dev libxv-dev libxvidcore-dev \\\n              linux-libc-dev nasm ninja-build pkg-config python3 python3-docutils wayland-protocols \\\n              x11proto-core-dev zlib1g-dev libfdk-aac-dev libtheora-dev libwebp-dev \\\n              unixodbc-dev libpq-dev libxxhash-dev libaom-dev libbs2b-dev libcaca-dev libcdio-paranoia-dev\n\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-linux-desktop\n\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n\n      - name: Install fast-forge\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n\n      - name: Build Linux\n        run: |\n          cd simple_live_app\n          fastforge package --platform linux --targets deb,zip --skip-clean\n          cd build/dist/*\n          mv simple_live_app-*-linux.deb simplelive-${{ matrix.arch }}-linux.deb\n          mv simple_live_app-*-linux.zip simplelive-${{ matrix.arch }}-linux.zip\n\n  build-windows:\n    runs-on: windows-latest\n    steps:\n      - name: Checkout PR code\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-windows-desktop\n\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter clean\n          flutter pub get\n\n      - name: Install fast-forge\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n\n      - name: Build Windows\n        run: |\n          cd simple_live_app\n          fastforge package --platform windows --targets msix,zip --skip-clean\n\n  # 打包 Flatpak\n  build-flatpak:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - name: Checkout PR code\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n      # 安装依赖\n      - name: Install dependencies\n        run: |\n          sudo add-apt-repository -y ppa:flatpak/stable\n          sudo apt-get update -q\n          sudo apt-get install -y flatpak flatpak-builder ca-certificates gnupg software-properties-common\n          flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo\n          git config --global protocol.file.allow always\n      # 构建 Flatpak bundle\n      - name: Build flatpak\n        run: |\n          flatpak-builder build-dir flatpak/flatpak-manifest.yaml \\\n            --arch=${{ matrix.arch }} \\\n            --repo=${{ matrix.arch }} \\\n            --force-clean \\\n            --user \\\n            --install-deps-from=flathub \\\n            --ccache \\\n            --disable-rofiles-fuse\n"
  },
  {
    "path": ".github/workflows/publish_app_dev.yaml",
    "content": "name: app-build-action-dev\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - 'dev'\n\n# If previous workflow is still running, we push again, we will cancel the previous workflow\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref_name }}\n  cancel-in-progress: true\n\njobs:\n\n  # packing android on ubuntu, macos slowly\n  build-android:\n    runs-on: ubuntu-latest\n    permissions: write-all\n\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v6\n        with:\n          ref: dev\n\n      # APK 签名设置\n      - name: Download Android keystore\n        id: android_keystore\n        uses: timheuer/base64-to-file@v1.2\n        with:\n          fileName: keystore.jks\n          encodedString: ${{ secrets.KEYSTORE_BASE64 }}\n      - name: Create key.properties\n        run: |\n          echo \"${{ secrets.FIREBASE_JSON }}\" | base64 --decode > simple_live_app/android/app/google-services.json\n          echo \"${{ secrets.FIREBASE_OPTIONS_DART }}\" | base64 --decode > simple_live_app/lib/firebase_options.dart\n          echo \"storeFile=${{ steps.android_keystore.outputs.filePath }}\" > simple_live_app/android/key.properties\n          echo \"storePassword=${{ secrets.STORE_PASSWORD }}\" >> simple_live_app/android/key.properties\n          echo \"keyPassword=${{ secrets.KEY_PASSWORD }}\" >> simple_live_app/android/key.properties\n          echo \"keyAlias=${{ secrets.KEY_ALIAS }}\" >> simple_live_app/android/key.properties\n\n      # 设置 JAVA 环境\n      - uses: actions/setup-java@v5\n        with:\n          distribution: \"zulu\"\n          java-version: \"17\"\n          cache: \"gradle\"\n          cache-dependency-path: |\n            simple_live_app/android/*.gradle*\n            simple_live_app/android/**/gradle-wrapper.properties\n\n      # 设置 Flutter\n      - name: Flutter action\n        uses: subosito/flutter-action@v2\n        with:\n          channel: stable\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n\n      # 更新 Flutter 的 packages\n      - name: Restore packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n\n      # 打包 APK\n      - name: Build APK\n        run: |\n          cd simple_live_app\n          flutter build apk --release --split-per-abi\n\n      # 上传 Artifacts\n      - name: Upload APK to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: android\n          path: |\n            simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk\n      \n\n  # 打包iOS、Mac\n  build-mac-ios:\n    # https://github.com/actions/runner-images/issues/12541\n    runs-on: macos-15\n\n    permissions:\n      contents: write\n\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n        with:\n          ref: dev\n\n      # 设置 JAVA 环境\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: \"21\"\n          cache: \"gradle\"\n\n      # 设置 Flutter\n      - name: Flutter action\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true \n\n      # 打开 MAC Desktop 支持\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-macos-desktop\n\n      # 更新 Flutter 的 packages\n      - name: Restore packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n\n      # 安装 appdmg npm install -g appdmg\n      - name: Install appdmg\n        run: npm install -g appdmg\n\n      # 设置 Fastforge 环境\n      - name: Install fast-forge\n        run: | \n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n\n      # 打包 iOS\n      - name: Build IPA\n        run: |\n          cd simple_live_app\n          flutter build ios --release --no-codesign\n\n      # 创建未签名 ipa\n      - name: Create IPA\n        run: |\n          cd simple_live_app\n          mkdir build/ios/iphoneos/Payload\n          cp -R build/ios/iphoneos/Runner.app build/ios/iphoneos/Payload/Runner.app\n          cd build/ios/iphoneos/\n          zip -q -r ios_no_sign.ipa Payload\n          cd ../../..\n\n      # 上传 IPA 至 Artifacts\n      - name: Upload IPA to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: ios\n          path: |\n            simple_live_app/build/ios/iphoneos/ios_no_sign.ipa\n\n      # 打包 MAC\n      - name: Build MacOS\n        run: |\n          cd simple_live_app\n          fastforge package --platform macos --targets dmg,zip --skip-clean\n      \n      # 上传 MAC 至 Artifacts\n      - name: Upload MacOS to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: mac\n          path: |\n            simple_live_app/build/dist/*/*.dmg\n            simple_live_app/build/dist/*/*.zip\n      # 完成\n      - run: echo \"🍏 This job's status is ${{ job.status }}.\"\n\n  # 打包 Linux\n  build-linux:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n        with:\n          ref: dev\n      # 设置 Flutter 环境\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          channel: master\n      # 安装依赖\n      - name: Update apt-get\n        run: sudo apt-get update\n      - name: Install Dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y clang cmake libgtk-3-dev unzip libasound2-dev gcc g++ autoconf automake \\\n              debhelper glslang-dev ladspa-sdk xutils-dev libasound2-dev libarchive-dev libbluray-dev \\\n              libdav1d-dev libdvdnav-dev libegl1-mesa-dev libepoxy-dev libfontconfig-dev libfreetype6-dev \\\n              libfribidi-dev libgl1-mesa-dev libgbm-dev libgme-dev libgsm1-dev libharfbuzz-dev libjpeg-dev \\\n              libbrotli-dev liblcms2-dev libmodplug-dev libmp3lame-dev libopenal-dev \\\n              libopus-dev libopencore-amrnb-dev libopencore-amrwb-dev libpulse-dev librtmp-dev \\\n              libsdl2-dev libsixel-dev libssh-dev libsoxr-dev libspeex-dev libtool \\\n              libv4l-dev libva-dev libvdpau-dev libvorbis-dev libvo-amrwbenc-dev \\\n              libunwind-dev libvpx-dev libwayland-dev libx11-dev libxext-dev libdrm-dev \\\n              libxkbcommon-dev libxrandr-dev libxss-dev libxv-dev libxvidcore-dev \\\n              linux-libc-dev nasm ninja-build pkg-config python3 python3-docutils wayland-protocols \\\n              x11proto-core-dev zlib1g-dev libfdk-aac-dev libtheora-dev libwebp-dev \\\n              unixodbc-dev libpq-dev libxxhash-dev libaom-dev libbs2b-dev libcaca-dev libcdio-paranoia-dev\n      # 打开 Linux Desktop 支持\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-linux-desktop\n      # 更新 Flutter 的 packages\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n      # 设置 Fastforge 环境\n      - name: Install fast-forge\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n      # build Linux DEB \\ ZIP\n      - name: Build Linux\n        run: |\n          cd simple_live_app\n          fastforge package --platform linux --targets deb,zip --skip-clean\n          cd build/dist/*\n          mv simple_live_app-*-linux.deb Slive-${{ matrix.arch }}-linux.deb\n          mv simple_live_app-*-linux.zip Slive-${{ matrix.arch }}-linux.zip\n      # 上传 Linux 包至 Artifacts\n      - name: Upload Linux APP to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: linux-${{ matrix.arch }}\n          path: |\n            simple_live_app/build/dist/*/*.deb\n            simple_live_app/build/dist/*/*.zip\n\n      # 完成\n      - run: echo \"🍏 Linux job's status is ${{ job.status }}.\"\n\n  # 打包 Windows\n  build-windows:\n    runs-on: windows-latest\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n        with:\n          ref: dev\n      # 设置 Flutter 环境\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-windows-desktop\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter clean\n          flutter pub get\n      # 设置 Fastforge 环境 和 Inno Setup\n      - name: Install fast-forge and Inno Setup\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n          choco install innosetup\n      # 添加中文安装引导\n      - name: Add Chinese language file for Inno Setup\n        run: |\n          cd simple_live_app\n          Copy-Item \"windows/packaging/exe/ChineseSimplified.isl\" \"C:\\Program Files (x86)\\Inno Setup 6\\Languages\\ChineseSimplified.isl\"\n        shell: powershell\n      # build Windows ZIP\\MSIX\\EXE\n      - name: Build Windows\n        run: |\n          cd simple_live_app\n          fastforge package --platform windows --targets msix,zip,exe --skip-clean\n          cd build/dist/*\n          Get-ChildItem \"simple_live_app-*\" | ForEach-Object {\n              $newName = $_.Name -replace '^simple_live_app', 'Slive'\n              Rename-Item $_ -NewName $newName\n          }\n        shell: pwsh\n      # 上传 Windows 至 Artifacts\n      - name: Upload Windows APP to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: windows\n          path: |\n            simple_live_app/build/dist/*/*.msix\n            simple_live_app/build/dist/*/*.zip\n            simple_live_app/build/dist/*/*.exe\n      # 完成\n      - run: echo \"🍏 Windows job's status is ${{ job.status }}.\"\n\n  # 打包 Flatpak\n  build-flatpak:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n        with:\n          ref: dev\n      # 安装依赖\n      - name: Install dependencies\n        run: |\n          sudo add-apt-repository -y ppa:flatpak/stable\n          sudo apt-get update -q\n          sudo apt-get install -y flatpak flatpak-builder ca-certificates gnupg software-properties-common\n          flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo\n          git config --global protocol.file.allow always\n      # 构建 Flatpak bundle\n      - name: Build flatpak bundle\n        run: |\n          flatpak-builder build-dir flatpak/flatpak-manifest.yaml \\\n            --arch=${{ matrix.arch }} \\\n            --repo=${{ matrix.arch }} \\\n            --force-clean \\\n            --user \\\n            --install-deps-from=flathub \\\n            --ccache \\\n            --disable-rofiles-fuse\n          flatpak build-bundle ${{ matrix.arch }} Slive-${{ matrix.arch }}.flatpak io.github.SlotSun.Slive\n\n      # 上传 Flatpak 包至 Artifacts\n      - name: Upload linux flatpak to artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: linux-flatpak-${{ matrix.arch }}\n          path: Slive-*.flatpak\n\n      # 完成\n      - run: echo \"🍏 Flatpak job's status is ${{ job.status }}.\"\n"
  },
  {
    "path": ".github/workflows/publish_app_release.yml",
    "content": "name: app-build-action-release\n# 推送 Tag 时触发\non:\n  workflow_dispatch: # 允许手动触发\n  push:\n    tags:\n      - \"v*\"\njobs:\n  # 打包 Android\n  build-android:\n    runs-on: ubuntu-latest\n    permissions: write-all\n\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v6\n\n      # APK 签名设置\n      - name: Download Android keystore\n        id: android_keystore\n        uses: timheuer/base64-to-file@v1.2\n        with:\n          fileName: keystore.jks\n          encodedString: ${{ secrets.KEYSTORE_BASE64 }}\n      - name: Create key.properties\n        run: |\n          echo \"${{ secrets.FIREBASE_JSON }}\" | base64 --decode > simple_live_app/android/app/google-services.json\n          echo \"${{ secrets.FIREBASE_OPTIONS_DART }}\" | base64 --decode > simple_live_app/lib/firebase_options.dart\n          echo \"storeFile=${{ steps.android_keystore.outputs.filePath }}\" > simple_live_app/android/key.properties\n          echo \"storePassword=${{ secrets.STORE_PASSWORD }}\" >> simple_live_app/android/key.properties\n          echo \"keyPassword=${{ secrets.KEY_PASSWORD }}\" >> simple_live_app/android/key.properties\n          echo \"keyAlias=${{ secrets.KEY_ALIAS }}\" >> simple_live_app/android/key.properties\n\n      # 设置 JAVA 环境\n      - uses: actions/setup-java@v5\n        with:\n          distribution: \"zulu\"\n          java-version: \"17\"\n          cache: \"gradle\"\n          cache-dependency-path: |\n            simple_live_app/android/*.gradle*\n            simple_live_app/android/**/gradle-wrapper.properties\n\n      # 设置 Flutter\n      - name: Flutter action\n        uses: subosito/flutter-action@v2\n        with:\n          channel: stable\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n\n      # 更新 Flutter 的 packages\n      - name: Restore packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n\n      # 打包 APK\n      - name: Build APK\n        run: |\n          cd simple_live_app\n          flutter build apk --release --split-per-abi\n\n      # 上传 APK 至 Artifacts\n      - name: Upload APK to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: android\n          path: |\n            simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk\n\n      # 读取版本信息\n      - name: Read version\n        id: version\n        uses: juliangruber/read-file-action@v1\n        with:\n          path: assets/app_version.json\n      - name: Echo version\n        run: echo \"${{ fromJson(steps.version.outputs.content).version }}\"\n      - name: Echo version content\n        run: echo \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n\n      # 上传至 Release\n      - name: Upload Release\n        uses: softprops/action-gh-release@v1\n        with:\n          name: \"${{ fromJson(steps.version.outputs.content).version }}\"\n          body: \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n          prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }}\n          token: ${{ secrets.TOKEN }}\n          files: |\n            simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk\n            simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk\n      # 完成\n      - run: echo \"🍏 This job's status is ${{ job.status }}.\"\n\n  # 打包 Linux\n  build-linux:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n      # 设置 Flutter 环境\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          channel: master\n      # 安装依赖\n      - name: Update apt-get\n        run: sudo apt-get update\n      - name: Install Dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y clang cmake libgtk-3-dev unzip libasound2-dev gcc g++ autoconf automake \\\n              debhelper glslang-dev ladspa-sdk xutils-dev libasound2-dev libarchive-dev libbluray-dev \\\n              libdav1d-dev libdvdnav-dev libegl1-mesa-dev libepoxy-dev libfontconfig-dev libfreetype6-dev \\\n              libfribidi-dev libgl1-mesa-dev libgbm-dev libgme-dev libgsm1-dev libharfbuzz-dev libjpeg-dev \\\n              libbrotli-dev liblcms2-dev libmodplug-dev libmp3lame-dev libopenal-dev \\\n              libopus-dev libopencore-amrnb-dev libopencore-amrwb-dev libpulse-dev librtmp-dev \\\n              libsdl2-dev libsixel-dev libssh-dev libsoxr-dev libspeex-dev libtool \\\n              libv4l-dev libva-dev libvdpau-dev libvorbis-dev libvo-amrwbenc-dev \\\n              libunwind-dev libvpx-dev libwayland-dev libx11-dev libxext-dev libdrm-dev \\\n              libxkbcommon-dev libxrandr-dev libxss-dev libxv-dev libxvidcore-dev \\\n              linux-libc-dev nasm ninja-build pkg-config python3 python3-docutils wayland-protocols \\\n              x11proto-core-dev zlib1g-dev libfdk-aac-dev libtheora-dev libwebp-dev \\\n              unixodbc-dev libpq-dev libxxhash-dev libaom-dev libbs2b-dev libcaca-dev libcdio-paranoia-dev\n      # 打开 Linux Desktop 支持\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-linux-desktop\n      # 更新 Flutter 的 packages\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n      # 设置 Fastforge 环境\n      - name: Install fast-forge\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n      # build Linux DEB\\ZIP\n      - name: Build Linux\n        run: |\n          cd simple_live_app\n          fastforge package --platform linux --targets deb,zip --skip-clean\n          cd build/dist/*\n          mv simple_live_app-*-linux.deb Slive-${{ matrix.arch }}-linux.deb\n          mv simple_live_app-*-linux.zip Slive-${{ matrix.arch }}-linux.zip\n      # 上传 Linux 包至 Artifacts\n      - name: Upload Linux APP to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: linux-${{ matrix.arch }}\n          path: |\n            simple_live_app/build/dist/*/*.deb\n            simple_live_app/build/dist/*/*.zip\n\n      # 读取版本信息\n      - name: Read version\n        id: version\n        uses: juliangruber/read-file-action@v1\n        with:\n          path: assets/app_version.json\n      - name: Echo version\n        run: echo \"${{ fromJson(steps.version.outputs.content).version }}\"\n      - name: Echo version content\n        run: echo \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n\n      # 上传至Release\n      - name: Upload Release\n        uses: softprops/action-gh-release@v1\n        with:\n          name: \"${{ fromJson(steps.version.outputs.content).version }}\"\n          body: \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n          prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }}\n          token: ${{ secrets.TOKEN }}\n          files: |\n            simple_live_app/build/dist/*/*.deb\n            simple_live_app/build/dist/*/*.zip\n      # 完成\n      - run: echo \"🍏 Linux job's status is ${{ job.status }}.\"\n\n  # 打包Windows\n  build-windows:\n    runs-on: windows-latest\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n      # 设置 Flutter 环境\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_app/pubspec.yaml\n          cache: true\n          channel: \"stable\"\n      - name: Enable Flutter Desktop\n        run: flutter config --enable-windows-desktop\n      - name: Restore Packages\n        run: |\n          cd simple_live_app\n          flutter pub get\n      # 设置 Fastforge 环境 和 Inno Setup\n      - name: Install Fastforge and Inno Setup\n        run: |\n          git clone https://github.com/SlotSun/fastforge.git\n          cd fastforge\n          dart pub global activate melos\n          melos run activate\n          choco install innosetup\n      # 添加中文安装引导\n      - name: Add Chinese language file for Inno Setup\n        run: |\n          cd simple_live_app\n          Copy-Item \"windows/packaging/exe/ChineseSimplified.isl\" \"C:\\Program Files (x86)\\Inno Setup 6\\Languages\\ChineseSimplified.isl\"\n        shell: powershell\n      # build Windows ZIP\\MSIX\\EXE\n      - name: Build Windows\n        run: |\n          cd simple_live_app\n          fastforge package --platform windows --targets msix,zip,exe --skip-clean\n          cd build/dist/*\n          Get-ChildItem \"simple_live_app-*\" | ForEach-Object {\n              $newName = $_.Name -replace '^simple_live_app', 'Slive'\n              Rename-Item $_ -NewName $newName\n          }\n        shell: pwsh\n      # 上传 Windows 至 Artifacts\n      - name: Upload Windows APP to Artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: windows\n          path: |\n            simple_live_app/build/dist/*/*.msix\n            simple_live_app/build/dist/*/*.zip\n            simple_live_app/build/dist/*/*.exe\n\n      # 读取版本信息\n      - name: Read version\n        id: version\n        uses: juliangruber/read-file-action@v1\n        with:\n          path: assets/app_version.json\n      - name: Echo version\n        run: echo \"${{ fromJson(steps.version.outputs.content).version }}\"\n      - name: Echo version content\n        run: echo \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n\n      # 上传至 Release\n      - name: Upload Release\n        uses: softprops/action-gh-release@v1\n        with:\n          name: \"${{ fromJson(steps.version.outputs.content).version }}\"\n          body: \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n          prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }}\n          token: ${{ secrets.TOKEN }}\n          files: |\n            simple_live_app/build/dist/*/*.msix\n            simple_live_app/build/dist/*/*.zip\n            simple_live_app/build/dist/*/*.exe\n\n      # 完成\n      - run: echo \"🍏 Windows job's status is ${{ job.status }}.\"\n\n  # 打包 Flatpak\n  build-flatpak:\n    strategy:\n      matrix:\n        include:\n          - runner: ubuntu-24.04\n            arch: x86_64\n          - runner: ubuntu-24.04-arm\n            arch: aarch64\n    runs-on: ${{ matrix.runner }}\n    permissions:\n      contents: write\n    steps:\n      # 签出代码\n      - uses: actions/checkout@v4\n      # 安装依赖\n      - name: Install dependencies\n        run: |\n          sudo add-apt-repository -y ppa:flatpak/stable\n          sudo apt-get update -q\n          sudo apt-get install -y flatpak flatpak-builder ca-certificates gnupg software-properties-common\n          flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo\n          git config --global protocol.file.allow always\n      # 构建 Flatpak bundle\n      - name: Build flatpak bundle\n        run: |\n          flatpak-builder build-dir flatpak/flatpak-manifest.yaml \\\n            --arch=${{ matrix.arch }} \\\n            --repo=${{ matrix.arch }} \\\n            --force-clean \\\n            --user \\\n            --install-deps-from=flathub \\\n            --ccache \\\n            --disable-rofiles-fuse\n          flatpak build-bundle ${{ matrix.arch }} Slive-${{ matrix.arch }}.flatpak io.github.SlotSun.Slive\n\n      # 上传 Flatpak 包至 Artifacts\n      - name: Upload linux flatpak to artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: linux-flatpak-${{ matrix.arch }}\n          path: Slive-*.flatpak\n\n      # 读取版本信息\n      - name: Read version\n        id: version\n        uses: juliangruber/read-file-action@v1\n        with:\n          path: assets/app_version.json\n      - name: Echo version\n        run: echo \"${{ fromJson(steps.version.outputs.content).version }}\"\n      - name: Echo version content\n        run: echo \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n\n      # 上传至 Release\n      - name: Upload Release\n        uses: softprops/action-gh-release@v1\n        with:\n          name: \"${{ fromJson(steps.version.outputs.content).version }}\"\n          body: \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n          prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }}\n          token: ${{ secrets.TOKEN }}\n          files: Slive-*.flatpak\n      # 完成\n      - run: echo \"🍏 Flatpak job's status is ${{ job.status }}.\"\n"
  },
  {
    "path": ".github/workflows/publish_tv_app_release.yaml",
    "content": "name: app-tv-build-action-release\n# 手动触发\non:\n  workflow_dispatch:\njobs:\n  build-tv:\n    runs-on: macos-latest\n    permissions:\n      contents: write\n    steps:\n      # 签出代码 \n      - uses: actions/checkout@v4\n        with:\n          ref: master\n        \n      # APK 签名设置\n      - name: Download Android keystore\n        id: android_tv_keystore\n        uses: timheuer/base64-to-file@v1.2\n        with:\n          fileName: keystore.jks\n          encodedString: ${{ secrets.TV_KEYSTORE_BASE64 }}\n      - name: Create key.properties\n        run: |\n          echo \"storeFile=${{ steps.android_tv_keystore.outputs.filePath }}\" > simple_live_tv_app/android/key.properties\n          echo \"storePassword=${{ secrets.TV_STORE_PASSWORD }}\" >> simple_live_tv_app/android/key.properties\n          echo \"keyPassword=${{ secrets.TV_KEY_PASSWORD }}\" >> simple_live_tv_app/android/key.properties\n          echo \"keyAlias=${{ secrets.TV_KEY_ALIAS }}\" >> simple_live_tv_app/android/key.properties\n\n      # 设置 JAVA 环境\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: \"17\"\n          cache: \"gradle\"\n    \n      # 设置 Flutter\n      - name: Flutter action\n        uses: subosito/flutter-action@v2\n        with:\n          flutter-version-file: simple_live_tv_app/pubspec.yaml\n          cache: true\n\n      # 更新 Flutter 的 packages\n      - name: Restore packages\n        run: |\n          cd simple_live_tv_app\n          flutter pub get\n        \n      # 打包 APK\n      - name: Build APK\n        run: |\n          cd simple_live_tv_app\n          flutter build apk --release --split-per-abi\n    \n      # 上传 APK 至 Artifacts\n      - name: Upload APK to Artifacts\n        uses: actions/upload-artifact@v3\n        with:\n          name: android_tv\n          path: |\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-x86_64-release.apk\n    \n      # 读取版本信息\n      - name: Read version\n        id: version\n        uses: juliangruber/read-file-action@v1\n        with:\n          path: assets/tv_app_version.json\n      - name: Echo version\n        run: echo \"${{ fromJson(steps.version.outputs.content).version }}\"\n      - name: Echo version content\n        run: echo \"${{ fromJson(steps.version.outputs.content).version_desc }}\"\n    \n      # 上传至 Release\n      - name: Upload Release\n        uses: softprops/action-gh-release@v1\n        with:\n          name: \"${{ fromJson(steps.version.outputs.content).version }}\"\n          body: \"# Android TV \\n${{ fromJson(steps.version.outputs.content).version_desc }}\"\n          prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }}\n          token: ${{ secrets.TOKEN }}\n          files: |\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-x86_64-release.apk\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk\n            simple_live_tv_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk\n        \n      # 完成\n      - run: echo \"🍏 This job's status is ${{ job.status }}.\"\n"
  },
  {
    "path": ".gitignore",
    "content": "simple_live_app/.vscode/settings.json\nsimple_live_tv_app/.vscode/settings.json\n.idea/\n.vscode/\n.vercel/\n.flatpak-builder/\n.crush/\nCRUSH.md\nbuild/\ndev-tool.ps1\n*.py\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# 开发贡献指南 / Contributing Guide\n\n感谢你对 Slive 的关注！欢迎各种形式的贡献，无论是修复 bug、添加新功能、改进文档还是提出建议。\n## 贡献须知\n- 因为一些原因，**dev** 作为Github Flow开发流程的主干\n- **master** 分支发版时 通过 merge squash dev，会在停更时删除dev分支并脱敏\n- 所以仓库的贡献者包括贡献代码统计都是不存在的\n\n## 🎯 贡献类型\n\n欢迎以下类型的贡献：\n\n### 🐛 修复 Bug\n- 在 Issues 中查找标记为 `bug` 的问题\n- 如果发现新的 bug，请先[创建 Issue](https://github.com/SlotSun/dart_simple_live/issues/new/choose) 描述问题\n\n### ✨ 添加新功能\n- 查找标记为 `enhancement`的 Issue\n- 对于较大的功能，建议先创建 Issue 讨论设计方案\n\n### 📖 改进文档\n- 修复文档中的错误或不清晰的地方\n- 添加使用示例和最佳实践\n\n### 🧪 添加测试\n- 为现有功能添加单元测试\n- 改进测试覆盖率\n- 添加集成测试\n\n### 🎨 UI/UX 改进\n- 优化界面交互体验\n- 修复界面样式问题\n- 提升易用性\n\n## 🚀 快速开始\n\n### 前置要求\n\n确保你的环境中已安装： \n\n- **Flutter 3.38.6^**\n- **Rust 1.28^**\n- **Visual Studio**\n\n### 安装 FVM\n\n```bash\n# macOS/Linux\ncurl -sL https://install.fvm.sh | bash\n\n# Windows\nchoco install fvm\n```\n\n### 安装 Flutter\n\n```bash\n# windows\nfvm version\nfvm list\nfvm install 3.38.6\n```\n\n**Linux**\n[详见官网教程](https://docs.flutter.dev/install/manual)\n\n### 克隆仓库\n\n```bash\ngit clone https://github.com/SlotSun/dart_simple_live.git\ncd dart_simple_live/simple_live_app\n```\n\n## 🏷️ 认领任务\n\n### 查找任务\n\n1. 浏览 [Issues 页面](https://github.com/SlotSun/dart_simple_live/issues)\n2. 查找带有以下标签的 Issue：\n    - `help wanted` - 需要社区帮助的任务\n    - `bug` - Bug 修复\n    - `enhancement` - 功能增强\n\n### 认领流程\n\n在你想要处理的 Issue 下评论：\n```\n/assign me\n```\n\n或者：\n```\n我可以解决此问题\n```\n\n\n## 💻 本地开发\n\n### 1. 安装依赖\n\n**Flutter依赖**：\n```bash\nfvm use 3.38.6\n# 安装Flutter_rust_bridge\ncargo install flutter_rust_bridge_codegen\nflutter pub get\n```\n\n### 2. 启动开发服务器\n\n**启动APP**（支持热重载）：\n```bash\nflutter run\n```\n\n### 3. 构建项目\n\n**安装 fastforge**\n```bash\ngit clone https://github.com/SlotSun/fastforge.git\ncd fastforge\ndart pub global activate melos\nmelos run activate\n```\n**Windows-安装 innosetup**\n```bash\n# 打包 windows\nchoco install innosetup\n```\n**构建APP**：\n```bash\n# bash in simple_live_app\ncd simple_live_app\n# 打包 windows\nfastforge package --platform windows --targets msix,zip,exe --skip-clean\n# Linux\nfastforge package --platform linux --targets deb,zip --skip-clean\n# Android-need key\nflutter build apk --release --split-per-abi\n```\n\n## 📁 代码结构\n\n### 项目目录速览\n- `simple_live_core` 项目核心库，实现获取各个网站的信息及弹幕。\n- `simple_live_console` 基于simple_live_core的控制台程序。\n- `simple_live_app` 基于核心库实现的Flutter APP客户端。\n- `simple_live_tv_app` 基于核心库实现的Flutter Android TV客户端。\n\n### 技术栈\n\n**Flutter**：\n- GetX(状态管理、路由)\n- Hive(持久化)\n- Dio(实时通信)\n\n## 📝 提交规范\n\n我们遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范：\n\n### Commit 格式\n\n```\n<类型>(<范围>): <简短描述>\n\n[可选的详细描述]\n\n[可选的脚注]\n```\n\n### 类型 (Type)\n\n- `feat`: 新功能\n- `fix`: Bug 修复\n- `docs`: 文档变更\n- `style`: 代码格式调整（不影响功能）\n- `refactor`: 重构（既不是新功能也不是 bug 修复）\n- `perf`: 性能优化\n- `test`: 添加或修改测试\n- `chore`: 辅助工具的变动\n- `ci`: 构建过程的变动\n\n### 范围 (Scope)\n\n可选，指明改动的模块：\n- `platfrom` - 直播平台\n- `Windows/Linux/Android` - 用户平台\n- `ui` - 用户界面\n- `ci` - 构建系统\n- `docs` - 文档\n\n### 示例\n\n```bash\nfeat(api): add layered agent support\n```\n\n## 🔍 Pull Request 要求\n### PR 流程\n```bash\ngit clone https://github.com/SlotSun/dart_simple_live.git\n# 基于dev分支创建 Type-Scope的分支\ngit checkout -b fix-xx origin/dev\n```\n**完成测试后，向主仓库的dev分支提交pr**\n### 提交前检查清单\n\n- [ ] 代码通过格式检查\n- [ ] 对于新功能，添加了相应的文档说明\n- [ ] 对于 UI 改动，提供了截图或录屏\n- [ ] Commit 信息遵循规范格式\n- [ ] PR 描述清晰说明了改动内容和原因\n\n### PR 标题格式\n\nPR 标题应该简洁明了，建议格式：\n\n```\n<类型>: <简短描述>\n```\n\n例如：\n- `feat: add WiFi device pairing support`\n- `fix: resolve video stream crash on device disconnect`\n- `docs: improve quick start guide`\n\n### PR 描述模板\n\n提交 PR 时，请使用以下模板：\n\n```markdown\n## 改动说明\n\n<!-- 简要描述这个 PR 做了什么 -->\n\n## 相关 Issue\n\n<!-- 关联的 Issue 编号，如 Closes #123 -->\n\n## 改动类型\n\n- [ ] Bug 修复\n- [ ] 新功能\n- [ ] 文档更新\n- [ ] 代码重构\n- [ ] 性能优化\n- [ ] 其他（请说明）\n\n## 测试说明\n\n<!-- 如何测试这些改动？ -->\n\n## 截图/录屏\n\n<!-- 对于 UI 改动，请提供截图或录屏 -->\n\n## 其他说明\n\n<!-- 其他需要说明的内容 -->\n```\n\n### Code Review\n\n提交 PR 后：\n1. 维护者会审查你的代码\n2. 可能会提出改进建议\n3. 请及时回复评论并根据反馈调整代码\n4. 所有讨论解决后，PR 会被合并\n\n## 🤝 行为准则\n\n### 我们的承诺\n\n为了营造一个开放和友好的环境，我们承诺：\n\n- 尊重不同的观点和经验\n- 优雅地接受建设性批评\n- 关注对社区最有利的事情\n- 对其他社区成员表示同理心\n\n### 不可接受的行为\n\n以下行为被视为不可接受：\n\n- 使用性别化的语言或图像，以及不受欢迎的性关注\n- 骚扰性评论、侮辱性/贬损性评论，以及人身或政治攻击\n- 公开或私下骚扰\n- 未经明确许可，发布他人的私人信息\n- 其他在专业环境中可能被认为不适当的行为\n\n## 🎉 感谢贡献\n\n感谢你花时间为 Slive 做出贡献！你的努力让这个项目变得更好。\n\n有任何问题？欢迎：\n- 在 [Issues](https://github.com/SlotSun/dart_simple_live/issues) 提问\n\n---"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "\n\n<p align=\"center\">\n    <img width=\"128\" src=\"/assets/logo.png\" alt=\"Simple Live logo\">\n</p>\n<h2 align=\"center\">Slive</h2>\n\n<p align=\"center\">\n我就默默看你表演\n</p>\n\n![浅色模式](/assets/screenshot_light.jpg)\n\n![深色模式](/assets/screenshot_dark.jpg)\n\n## 支持直播平台：\n\n- 虎牙直播\n\n- 斗鱼直播\n\n- 哔哩哔哩直播\n\n- 抖音直播\n\n## APP支持平台\n\n- [x] Android\n- [x] Windows\n- [x] Linux\n- [x] iOS `自测`\n- [x] MacOS `自测`\n- [ ] Android TV `请自行打包` [说明](https://github.com/SlotSun/dart_simple_live/issues/89)\n\n#### Arch Linux: \n```bash \n  yay -S slive\n  yay -S slive-bin\n```\n\n只保证Android, Linux和Windows可用性\n\n请到[Releases](https://github.com/slotsun/dart_simple_live/releases)下载最新版本，iOS请到上游或者action下载体验\n\n如果想体验最新功能，可前往[Actions](https://github.com/slotsun/dart_simple_live/actions)下载自动打包的开发版本\n\nWindows建议下载UWP版[聚合直播](https://www.microsoft.com/store/apps/9N1TWG2G84VD)，体验会更好\n\n\n## 项目结构\n\n- `simple_live_core` 项目核心库，实现获取各个网站的信息及弹幕。\n- `simple_live_console` 基于simple_live_core的控制台程序。\n- `simple_live_app` 基于核心库实现的Flutter APP客户端。\n- `simple_live_tv_app` 基于核心库实现的Flutter Android TV客户端。\n\n## 环境\n\nflutter 3.38.6\n\n## 参考及引用\n\n[AllLive](https://github.com/xiaoyaocz/AllLive) `本项目的C#版，有兴趣可以看看`\n\n[dart_tars_protocol](https://github.com/xiaoyaocz/dart_tars_protocol.git)\n\n[lovelyyoshino/Bilibili-Live-API](https://github.com/lovelyyoshino/Bilibili-Live-API/blob/master/API.WebSocket.md)\n\n[IsoaSFlus/danmaku](https://github.com/IsoaSFlus/danmaku)\n\n[BacooTang/huya-danmu](https://github.com/BacooTang/huya-danmu)\n\n[TarsCloud/Tars](https://github.com/TarsCloud/Tars)\n\n[5ime/Tiktok_Signature](https://github.com/5ime/Tiktok_Signature)\n\n[biliup](https://github.com/biliup/biliup)\n\n## 声明\n\n本项目的所有功能都是基于互联网上公开的资料开发，无任何破解、逆向工程等行为。\n\n本项目仅用于学习交流编程技术，严禁将本项目用于商业目的。如有任何商业行为，均与本项目无关。\n\n如果本项目存在侵犯您的合法权益的情况，请及时与开发者联系，开发者将会及时删除有关内容。\n"
  },
  {
    "path": "assets/app_version.json",
    "content": "{\n    \"version\": \"1.8.7\",\n    \"version_num\": 10807,\n    \"version_desc\": \"- 一个非常重要的过渡版本 \\n- 修复huya搜索 @GH4NG \\n- 引入Firebase \\n- 大量数据错误和潜在问题修复 \\n- 一些细节调整  \\n- 关于linux的一系列修复 @pugaizai \\n- tips: ios和macos用户请到action更新测试或者下载上游仓库版本\",\n    \"prerelease\": true,\n    \"download_url\": \"https://github.com/SlotSun/dart_simple_live/releases\"\n}\n"
  },
  {
    "path": "assets/tv_app_version.json",
    "content": "{\n    \"version\": \"1.5.0\",\n    \"version_num\": 10500,\n    \"version_desc\": \"- 永远的1.5.0\",\n    \"prerelease\":true,\n    \"download_url\": \"https://github.com/xiaoyaocz/dart_simple_live/releases\"\n}"
  },
  {
    "path": "assets/update-linux-metainfo.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\n\nString _xmlEscape(String s) => s\n    .replaceAll('&', '&amp;')\n    .replaceAll('<', '&lt;')\n    .replaceAll('>', '&gt;')\n    .replaceAll('\"', '&quot;')\n    .replaceAll(\"'\", '&apos;');\n\nvoid main() {\n  final projectRoot = Directory.current.path;\n  final jsonPath = '$projectRoot/assets/app_version.json';\n  final targetPath =\n      '$projectRoot/simple_live_app/assets/io.github.SlotSun.Slive.metainfo.xml';\n\n  final jsonFile = File(jsonPath);\n  if (!jsonFile.existsSync()) {\n    stderr.writeln('app_version.json not found: $jsonPath');\n    exit(2);\n  }\n\n  final targetFile = File(targetPath);\n  if (!targetFile.existsSync()) {\n    stderr.writeln('target file not found: $targetPath');\n    exit(2);\n  }\n\n  final map = json.decode(jsonFile.readAsStringSync());\n  final version = (map['version'] ?? '').toString();\n  final desc = (map['version_desc'] ?? '').toString();\n\n  final date = DateTime.now().toIso8601String().split('T').first;\n\n  final releaseBlock = [\n    '    <release version=\"$version\" date=\"$date\">',\n    '      <description>',\n    for (final line in desc.split('\\n'))\n      '        <p>${_xmlEscape(line.replaceAll(\"\\r\", \"\"))}</p>',\n    '      </description>',\n    '    </release>',\n  ].join('\\n');\n\n  final content = targetFile.readAsStringSync();\n\n  final releasesReg = RegExp(\n    r'(<releases\\b[^>]*>)([\\s\\S]*?)(  </releases>)',\n    multiLine: true,\n    dotAll: true,\n  );\n\n  // 直接替换第一个 <releases> 区块（如果不存在则 content 保持不变）\n  final newContent = content.replaceFirstMapped(\n    releasesReg,\n    (m) => '${m.group(1)}\\n$releaseBlock\\n${m.group(3)}',\n  );\n\n  targetFile.writeAsStringSync(newContent);\n  stdout.writeln('Update Done: $targetPath');\n}\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "/node_modules\n.idea\n.vitepress/cache"
  },
  {
    "path": "docs/.vitepress/config.mts",
    "content": "import { defineConfig } from 'vitepress'\n\n// https://vitepress.dev/reference/site-config\nexport default defineConfig({\n  base: '/dart_simple_live/',\n  title: \"Slive Doc\",\n  head: [\n    [\"link\", { rel: \"icon\", href: \"/favicon.ico\" }],\n  ],\n  description: \"Slive Doc\",\n  themeConfig: {\n    // https://vitepress.dev/reference/default-theme-config\n    nav: [\n      { text: 'Home', link: '/' },\n      { text: '开发指南', link: '/contributing' }\n    ],\n\n    sidebar: [\n      {\n        text: '文档',\n        items: [\n          { text: '开发指南', link: '/contributing' },\n          { text: '用户指南', link: '/user' }\n        ]\n      }\n    ],\n\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/SlotSun/dart_simple_live' }\n    ]\n  }\n})\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Slive Docs\n\n基于 VitePress\n\n## 部署\n\n安装依赖\n\n```shell\npnpm install\n```\n\n运行\n\n```shell\npnpm run docs:dev\n```\n"
  },
  {
    "path": "docs/contributing.md",
    "content": "# 开发贡献指南 / Contributing Guide\n\n感谢你对 Slive 的关注！欢迎各种形式的贡献，无论是修复 bug、添加新功能、改进文档还是提出建议。\n## 贡献须知\n- 因为一些原因，**dev** 作为Github Flow开发流程的主干\n- **master** 分支发版时 通过 merge squash dev，会在停更时删除dev分支并脱敏\n- 所以仓库的贡献者包括贡献代码统计都是不存在的\n\n## 🎯 贡献类型\n\n欢迎以下类型的贡献：\n\n### 🐛 修复 Bug\n- 在 Issues 中查找标记为 `bug` 的问题\n- 如果发现新的 bug，请先[创建 Issue](https://github.com/SlotSun/dart_simple_live/issues/new/choose) 描述问题\n\n### ✨ 添加新功能\n- 查找标记为 `enhancement`的 Issue\n- 对于较大的功能，建议先创建 Issue 讨论设计方案\n\n### 📖 改进文档\n- 修复文档中的错误或不清晰的地方\n- 添加使用示例和最佳实践\n\n### 🧪 添加测试\n- 为现有功能添加单元测试\n- 改进测试覆盖率\n- 添加集成测试\n\n### 🎨 UI/UX 改进\n- 优化界面交互体验\n- 修复界面样式问题\n- 提升易用性\n\n## 🚀 快速开始\n\n### 前置要求\n\n确保你的环境中已安装： \n\n- **Flutter 3.38.6^**\n- **Rust 1.28^**\n- **Visual Studio**\n\n### 安装 FVM\n\n```bash\n# macOS/Linux\ncurl -sL https://install.fvm.sh | bash\n\n# Windows\nchoco install fvm\n```\n\n### 安装 Flutter\n\n```bash\n# windows\nfvm version\nfvm list\nfvm install 3.38.6\n```\n\n**Linux**\n[详见官网教程](https://docs.flutter.dev/install/manual)\n\n### 克隆仓库\n\n```bash\ngit clone https://github.com/SlotSun/dart_simple_live.git\ncd dart_simple_live/simple_live_app\n```\n\n## 🏷️ 认领任务\n\n### 查找任务\n\n1. 浏览 [Issues 页面](https://github.com/SlotSun/dart_simple_live/issues)\n2. 查找带有以下标签的 Issue：\n    - `help wanted` - 需要社区帮助的任务\n    - `bug` - Bug 修复\n    - `enhancement` - 功能增强\n\n### 认领流程\n\n在你想要处理的 Issue 下评论：\n```\n/assign me\n```\n\n或者：\n```\n我可以解决此问题\n```\n\n\n## 💻 本地开发\n\n### 1. 安装依赖\n\n**Flutter依赖**：\n```bash\nfvm use 3.38.6\n# 安装Flutter_rust_bridge\ncargo install flutter_rust_bridge_codegen\nflutter pub get\n```\n\n### 2. 启动开发服务器\n\n**启动APP**（支持热重载）：\n```bash\nflutter run\n```\n\n### 3. 构建项目\n\n**安装 fastforge**\n```bash\ngit clone https://github.com/SlotSun/fastforge.git\ncd fastforge\ndart pub global activate melos\nmelos run activate\n```\n**Windows-安装 innosetup**\n```bash\n# 打包 windows\nchoco install innosetup\n```\n**构建APP**：\n```bash\n# bash in simple_live_app\ncd simple_live_app\n# 打包 windows\nfastforge package --platform windows --targets msix,zip,exe --skip-clean\n# Linux\nfastforge package --platform linux --targets deb,zip --skip-clean\n# Android-need key\nflutter build apk --release --split-per-abi\n```\n\n## 📁 代码结构\n\n### 项目目录速览\n- `simple_live_core` 项目核心库，实现获取各个网站的信息及弹幕。\n- `simple_live_console` 基于simple_live_core的控制台程序。\n- `simple_live_app` 基于核心库实现的Flutter APP客户端。\n- `simple_live_tv_app` 基于核心库实现的Flutter Android TV客户端。\n\n### 技术栈\n\n**Flutter**：\n- GetX(状态管理、路由)\n- Hive(持久化)\n- Dio(实时通信)\n\n## 📝 提交规范\n\n我们遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范：\n\n### Commit 格式\n\n```\n<类型>(<范围>): <简短描述>\n\n[可选的详细描述]\n\n[可选的脚注]\n```\n\n### 类型 (Type)\n\n- `feat`: 新功能\n- `fix`: Bug 修复\n- `docs`: 文档变更\n- `style`: 代码格式调整（不影响功能）\n- `refactor`: 重构（既不是新功能也不是 bug 修复）\n- `perf`: 性能优化\n- `test`: 添加或修改测试\n- `chore`: 辅助工具的变动\n- `ci`: 构建过程的变动\n\n### 范围 (Scope)\n\n可选，指明改动的模块：\n- `platfrom` - 直播平台\n- `Windows/Linux/Android` - 用户平台\n- `ui` - 用户界面\n- `ci` - 构建系统\n- `docs` - 文档\n\n### 示例\n\n```bash\nfeat(api): add layered agent support\n```\n\n## 🔍 Pull Request 要求\n### PR 流程\n```bash\ngit clone https://github.com/SlotSun/dart_simple_live.git\n# 基于dev分支创建 Type-Scope的分支\ngit checkout -b fix-xx origin/dev\n```\n**完成测试后，向主仓库的dev分支提交pr**\n### 提交前检查清单\n\n- [ ] 代码通过格式检查\n- [ ] 对于新功能，添加了相应的文档说明\n- [ ] 对于 UI 改动，提供了截图或录屏\n- [ ] Commit 信息遵循规范格式\n- [ ] PR 描述清晰说明了改动内容和原因\n\n### PR 标题格式\n\nPR 标题应该简洁明了，建议格式：\n\n```\n<类型>: <简短描述>\n```\n\n例如：\n- `feat: add WiFi device pairing support`\n- `fix: resolve video stream crash on device disconnect`\n- `docs: improve quick start guide`\n\n### PR 描述模板\n\n提交 PR 时，请使用以下模板：\n\n```markdown\n## 改动说明\n\n<!-- 简要描述这个 PR 做了什么 -->\n\n## 相关 Issue\n\n<!-- 关联的 Issue 编号，如 Closes #123 -->\n\n## 改动类型\n\n- [ ] Bug 修复\n- [ ] 新功能\n- [ ] 文档更新\n- [ ] 代码重构\n- [ ] 性能优化\n- [ ] 其他（请说明）\n\n## 测试说明\n\n<!-- 如何测试这些改动？ -->\n\n## 截图/录屏\n\n<!-- 对于 UI 改动，请提供截图或录屏 -->\n\n## 其他说明\n\n<!-- 其他需要说明的内容 -->\n```\n\n### Code Review\n\n提交 PR 后：\n1. 维护者会审查你的代码\n2. 可能会提出改进建议\n3. 请及时回复评论并根据反馈调整代码\n4. 所有讨论解决后，PR 会被合并\n\n## 🤝 行为准则\n\n### 我们的承诺\n\n为了营造一个开放和友好的环境，我们承诺：\n\n- 尊重不同的观点和经验\n- 优雅地接受建设性批评\n- 关注对社区最有利的事情\n- 对其他社区成员表示同理心\n\n### 不可接受的行为\n\n以下行为被视为不可接受：\n\n- 使用性别化的语言或图像，以及不受欢迎的性关注\n- 骚扰性评论、侮辱性/贬损性评论，以及人身或政治攻击\n- 公开或私下骚扰\n- 未经明确许可，发布他人的私人信息\n- 其他在专业环境中可能被认为不适当的行为\n\n## 🎉 感谢贡献\n\n感谢你花时间为 Slive 做出贡献！你的努力让这个项目变得更好。\n\n有任何问题？欢迎：\n- 在 [Issues](https://github.com/SlotSun/dart_simple_live/issues) 提问\n\n---"
  },
  {
    "path": "docs/index.md",
    "content": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\n\nhero:\n  name: \"Slive Docs\"\n  text: \"我就默默看你表演\"\n  tagline: 基于Flutter开发的直播聚合软件\n  actions:\n    - theme: brand\n      text: 开发指南\n      link: /contributing\n    - theme: alt\n      text: 用户指南\n      link: /user\n\nfeatures:\n  - title: 目标\n    details: 只需要一个软件就可以观看多个直播平台\n  - title: 直播平台支持\n    details: BiliBili/Douyu/Huya/Douyin\n  - title: 平台支持\n    details: Android/Windows/Linux\n---\n\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"Slive Docs\",\n  \"version\": \"1.0.0\",\n  \"devDependencies\": {\n    \"vitepress\": \"2.0.0-alpha.15\"\n  },\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev\",\n    \"docs:build\": \"vitepress build\",\n    \"docs:preview\": \"vitepress preview\"\n  },\n  \"dependencies\": {\n    \"Slive Docs\": \"link:\"\n  }\n}"
  },
  {
    "path": "docs/user.md",
    "content": "# 用户指南 / User Guide\n\n# 必知必看\n## 提交问题前必知必看\n- 随着用户数增多，问题反馈数增多，作者时间有限不能逐个回复还请见谅\n- 与之伴生的是，很多人不能正确反馈问题导致作者不能明确复现并定位问题，浪费了作者有限的休息时间\n- 一定要有一个共识，开源社区开源软件作者是在无偿贡献自己的业余时间和精力，出于技术学习和交流目的，是在作者自认为是正常人的认知范围内进行技术开发\n- 更要明白，你的私人需求不一定能够得到满足，问题的解决是有优先级的\n- 一定要先搜索仓库内是否已经有类似问题\n- 一定要详细正确填写设备型号，系统信息\n- 多次可复现后录大小低于10mb的视频\n- 详细说明复现过程\n- 例如观看直播问题，具体在什么手机什么系统什么直播平台什么房间使用什么流，出现了什么问题，使用硬解，硬解参数是怎么设置的，开启log后发送，无log不解决\n- 例如非直播问题，具体在什么系统什么界面使用什么功能，如何操作导致此问题，有无排查硬件兼容，软件互斥，鼠标失灵，键盘卡键等自身问题\n- 提出问题前使用AI或搜索引擎尝试解决并归纳问题\n- 其余我还没想到但可能提高解决问题效率的注意事项\n## 风控问题\n- 不要快速手动刷新，一定要把更新线程切换到4\n- 尽量减少搜索使用频率，最好使用链接解析，很多平台的不准确搜索涉及到推荐系统模型；普通接口CDN很快，搜索走内部系统一次的成本大概是普通接口的几十倍，风控会比较明显\n- 发现进入直播间报错，尝试切换账号切换网络重试\n\n### 安全问题\n- 一定要在仓库或可信源下载软件\n- 被作者签名的app hash对的上 签名对的上就表示没有被篡改，否则被篡改藏木马病毒你安装后可能有损失\n- 开源软件不代表绝对的安全\n- 一些二次封装收费的，那都不是我干的和我没关系；我再次声明，我自身有良好的本职工作收入，我对大家没有任何经济上的要求，甚至帮忙扫支付宝红包的需求都没有；我只是学习并提升下自己的开发技术，大家帮忙测试下就好，不用感谢也不用宣传\n\n## 用户账户配置\n### WebDav\n### BiliBili\n### Douyin\n\n## 播放器设置\n### 播放器参数\n### 弹幕参数设置\n\n## 关注功能\n### 标签功能\n### 主播信息\n### 关注清理\n\n## 链接解析\n\n## 外观设置\n### 字体设置\n\n## 其他说明"
  },
  {
    "path": "flatpak/flatpak-manifest.yaml",
    "content": "app-id: io.github.SlotSun.Slive\nruntime: org.freedesktop.Platform\nruntime-version: '25.08'\nsdk: org.freedesktop.Sdk\nsdk-extensions:\n  - org.freedesktop.Sdk.Extension.llvm21\ncommand: io.github.SlotSun.Slive\nfinish-args:\n  - --share=ipc\n  - --socket=fallback-x11\n  - --socket=wayland\n  - --socket=pulseaudio\n  - --share=network\n  - --device=dri\n  - --talk-name=org.freedesktop.ScreenSaver\n  # user settings synchronization feature requires this D-Bus\n  - --system-talk-name=org.freedesktop.NetworkManager.IP4Config\ncleanup:\n  - '*.a'\n  - '*.la'\n  - /include\n  - /lib/cmake\n  - /lib/pkgconfig\n  - /man\n  - /share/man\n  - /share/doc\n  - /share/gtk-docmodules\n\nmodules:\n  - name: rustup\n    buildsystem: simple\n    build-options:\n      build-args:\n        - --share=network\n      env:\n        CARGO_HOME: /var/lib/rustup\n        RUSTUP_HOME: /var/lib/rustup\n    build-commands:\n      - chmod -v +x rustup-init && ./rustup-init -y --profile minimal --no-modify-path\n    sources:\n      - type: file\n        only-arches: [x86_64]\n        url: https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init\n        sha256: 20a06e644b0d9bd2fbdbfd52d42540bdde820ea7df86e92e533c073da0cdd43c\n      - type: file\n        only-arches: [aarch64]\n        url: https://static.rust-lang.org/rustup/dist/aarch64-unknown-linux-gnu/rustup-init\n        sha256: e3853c5a252fca15252d07cb23a1bdd9377a8c6f3efa01531109281ae47f841c\n\n  - name: Slive\n    buildsystem: simple\n    build-options:\n      build-args:\n        - --share=network\n      arch:\n        x86_64:\n          env:\n            BUNDLE_PATH: simple_live_app/build/linux/x64/release/bundle\n        aarch64:\n          env:\n            BUNDLE_PATH: simple_live_app/build/linux/arm64/release/bundle\n      append-path: /var/lib/rustup/bin:/usr/lib/sdk/llvm21/bin:/run/build/Slive/flutter/bin\n      prepend-ld-library-path: /usr/lib/sdk/llvm21/lib\n      env:\n        RUSTUP_HOME: /var/lib/rustup\n        CARGO_HOME: /var/lib/rustup\n        PUB_CACHE: /run/build/Slive/.pub-cache\n    build-commands:\n      - cd simple_live_app && flutter build linux --release\n      - install -dvm755 ${FLATPAK_DEST}/bin\n      - cp -av ${BUNDLE_PATH}/* ${FLATPAK_DEST}/bin\n      - install -Dvm644 simple_live_app/assets/${FLATPAK_ID}.metainfo.xml -t ${FLATPAK_DEST}/share/metainfo\n      - install -Dvm644 simple_live_app/assets/images/logo.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/${FLATPAK_ID}.png\n      - install -Dvm644 simple_live_app/assets/${FLATPAK_ID}.desktop -t ${FLATPAK_DEST}/share/applications\n    sources:\n      - type: dir\n        path: \"../\"\n      - type: git\n        url: https://github.com/flutter/flutter.git\n        tag: 3.38.6\n        commit: 8b872868494e429d94fa06dca855c306438b22c0\n        dest: flutter\n"
  },
  {
    "path": "flatpak/libplacebo-python-3.14.patch",
    "content": "From 12509c0f1ee8c22ae163017f0a5e7b8a9d983a17 Mon Sep 17 00:00:00 2001\nFrom: Nicolas Chauvet <kwizart@gmail.com>\nDate: Tue, 29 Jul 2025 11:42:35 +0200\nSubject: [PATCH] vulkan/utils_gen: fix for python 3.14\n\nPython 3.14+ has added more type checking. This patch fixes usage\n\nFixes: https://github.com/haasn/libplacebo/issues/335\n\nSigned-off-by: Nicolas Chauvet <kwizart@gmail.com>\n---\n src/vulkan/utils_gen.py | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/src/vulkan/utils_gen.py b/src/vulkan/utils_gen.py\nindex 9a97d35f3..9b803d82b 100644\n--- a/src/vulkan/utils_gen.py\n+++ b/src/vulkan/utils_gen.py\n@@ -202,7 +202,8 @@ def find_registry_xml(datadir):\n     if not xmlfile or xmlfile == '':\n         xmlfile = find_registry_xml(datadir)\n \n-    registry = VkXML(ET.parse(xmlfile))\n+    tree = ET.parse(xmlfile)\n+    registry = VkXML(tree.getroot())\n     with open(outfile, 'w') as f:\n         f.write(TEMPLATE.render(\n             vkresults = get_vkenum(registry, 'VkResult'),\n"
  },
  {
    "path": "simple_live_app/.fvmrc",
    "content": "{\n  \"flutter\": \"3.38.6\"\n}"
  },
  {
    "path": "simple_live_app/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.build/\n.buildlog/\n.history\n.svn/\n.swiftpm/\nmigrate_working_dir/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\n\n# Android Studio will place build artifacts here\n/android/app/debug\n/android/app/profile\n/android/app/release\n/android/app/.cxx\n\n/windows/out\n/windows/.vs\n\n/ios/Podfile.lock\n\n.fvm/\n\n# firebase\nfirebase.json"
  },
  {
    "path": "simple_live_app/.metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: \"adc901062556672b4138e18a4dc62a4be8f4b3c2\"\n  channel: \"stable\"\n\nproject_type: app\n\n# Tracks metadata for the flutter migrate command\nmigration:\n  platforms:\n    - platform: root\n      create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2\n      base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2\n    - platform: linux\n      create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2\n      base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2\n\n  # User provided section\n\n  # List of Local paths (relative to this file) that should be\n  # ignored by the migrate tool.\n  #\n  # Files that are not part of the templates will be ignored by default.\n  unmanaged_files:\n    - 'lib/main.dart'\n    - 'ios/Runner.xcodeproj/project.pbxproj'\n"
  },
  {
    "path": "simple_live_app/README.md",
    "content": "# simple_live_app\n\n基于核心库实现的Flutter APP客户端。\n"
  },
  {
    "path": "simple_live_app/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\nanalyzer:\n  errors:\n    unintended_html_in_doc_comment: ignore\ninclude: package:flutter_lints/flutter.yaml\n\nformatter:\n  trailing_commas: preserve\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n    constant_identifier_names: false\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_app/android/.gitignore",
    "content": "gradle-wrapper.jar\n/app/build/\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n.cxx/\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/to/reference-keystore\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "simple_live_app/android/app/build.gradle.kts",
    "content": "import org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport java.util.Properties\nimport java.io.FileInputStream\n\nplugins {\n    id(\"com.android.application\")\n    // START: FlutterFire Configuration\n    id(\"com.google.gms.google-services\")\n    id(\"com.google.firebase.crashlytics\")\n    // END: FlutterFire Configuration\n    id(\"kotlin-android\")\n    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.\n    id(\"dev.flutter.flutter-gradle-plugin\")\n}\n\nval keystoreProperties = Properties()\nval keystorePropertiesFile = rootProject.file(\"key.properties\")\nif (keystorePropertiesFile.exists()) {\n    keystoreProperties.load(FileInputStream(keystorePropertiesFile))\n}\n\nandroid {\n    namespace = \"com.slotsun.slive\"\n    compileSdk = flutter.compileSdkVersion\n    ndkVersion = \"28.0.13004108\"\n\n    compileOptions {\n        sourceCompatibility = JavaVersion.VERSION_17\n        targetCompatibility = JavaVersion.VERSION_17\n    }\n\n    kotlin {\n        compilerOptions {\n            jvmTarget.set(JvmTarget.JVM_17)\n        }\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId = \"com.slotsun.slive\"\n        // You can update the following values to match your application needs.\n        // For more information, see: https://flutter.dev/to/review-gradle-config.\n        minSdk = flutter.minSdkVersion\n        targetSdk = flutter.targetSdkVersion\n        versionCode = flutter.versionCode\n        versionName = flutter.versionName\n    }\n\n    signingConfigs {\n        create(\"release\") {\n            keyAlias = keystoreProperties[\"keyAlias\"] as String\n            keyPassword = keystoreProperties[\"keyPassword\"] as String\n            storeFile = keystoreProperties[\"storeFile\"]?.let { file(it) }\n            storePassword = keystoreProperties[\"storePassword\"] as String\n        }\n    }\n\n    buildTypes {\n        release {\n            // TODO: Add your own signing config for the release build.\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig = signingConfigs.getByName(\"release\")\n            isMinifyEnabled = true\n            isShrinkResources = true\n            proguardFiles(\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n        }\n    }\n}\n\nflutter {\n    source = \"../..\"\n}"
  },
  {
    "path": "simple_live_app/android/app/google-services.json",
    "content": "{\n  \"project_info\": {\n    \"project_number\": \"000000000000\",\n    \"project_id\": \"com-slotsun-slive\",\n    \"storage_bucket\": \"com-slotsun-slive.firebasestorage.app\"\n  },\n  \"client\": [\n    {\n      \"client_info\": {\n        \"mobilesdk_app_id\": \"1:000000000000:android:0000000000000000\",\n        \"android_client_info\": {\n          \"package_name\": \"com.slotsun.slive\"\n        }\n      },\n      \"oauth_client\": [],\n      \"api_key\": [\n        {\n          \"current_key\": \"0\"\n        }\n      ],\n      \"services\": {\n        \"appinvite_service\": {\n          \"other_platform_oauth_client\": []\n        }\n      }\n    }\n  ],\n  \"configuration_version\": \"1\"\n}"
  },
  {
    "path": "simple_live_app/android/app/proguard-rules.pro",
    "content": "-keep class org.videolan.libvlc.** { *; }"
  },
  {
    "path": "simple_live_app/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n   <uses-permission android:name=\"android.permission.INTERNET\" />\n   <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n   <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n   <uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\" />\n    <meta-data\n        android:name=\"io.flutter.embedding.android.EnableImpeller\"\n        android:value=\"false\"\n        />\n    <application\n        android:label=\"Slive\"\n        android:name=\"${applicationName}\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:networkSecurityConfig=\"@xml/network_security_config\"\n        android:extractNativeLibs=\"true\"\n        android:usesCleartextTraffic=\"true\">\n        <activity\n            android:name=\".MainActivity\"\n            android:supportsPictureInPicture=\"true\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTop\"\n            android:taskAffinity=\"\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:extractNativeLibs=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n    <!-- Required to query activities that can process text, see:\n         https://developer.android.com/training/package-visibility and\n         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.\n\n         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->\n    <queries>\n        <intent>\n            <action android:name=\"android.intent.action.PROCESS_TEXT\"/>\n            <data android:mimeType=\"text/plain\"/>\n        </intent>\n    </queries>\n</manifest>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/kotlin/com/slotsun/slive/MainActivity.kt",
    "content": "package com.slotsun.slive\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity : FlutterActivity()\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "﻿<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@color/ic_launcher_background\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\">\n  <group android:scaleX=\"0.73333335\"\n      android:scaleY=\"0.73333335\"\n      android:translateX=\"136.53334\"\n      android:translateY=\"136.53334\">\n    <path\n        android:pathData=\"M0,0h1024v1024h-1024z\">\n      <aapt:attr name=\"android:fillColor\">\n        <gradient\n            android:centerX=\"512\"\n            android:centerY=\"512\"\n            android:gradientRadius=\"512\"\n            android:type=\"radial\">\n          <item android:offset=\"0\" android:color=\"#FF3193CB\"/>\n          <item android:offset=\"0.3\" android:color=\"#FF2B84BD\"/>\n          <item android:offset=\"0.6\" android:color=\"#FF2675AF\"/>\n          <item android:offset=\"1\" android:color=\"#FF1E6BA0\"/>\n        </gradient>\n      </aapt:attr>\n    </path>\n    <path\n        android:pathData=\"M234,388Q234,280 342,388Q450,496 558,388Q666,280 882,388\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M234,568L234,748\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M342,568L342,676M342,604L342,604\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M450,568L504,676L558,568\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M666,568Q612,622 666,676Q720,622 774,568M648,672.4Q828,658 846,604\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M306,478L306,463.6\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M648,469L702,451\"\n        android:strokeWidth=\"36\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeLineCap=\"round\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/drawable/ic_launcher_monochrome.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\">\n    <group android:scaleX=\"0.67833334\"\n        android:scaleY=\"0.67833334\"\n        android:translateX=\"164.69333\"\n        android:translateY=\"164.69333\">\n        <path\n            android:pathData=\"M234,388Q234,280 342,388Q450,496 558,388Q666,280 882,388\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M234,568L234,748\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M342,568L342,676M342,604L342,604\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M450,568L504,676L558,568\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M666,568Q612,622 666,676Q720,622 774,568M648,672.4Q828,658 846,604\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M306,478L306,463.6\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n        <path\n            android:pathData=\"M648,469L702,451\"\n            android:strokeWidth=\"36\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeLineCap=\"round\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#206CA1</color>\n</resources>"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/ic_launcher_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n        <item name=\"android:windowLayoutInDisplayCutoutMode\">shortEdges</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n        <item name=\"android:windowLayoutInDisplayCutoutMode\">shortEdges</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "simple_live_app/android/app/src/main/res/xml/network_security_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<network-security-config>\n    <base-config cleartextTrafficPermitted=\"true\" />\n</network-security-config>\n"
  },
  {
    "path": "simple_live_app/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "simple_live_app/android/build.gradle.kts",
    "content": "allprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\nval newBuildDir: Directory =\n    rootProject.layout.buildDirectory\n        .dir(\"../../build\")\n        .get()\nrootProject.layout.buildDirectory.value(newBuildDir)\n\nsubprojects {\n    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)\n    project.layout.buildDirectory.value(newSubprojectBuildDir)\n}\nsubprojects {\n    project.evaluationDependsOn(\":app\")\n}\n\ntasks.register<Delete>(\"clean\") {\n    delete(rootProject.layout.buildDirectory)\n}\n"
  },
  {
    "path": "simple_live_app/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.14-all.zip\n"
  },
  {
    "path": "simple_live_app/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "simple_live_app/android/settings.gradle.kts",
    "content": "pluginManagement {\n    val flutterSdkPath =\n        run {\n            val properties = java.util.Properties()\n            file(\"local.properties\").inputStream().use { properties.load(it) }\n            val flutterSdkPath = properties.getProperty(\"flutter.sdk\")\n            require(flutterSdkPath != null) { \"flutter.sdk not set in local.properties\" }\n            flutterSdkPath\n        }\n\n    includeBuild(\"$flutterSdkPath/packages/flutter_tools/gradle\")\n\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\n\nplugins {\n    id(\"dev.flutter.flutter-plugin-loader\") version \"1.0.0\"\n    id(\"com.android.application\") version \"8.11.1\" apply false\n    // START: FlutterFire Configuration\n    id(\"com.google.gms.google-services\") version(\"4.3.15\") apply false\n    id(\"com.google.firebase.crashlytics\") version(\"2.8.1\") apply false\n    // END: FlutterFire Configuration\n    id(\"org.jetbrains.kotlin.android\") version \"2.2.20\" apply false\n}\n\ninclude(\":app\")\n"
  },
  {
    "path": "simple_live_app/assets/fonts/fonts-manifest.json",
    "content": "﻿[\n  {\n    \"id\": \"judousansui\",\n    \"name\": \"句读黑体 UI Hans\",\n    \"files\": [\n      \"judousansui/JudouSansUiHans-ExtraLight.ttf\",\n      \"judousansui/JudouSansUiHans-Light.ttf\",\n      \"judousansui/JudouSansUiHans-Regular.ttf\",\n      \"judousansui/JudouSansUiHans-Medium.ttf\",\n      \"judousansui/JudouSansUiHans-Bold.ttf\",\n      \"judousansui/JudouSansUiHans-Heavy.ttf\"\n    ],\n    \"desc\": \"句读黑体，基于思源黑体和 FiraGO 等字体，商用免费的多文种混排字体。\",\n    \"official\": \"https://github.com/JudouEco/JudouSans\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"judousansuihant\",\n    \"name\": \"句读黑体 UI Hant\",\n    \"files\": [\n      \"judousansuihant/JudouSansUiHant-ExtraLight.ttf\",\n      \"judousansuihant/JudouSansUiHant-Light.ttf\",\n      \"judousansuihant/JudouSansUiHant-Regular.ttf\",\n      \"judousansuihant/JudouSansUiHant-Medium.ttf\",\n      \"judousansuihant/JudouSansUiHant-Bold.ttf\",\n      \"judousansuihant/JudouSansUiHant-Heavy.ttf\"\n    ],\n    \"desc\": \"句读黑体 传承字形版本\",\n    \"official\": \"https://github.com/JudouEco/JudouSans\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n{\n    \"id\": \"frex-sans\",\n    \"name\": \"械黑\",\n    \"files\": [\n      \"frex-sans/FrexSansGB-Thin.ttf\",\n      \"frex-sans/FrexSansGB-ExtraLight.ttf\",\n      \"frex-sans/FrexSansGB-Light.ttf\",\n      \"frex-sans/FrexSansGB-Text.ttf\",\n      \"frex-sans/FrexSansGB-Medium.ttf\",\n      \"frex-sans/FrexSansGB-SemiBold.ttf\",\n      \"frex-sans/FrexSansGB-Bold.ttf\"\n    ],\n    \"desc\": \"将 IBM Plex Sans SC 中成部件的大量不必要修改还原成字体的原有风格，并修复了其中的一部分错形，部分零碎的字形也已恢复到繁体版和日文版原本的设计。\",\n    \"official\": \"https://www.maoken.com/freefonts/26125.html\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n{\n    \"id\": \"chilldin\",\n    \"name\": \"寒蝉德黑体\",\n    \"files\": [\n      \"chilldin/ChillDINGothic_Regular.otf\",\n      \"chilldin/ChillDINGothic_Medium.otf\",\n      \"chilldin/ChillDINGothic_Bold.otf\"\n    ],\n    \"desc\": \"源于德国工业标准字体“DIN”，基于D-DIN的修缮。\",\n    \"official\": \"github.com/Warren2060/ChillDIN-ChillDINGothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n{\n    \"id\": \"zhiyimaru\",\n    \"name\": \"致一圆体\",\n    \"files\": [\n      \"zhiyimaru/ZhiyiMaru-Regular.ttf\",\n      \"zhiyimaru/ZhiyiMaru-Bold.ttf\"\n    ],\n    \"desc\": \"基于旧印刷字形的「霞鹜晰黑」修改而来，并制作了圆体、粗圆，以适应现代阅读环境对多样式、多字重字型的需要。\",\n    \"official\": \"https://github.com/RiyipuSipino/ZhiyiSans\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"chiron-go-round\",\n    \"name\": \"昭源环方\",\n    \"files\": [\n      \"chiron-go-round/ChironGoRoundTC-300L.ttf\",\n      \"chiron-go-round/ChironGoRoundTC-400R.ttf\",\n      \"chiron-go-round/ChironGoRoundTC-500M.ttf\",\n      \"chiron-go-round/ChironGoRoundTC-700B.ttf\"\n    ],\n    \"desc\": \"现代笔形风格，平衡标准字形和印刷体惯用笔形的免费开源仿圆体字体。\",\n    \"official\": \"https://github.com/chiron-fonts/chiron-go-round-tc\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"copperzhengkai\",\n    \"name\": \"汇迹正楷\",\n    \"files\": [\n      \"copperzhengkai/CooperZhengKai.ttf\"\n    ],\n    \"desc\": \"Cooper 搭配汇文正楷，更楷体。\",\n    \"official\": \"https://www.maoken.com/freefonts/24749.html\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"fusion-pixel\",\n    \"name\": \"缝合像素字体\",\n    \"files\": [\n      \"fusion-pixel/fusion-pixel-12px-proportional-zh_hans.ttf\"\n    ],\n    \"desc\": \"该项目为「方舟像素字体」的临时性过渡方案。使用多个像素字体合并而成，因此以「缝合」命名。\",\n    \"official\": \"https://github.com/TakWolf/fusion-pixel-font\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"chillroundm\",\n    \"name\": \"寒蝉半圆体\",\n    \"files\": [\n      \"chillroundm/ChillRoundM.otf\"\n    ],\n    \"desc\": \"寒蝉半圆体，基于日本开源字体 Zen Maru Gothic 进行调整的圆体字体，更新为符合 GB2312 标准的字符集，使其应用范围更广；修正部分字形和补充部分字形，调整到更均衡的排版。\",\n    \"official\": \"https://github.com/Warren2060/ChillRound\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"huiwen-hkhei\",\n    \"name\": \"汇文港黑\",\n    \"files\": [\n      \"huiwen-hkhei/HuiwenHKHei-Regular.ttf\"\n    ],\n    \"desc\": \"特里王系列精品免费商用字体，字形主要参考自照排时期香港广泛使用的港版岩田黑体。\",\n    \"official\": \"https://zhuanlan.zhihu.com/p/12669052378\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://zhuanlan.zhihu.com/p/12669052378\"\n    }\n  },\n  {\n    \"id\": \"huiwen-mincho\",\n    \"name\": \"汇文明朝体 GBK\",\n    \"files\": [\n      \"huiwen-mincho/HuiwenMinchoGBK-Regular.ttf\"\n    ],\n    \"desc\": \"特里王系列精品免费商用字体，字形主要来自五六十年代官方各种汉字改革文件。\",\n    \"official\": \"https://zhuanlan.zhihu.com/p/12669052378\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://zhuanlan.zhihu.com/p/12669052378\"\n    }\n  },\n  {\n    \"id\": \"huiwen-zhengkai\",\n    \"name\": \"汇文正楷\",\n    \"files\": [\n      \"huiwen-zhengkai/HuiwenZhengKai-Regular.ttf\"\n    ],\n    \"desc\": \"特里王系列精品免费商用字体，字形来自大名鼎鼎的「汉文正楷」。\",\n    \"official\": \"https://zhuanlan.zhihu.com/p/12669052378\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://zhuanlan.zhihu.com/p/12669052378\"\n    }\n  },\n  {\n    \"id\": \"huiwen-fangsong\",\n    \"name\": \"汇文仿宋\",\n    \"files\": [\n      \"huiwen-fangsong/HuiwenFangSong-Regular.ttf\"\n    ],\n    \"desc\": \"特里王系列精品免费商用字体，字形来自新华字模厂的老 59-4 仿宋体。\",\n    \"official\": \"https://zhuanlan.zhihu.com/p/12669052378\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://zhuanlan.zhihu.com/p/12669052378\"\n    }\n  },\n  {\n    \"id\": \"blix\",\n    \"name\": \"卜力士\",\n    \"files\": [\n      \"blix/Blix-Thin.otf\",\n      \"blix/Blix-ExtraLight.otf\",\n      \"blix/Blix-Light.otf\",\n      \"blix/Blix-Text.otf\",\n      \"blix/Blix-Medium.otf\",\n      \"blix/Blix-SemiBold.otf\",\n      \"blix/Blix-Bold.otf\"\n    ],\n    \"desc\": \"基于 IBM Plex Sans 汉字系列的合并字体，尽可能减少规范字形的󠄁影响。\",\n    \"official\": \"https://drive.google.com/drive/folders/14naJSasVxrPstbWkHtK696LLGAb5H-vm?usp=sharing\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"plix\",\n    \"name\": \"普力士\",\n    \"files\": [\n      \"plix/Plix-Thin.otf\",\n      \"plix/Plix-ExtraLight.otf\",\n      \"plix/Plix-Light.otf\",\n      \"plix/Plix-Text.otf\",\n      \"plix/Plix-Medium.otf\",\n      \"plix/Plix-SemiBold.otf\",\n      \"plix/Plix-Bold.otf\"\n    ],\n    \"desc\": \"基于 IBM Plex Sans 汉字系列的合并字体，尽可能减少规范字形的󠄁影响。\",\n    \"official\": \"https://drive.google.com/drive/folders/14naJSasVxrPstbWkHtK696LLGAb5H-vm?usp=sharing\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"ibm-plex-sans-sc\",\n    \"name\": \"IBM Plex Sans SC\",\n    \"files\": [\n      \"ibm-plex-sans-sc/IBMPlexSansSC-Thin.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-ExtraLight.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-Light.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-Text.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-Medium.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-SemiBold.otf\",\n      \"ibm-plex-sans-sc/IBMPlexSansSC-Bold.otf\"\n    ],\n    \"desc\": \"IBM 的开源字体。全球性，多功能，且像 IBM 一样独特。\",\n    \"official\": \"https://github.com/IBM/plex/tree/feat-plex-sans-sc/packages/plex-sans-sc\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"yozai\",\n    \"name\": \"悠哉字体\",\n    \"files\": [\n      \"yozai/Yozai-Light.ttf\",\n      \"yozai/Yozai-Regular.ttf\",\n      \"yozai/Yozai-Medium.ttf\"\n    ],\n    \"desc\": \"一款基于 Y.OzFont 的手写风格的字体。\",\n    \"official\": \"https://github.com/lxgw/yozai-font\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"childfunsans\",\n    \"name\": \"游趣体\",\n    \"files\": [\n      \"childfunsans/ChildFunSans.ttf\"\n    ],\n    \"desc\": \"一款开源简体中文字体，基于 Fontworks 的 Stick 衍生。\",\n    \"official\": \"https://github.com/Des-Magmeta/ChildFunSans\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"tsuipita\",\n    \"name\": \"晓声通秋茄体\",\n    \"files\": [\n      \"tsuipita/ToneOZ-Tsuipita-TC.ttf\"\n    ],\n    \"desc\": \"基于随峰体扩展，开源免费可商用的的手写字型。\",\n    \"official\": \"https://toneoz.com/blog/tsuipita/\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"kaisei\",\n    \"name\": \"江城解星体\",\n    \"files\": [\n      \"kaisei/kaisei.ttf\"\n    ],\n    \"desc\": \"不同于传统的印刷，通过在右侧添加加圆型衬线，使字体左右更加平衡，同时也为字体添加了不一样的特色。\",\n    \"official\": \"https://toneoz.com/blog/tsuipita/\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"xuandongkaishu\",\n    \"name\": \"玄冬楷书\",\n    \"files\": [\n      \"xuandongkaishu/XuandongKaishu.ttf\"\n    ],\n    \"desc\": \"基于开源字体《马善政毛笔楷书》的拓展字体。在原版的基础之上修复了错误的字形并添加竖排排版的特性。\",\n    \"official\": \"https://github.com/Skr-ZERO/Xuandong-Kaishu\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"misans\",\n    \"name\": \"MiSans\",\n    \"files\": [\n      \"misans/MiSans-Bold.ttf\",\n      \"misans/MiSans-Heavy.ttf\",\n      \"misans/MiSans-Light.ttf\",\n      \"misans/MiSans-Medium.ttf\",\n      \"misans/MiSans-Regular.ttf\",\n      \"misans/MiSans-Thin.ttf\"\n    ],\n    \"desc\": \"MiSans Global 是由小米主导，联合蒙纳字库、汉仪字库共同打造的全球语言字体定制项目。这是一个庞大的字体家族，涵盖 20 多种书写系统，支持 600 多种语言，字符数量超过 10 万个。作为 Xiaomi HyperOS 系统默认字体，我们以简约/清晰，人文/易读，统一的视觉风格为基本原则出发，构建多语言信息体验一致性，旨在帮助为 Xiaomi HyperOS 提供互联的通用体验。\",\n    \"official\": \"https://hyperos.mi.com/font\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://hyperos.mi.com/font/faq\"\n    }\n  },\n  {\n    \"id\": \"alibabapuhuiti3\",\n    \"name\": \"阿里巴巴普惠体 3.0\",\n    \"files\": [\n      \"alibabapuhuiti3/AlibabaPuHuiTi-3-45-Light.ttf\",\n      \"alibabapuhuiti3/AlibabaPuHuiTi-3-55-Regular.ttf\",\n      \"alibabapuhuiti3/AlibabaPuHuiTi-3-75-SemiBold.ttf\",\n      \"alibabapuhuiti3/AlibabaPuHuiTi-3-95-ExtraBold.ttf\"\n    ],\n    \"desc\": \"阿里巴巴普惠体是一套全球永久免费正版商用的字体家族。阿里巴巴普惠体 3.0 为一套符合新国家标准 GB18030-2022 的简体中文字符集，包含 GB18030-2022 强制规范三个实现级别：实现级别 1 + 实现级别 2 标准规格的 7 字重、实现级别 3 标准规格的 Regular 单一字重。7 字重共 194460 个全形汉字。包含拉丁字母、希腊字母、西里尔字母、标点符号。\",\n    \"official\": \"https://www.alibabafonts.com/\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://www.yuque.com/yiguang-wkqc2/puhuiti/nus9wiinq4aeiegy\"\n    }\n  },\n  {\n    \"id\": \"lxgwneoxihei\",\n    \"name\": \"霞鹜新晰黑 屏幕阅读版\",\n    \"files\": [\n      \"lxgwneoxihei/LXGWNeoXiHeiScreen.ttf\"\n    ],\n    \"desc\": \"一款基于 IPAex 黑体的中文开源字体，是将日本写法的字体改造成中国大陆规范写法的尝试。\",\n    \"official\": \"https://github.com/lxgw/LxgwNeoXiZhi-Screen\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"lxgwneozhisong\",\n    \"name\": \"霞鹜新致宋 屏幕阅读版\",\n    \"files\": [\n      \"lxgwneozhisong/LXGWNeoZhiSongScreen.ttf\"\n    ],\n    \"desc\": \"基于「IPAex 明朝」「IPAmj 明朝」的中文开源字体，是将日本写法的字体改造成中国大陆规范写法的尝试。\",\n    \"official\": \"https://github.com/lxgw/LxgwNeoXiZhi-Screen\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"chillroundf\",\n    \"name\": \"寒蝉全圆体\",\n    \"files\": [\n      \"chillroundf/ChillRoundF.ttf\"\n    ],\n    \"desc\": \"寒蝉全圆体，基于《小杉圆体》《justfont 粉圆》《猫啃糖圆体》进行调整的圆体字型，更新为超大字符数量的字符集，使其应用范围更广。综合考量各版本字形的使用并挑选合理的字形。修正部分字形和补充部分字形。调整到更均衡的排版。\",\n    \"official\": \"https://github.com/Warren2060/ChillRound\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"hmsans\",\n    \"name\": \"HarmonyOS Sans\",\n    \"files\": [\n      \"hmsans/HarmonyOS_Sans_SC_Black.ttf\",\n      \"hmsans/HarmonyOS_Sans_SC_Bold.ttf\",\n      \"hmsans/HarmonyOS_Sans_SC_Light.ttf\",\n      \"hmsans/HarmonyOS_Sans_SC_Medium.ttf\",\n      \"hmsans/HarmonyOS_Sans_SC_Regular.ttf\",\n      \"hmsans/HarmonyOS_Sans_SC_Thin.ttf\"\n    ],\n    \"desc\": \"华为全新品牌定制字体，HarmonyOS Sans 字体版权归华为所有\",\n    \"official\": \"https://developer.huawei.com/consumer/cn/design/resource\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"hmsans/LICENSE.txt\"\n    }\n  },\n  {\n    \"id\": \"xwwk\",\n    \"name\": \"霞鹜文楷 Lite\",\n    \"files\": [\n      \"xwwk/LXGWWenKaiLite-Light.ttf\",\n      \"xwwk/LXGWWenKaiLite-Regular.ttf\",\n      \"xwwk/LXGWWenKaiLite-Medium.ttf\"\n    ],\n    \"desc\": \"An open-source Chinese font derived from Fontworks' Klee One. 一款基于 FONTWORKS 的 Klee One 的开源中文字体，保留「亠」「宀」等起笔的直点和「㇙」「㇜」等笔画折角处断笔设计等。\",\n    \"official\": \"https://github.com/lxgw/LxgwWenKai-Lite\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"xwwkgb\",\n    \"name\": \"霞鹜文楷 GB Lite\",\n    \"files\": [\n      \"xwwkgb/LXGWWenKaiGBLite-Light.ttf\",\n      \"xwwkgb/LXGWWenKaiGBLite-Regular.ttf\",\n      \"xwwkgb/LXGWWenKaiGBLite-Medium.ttf\"\n    ],\n    \"desc\": \"在霞鹜文楷的基础上，尽可能严格按照中国大陆的字形标准（G 源字形）对字形、笔形作进一步修改。\",\n    \"official\": \"https://github.com/lxgw/LxgwWenkaiGB-Lite\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"lhzt\",\n    \"name\": \"小赖字体\",\n    \"files\": [\n      \"lhzt/XiaolaiSC-Regular.ttf\"\n    ],\n    \"desc\": \"一款衍生于「濑户字体」的中文手写字型。\",\n    \"official\": \"https://github.com/lxgw/kose-font\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"knmaiyuan\",\n    \"name\": \"荆南麦圆体\",\n    \"files\": [\n      \"knmaiyuan/KNMaiyuan-Regular.ttf\"\n    ],\n    \"desc\": \"麦圆体萌系可爱的手写风格，字体每个笔画的粗细相同，两端圆润饱满，凸显可爱风格。虽是手写字体，笔画分明没有细小的连接，使字体更加清新俏皮。无论是做食品类还是母婴类，抑或是儿童类的设计都特别适合。\",\n    \"official\": \"https://github.com/maoken-fonts/KNMaiyuan\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"mizukigothic\",\n    \"name\": \"水木黑体\",\n    \"files\": [\n      \"mizukigothic/MizukiGothic-Regular.ttf\"\n    ],\n    \"desc\": \"一个还原未被楷化的大陆字形项目。\",\n    \"official\": \"https://github.com/enderseven1/Mizuki-Gothic\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"mizukiming\",\n    \"name\": \"水木明体\",\n    \"files\": [\n      \"mizukiming/MizukiMing-Regular.ttf\"\n    ],\n    \"desc\": \"致力于打造印刷体风格字形的项目。\",\n    \"official\": \"https://github.com/enderseven1/Mizuki-Ming/\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"yrdzst\",\n    \"name\": \"杨任东竹石体\",\n    \"files\": [\n      \"yrdzst/yrdzst-Bold.ttf\",\n      \"yrdzst/yrdzst-Extralight.ttf\",\n      \"yrdzst/yrdzst-Heavy.ttf\",\n      \"yrdzst/yrdzst-Light.ttf\",\n      \"yrdzst/yrdzst-Medium.ttf\",\n      \"yrdzst/yrdzst-Regular.ttf\",\n      \"yrdzst/yrdzst-Semibold.ttf\"\n    ],\n    \"desc\": \"杨任东竹石体于 2017 年 4 月 26 日世界知识产权日正式发布，本字体版本为 1.23。字体按照 GB2312-80 书写，并增补了少量常见汉字；整套字体有 7 个字重，共计 50000 余个字符。本套字体授权全社会免费商用，意味着您可以将其无限制地捆入您的商业产品中，如海报、包装、logo、网页、APP 等。\",\n    \"official\": \"ttps://mp.weixin.qq.com/s/7kv3i_YEs7x9_9IrCDYvBA\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/7kv3i_YEs7x9_9IrCDYvBA\"\n    }\n  },\n  {\n    \"id\": \"opposans\",\n    \"name\": \"OPlusSans\",\n    \"files\": [\n      \"opposans/OPlusSans3-ExtraLight.ttf\",\n      \"opposans/OPlusSans3-Light.ttf\",\n      \"opposans/OPlusSans3-Regular.ttf\",\n      \"opposans/OPlusSans3-Medium.ttf\",\n      \"opposans/OPlusSans3-Bold.ttf\"\n    ],\n    \"desc\": \"OPlusSans（原名 OPPOSans）允许个人或企业免费使用，含商业用途，版权归 OPPO 广东移动通信有限公司所有。\",\n    \"official\": \"https://www.coloros.com/index/newsDetail?id=72\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://www.coloros.com/index/newsDetail?id=72\"\n    }\n  },\n  {\n    \"id\": \"sarasa-gothic\",\n    \"name\": \"更纱黑体\",\n    \"files\": [\n      \"sarasa-gothic/SarasaGothicSC-Light.ttf\",\n      \"sarasa-gothic/SarasaGothicSC-Regular.ttf\",\n      \"sarasa-gothic/SarasaGothicSC-SemiBold.ttf\",\n      \"sarasa-gothic/SarasaGothicSC-Bold.ttf\"\n    ],\n    \"desc\": \"更纱黑体使用全宽引号和比例数字。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-ui\",\n    \"name\": \"更纱黑体 UI\",\n    \"files\": [\n      \"sarasa-ui/SarasaUiSC-Light.ttf\",\n      \"sarasa-ui/SarasaUiSC-Regular.ttf\",\n      \"sarasa-ui/SarasaUiSC-SemiBold.ttf\",\n      \"sarasa-ui/SarasaUiSC-Bold.ttf\"\n    ],\n    \"desc\": \"更纱黑体 UI 使用缩进引号和等宽数字。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-mono\",\n    \"name\": \"等距更纱黑体\",\n    \"files\": [\n      \"sarasa-mono/SarasaMonoSC-Light.ttf\",\n      \"sarasa-mono/SarasaMonoSC-Regular.ttf\",\n      \"sarasa-mono/SarasaMonoSC-SemiBold.ttf\",\n      \"sarasa-mono/SarasaMonoSC-Bold.ttf\"\n    ],\n    \"desc\": \"等距更纱黑体使用等宽西文《Iosevka》。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-slab\",\n    \"name\": \"等距更纱黑体 Slab\",\n    \"files\": [\n      \"sarasa-slab/SarasaMonoSlabSC-Light.ttf\",\n      \"sarasa-slab/SarasaMonoSlabSC-Regular.ttf\",\n      \"sarasa-slab/SarasaMonoSlabSC-SemiBold.ttf\",\n      \"sarasa-slab/SarasaMonoSlabSC-Bold.ttf\"\n    ],\n    \"desc\": \"等距更纱黑体 Slab 使用等宽西文《Iosevka Slab》。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-gothic-cl\",\n    \"name\": \"更纱黑体 CL 旧字形\",\n    \"files\": [\n      \"sarasa-gothic-cl/SarasaGothicCL-Light.ttf\",\n      \"sarasa-gothic-cl/SarasaGothicCL-Regular.ttf\",\n      \"sarasa-gothic-cl/SarasaGothicCL-SemiBold.ttf\",\n      \"sarasa-gothic-cl/SarasaGothicCL-Bold.ttf\"\n    ],\n    \"desc\": \"更纱黑体使用全宽引号和比例数字。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-ui-cl\",\n    \"name\": \"更纱黑体 UI CL 旧字形\",\n    \"files\": [\n      \"sarasa-ui-cl/SarasaUiCL-Light.ttf\",\n      \"sarasa-ui-cl/SarasaUiCL-Regular.ttf\",\n      \"sarasa-ui-cl/SarasaUiCL-SemiBold.ttf\",\n      \"sarasa-ui-cl/SarasaUiCL-Bold.ttf\"\n    ],\n    \"desc\": \"更纱黑体 UI 使用缩进引号和等宽数字。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-mono-cl\",\n    \"name\": \"等距更纱黑体 CL 旧字形\",\n    \"files\": [\n      \"sarasa-mono-cl/SarasaMonoCL-Light.ttf\",\n      \"sarasa-mono-cl/SarasaMonoCL-Regular.ttf\",\n      \"sarasa-mono-cl/SarasaMonoCL-SemiBold.ttf\",\n      \"sarasa-mono-cl/SarasaMonoCL-Bold.ttf\"\n    ],\n    \"desc\": \"等距更纱黑体使用等宽西文《Iosevka》。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"sarasa-slab-cl\",\n    \"name\": \"等距更纱黑体 Slab CL 旧字形\",\n    \"files\": [\n      \"sarasa-slab-cl/SarasaMonoSlabCL-Light.ttf\",\n      \"sarasa-slab-cl/SarasaMonoSlabCL-Regular.ttf\",\n      \"sarasa-slab-cl/SarasaMonoSlabCL-SemiBold.ttf\",\n      \"sarasa-slab-cl/SarasaMonoSlabCL-Bold.ttf\"\n    ],\n    \"desc\": \"等距更纱黑体 Slab 使用等宽西文《Iosevka Slab》。\",\n    \"official\": \"https://github.com/be5invis/Sarasa-Gothic\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"ysxxk\",\n    \"name\": \"演示夏行楷\",\n    \"files\": [\n      \"ysxxk/ysxxk.ttf\"\n    ],\n    \"desc\": \"「演示夏行楷」是 Keynote 研究所的人生哥制作发布的一款毛笔字体。字稿作者是刘锡栋：中国漓江书画艺术家协会理事丨北京中国书画研究院研究员丨中国民族硬笔书法家协会会员丨中国楹联学会会员丨黑龙江楹联家协会会员丨高级政工师，已退休 该字体简体中文行楷，包含标准的 6763 个字符。\",\n    \"official\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\"\n    }\n  },\n  {\n    \"id\": \"ysfxt\",\n    \"name\": \"演示佛系体\",\n    \"files\": [\n      \"ysfxt/ysfxt.ttf\"\n    ],\n    \"desc\": \"「演示佛系体」是由一生酷爱书法的纪国才老先生，在 80 岁这年亲手写了一套独具风格的字体，并授权 Keynote 研究所 和 秋叶 PPT 面向全社会联合发布，全渠道免费商用！\",\n    \"official\": \"https://mp.weixin.qq.com/s/iWn8SWH5ymBKmsGiHe8Yfw\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/iWn8SWH5ymBKmsGiHe8Yfw\"\n    }\n  },\n  {\n    \"id\": \"ysqhk\",\n    \"name\": \"演示秋鸿楷\",\n    \"files\": [\n      \"ysqhk/ysqhk.ttf\"\n    ],\n    \"desc\": \"「演示秋鸿楷」是 Keynote 研究所的人生哥制作发布的一款毛笔字体。字稿的作者是叶运鹏：高中教师丨辽宁人丨 98 年加入农民书画家协会。该字体简体中文楷书，包含标准的 6763 个字符。\",\n    \"official\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\"\n    }\n  },\n  {\n    \"id\": \"yscfk\",\n    \"name\": \"演示春风楷\",\n    \"files\": [\n      \"yscfk/yscfk.ttf\"\n    ],\n    \"desc\": \"「演示春风楷」是 Keynote 研究所的人生哥制作发布的一款毛笔字体。字稿的作者是徐占海，军人出身，1983 年入伍。每日笔耕不辍练习写字。该字体简体中文楷书，包含标准的 6763 个字符。\",\n    \"official\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/CRnRsYu8ymlG9_oK6wmBag\"\n    }\n  },\n  {\n    \"id\": \"ysyrxk\",\n    \"name\": \"演示悠然小楷\",\n    \"files\": [\n      \"ysyrxk/ysyrxk.ttf\"\n    ],\n    \"desc\": \"「演示悠然小楷」是秋叶 PPT 联合 keynote 研究所推出的一款书法字体，字稿的作者是孟祥媛，一位还在大学读书的书法专业学生。初看「演示悠然小楷」，可能并不觉得惊艳，再品，却会发现透着质朴、率真的气息。正如尚在象牙塔中的作者本人，那是未经雕琢的拙朴书生气。接下来，一起体会悠然小楷的这股「拙气」。悠然小楷笔画分明，结构清晰，没有过度的连笔和飞白，对阅读识别更为友好；小楷字形较小，天然拥有更大的字间距，即便作为长段文字使用，阅读上也不会有太大视觉压力；悠然小楷的笔画力度分布均衡，起收有序，没有太过强烈的对比，自然沉劲而不漂浮；在小楷的基础上有些行楷的影子，为字体增添了灵动，但又有克制，形成停而不断、笔断意连之态；部分笔画细节可能并不完美，不够顺滑，但这份未经雕琢，又何尝不是一种难得的拙朴；所以见过很多大开大合的书法字体后，再见悠然小楷，可能没有很惊艳之感。但艳丽与喧嚣并不一定代表力量，沉劲入骨更难能可贵\",\n    \"official\": \"https://mp.weixin.qq.com/s/Q1lAIre4yJ-Zlf2CD82EPA\",\n    \"license\": {\n      \"name\": \"其他协议\",\n      \"url\": \"https://mp.weixin.qq.com/s/Q1lAIre4yJ-Zlf2CD82EPA\"\n    }\n  },\n  {\n    \"id\": \"cyroithb\",\n    \"name\": \"Cyroit HB\",\n    \"files\": [\n      \"cyroithb/CyroitHB-Regular.ttf\",\n      \"cyroithb/CyroitHB-Bold.ttf\"\n    ],\n    \"desc\": \"全角英数や半角カナが判別しやすい、文字間隔調整機能付き等幅フォント。\",\n    \"official\": \"https://github.com/omonomo/Cyroit\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"advocateancientrounded\",\n    \"name\": \"尙古圆体\",\n    \"files\": [\n      \"advocateancientrounded/ShangguRoundST-Light.ttf\",\n      \"advocateancientrounded/ShangguRoundST-Regular.ttf\",\n      \"advocateancientrounded/ShangguRoundST-Medium.ttf\",\n      \"advocateancientrounded/ShangguRoundST-Bold.ttf\"\n    ],\n    \"desc\": \"基于思源的传承字形（旧字形）字体。\",\n    \"official\": \"https://github.com/GuiWonder/Shanggu\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"fanthinkgrotesk\",\n    \"name\": \"繁 Think 黑\",\n    \"files\": [\n      \"fanthinkgrotesk/FanThinkGrotesk-Thin.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-ExtraLight.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-Light.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-Text.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-Medium.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-SemiBold.otf\",\n      \"fanthinkgrotesk/FanThinkGrotesk-Bold.otf\"\n    ],\n    \"desc\": \"繁 Think 黑是一套基於 IBM Plex Sans TC 的自動簡轉繁字體。簡轉繁代碼來自 GuiWonder。\",\n    \"official\": \"https://github.com/pkj-l/FanThinkGrotesk\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"ipagothic\",\n    \"name\": \"IPAGothic\",\n    \"files\": [\n      \"ipagothic/ipag.ttf\"\n    ],\n    \"desc\": \"应 IPA 许可证要求，增加 IPA 原版字体以允许用户“替换回原始字体”。\",\n    \"official\": \"https://moji.or.jp/ipafont/ipa00303/\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"ipamincho\",\n    \"name\": \"IPAMincho\",\n    \"files\": [\n      \"ipamincho/ipam.ttf\"\n    ],\n    \"desc\": \"应 IPA 许可证要求，增加 IPA 原版字体以允许用户“替换回原始字体”。\",\n    \"official\": \"https://moji.or.jp/ipafont/ipa00303/\",\n    \"license\": {\n      \"name\": \"IPA Font License 1.0\",\n      \"url\": \"https://moji.or.jp/ipafont/license/\"\n    }\n  },\n  {\n    \"id\": \"atkinson\",\n    \"name\": \"Atkinson Hyperlegible Next\",\n    \"files\": [\n      \"atkinson/AtkinsonHyperlegibleNext-ExtraLight.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-Light.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-Regular.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-Medium.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-SemiBold.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-Bold.ttf\",\n      \"atkinson/AtkinsonHyperlegibleNext-ExtraBold.ttf\"\n    ],\n    \"desc\": \"Atkinson Hyperlegible, named after the founder of the Braille Institute, has been developed specifically to increase legibility for readers with low vision, and to improve comprehension.\",\n    \"official\": \"https://www.brailleinstitute.org/freefont/\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"lexend\",\n    \"name\": \"Lexend Deca\",\n    \"files\": [\n      \"lexend/LexendDeca-Thin.ttf\",\n      \"lexend/LexendDeca-ExtraLight.ttf\",\n      \"lexend/LexendDeca-Light.ttf\",\n      \"lexend/LexendDeca-Regular.ttf\",\n      \"lexend/LexendDeca-Medium.ttf\",\n      \"lexend/LexendDeca-SemiBold.ttf\",\n      \"lexend/LexendDeca-Bold.ttf\",\n      \"lexend/LexendDeca-ExtraBold.ttf\",\n      \"lexend/LexendDeca-Black.ttf\"\n    ],\n    \"desc\": \"Lexend is a variable typeface designed by Bonnie Shaver-Troup and Thomas Jockin in 2018. Applying the Shaver-Troup Individually Optimal Text Formation Factors, studies have found readers instantaneously improve their reading fluency.\",\n    \"official\": \"https://www.lexend.com/\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  },\n  {\n    \"id\": \"playpen\",\n    \"name\": \"Playpen Sans\",\n    \"files\": [\n      \"playpen/PlaypenSans-Thin.ttf\",\n      \"playpen/PlaypenSans-ExtraLight.ttf\",\n      \"playpen/PlaypenSans-Light.ttf\",\n      \"playpen/PlaypenSans-Regular.ttf\",\n      \"playpen/PlaypenSans-Medium.ttf\",\n      \"playpen/PlaypenSans-SemiBold.ttf\",\n      \"playpen/PlaypenSans-Bold.ttf\",\n      \"playpen/PlaypenSans-ExtraBold.ttf\"\n    ],\n    \"desc\": \"Playpen Sans is one of the font families produced by TypeTogether after more than two years of primary research into handwriting education for Latin-based languages. It has seven automatic alternates for each character and a built-in shuffler that both ensures variation and avoids repetitive shapes in close proximity. This feature adds to the overall organic, spontaneous, and authentic feel of the handwritten style.\",\n    \"official\": \"https://github.com/TypeTogether/Playpen-Sans\",\n    \"license\": {\n      \"name\": \"SIL OFL 1.1\",\n      \"url\": \"https://openfontlicense.org/open-font-license-official-text/\"\n    }\n  }\n]"
  },
  {
    "path": "simple_live_app/assets/io.github.SlotSun.Slive.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=Slive\nGenericName=Livestream Player\nIcon=io.github.SlotSun.Slive\nExec=io.github.SlotSun.Slive %U\nCategories=AudioVideo;Audio;Video;Network\nKeywords=Livestream;Video\nStartupNotify=true\n"
  },
  {
    "path": "simple_live_app/assets/io.github.SlotSun.Slive.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop\">\n  <id>io.github.SlotSun.Slive</id>\n  <launchable type=\"desktop-id\">io.github.SlotSun.Slive.desktop</launchable>\n  <name>Slive</name>\n  <developer id=\"io.github.slotsun\">\n    <name>SlotSun</name>\n  </developer>\n  <summary>Watch live streams simply</summary>\n  <summary xml:lang=\"zh_CN\">我就默默看你表演</summary>\n  <metadata_license>CC0-1.0</metadata_license>\n  <project_license>GPL-3.0</project_license>\n  <url type=\"homepage\">https://github.com/SlotSun/dart_simple_live/</url>\n  <url type=\"bugtracker\">https://github.com/SlotSun/dart_simple_live/issues</url>\n  <description>\n    <p>Slive is a lightweight and user-friendly application for watching live streams across multiple platforms, offering a seamless watching experience with support for popular streaming services.</p>\n    <p xml:lang=\"zh_CN\">Slive 是一款轻量级且用户友好的直播观看应用，支持多个主流直播平台，提供流畅的观看体验。</p>\n    <p>Slive support platforms:</p>\n    <p xml:lang=\"zh_CN\">支持直播平台：</p>\n    <ul>\n        <li>Huya</li>\n        <li xml:lang=\"zh_CN\">虎牙</li>\n        <li>Douyu</li>\n        <li xml:lang=\"zh_CN\">斗鱼</li>\n        <li>Bilibili</li>\n        <li xml:lang=\"zh_CN\">哔哩哔哩</li>\n        <li>Douyin</li>\n        <li xml:lang=\"zh_CN\">抖音</li>\n    </ul>\n  </description>\n  <screenshots>\n    <screenshot type=\"default\">\n      <caption>Light Mode</caption>\n      <image type=\"source\">https://raw.githubusercontent.com/SlotSun/dart_simple_live/v1.7.18/assets/screenshot_light.jpg</image>\n    </screenshot>\n    <screenshot type=\"default\">\n      <caption>Dark Mode</caption>\n      <image type=\"source\">https://raw.githubusercontent.com/SlotSun/dart_simple_live/v1.7.18/assets/screenshot_dark.jpg</image>\n    </screenshot>\n  </screenshots>\n  <releases>\n    <release version=\"1.8.7\" date=\"2026-02-06\">\n      <description>\n        <p>- 一个非常重要的过渡版本 </p>\n        <p>- 修复huya搜索 @GH4NG </p>\n        <p>- 引入Firebase </p>\n        <p>- 大量数据错误和潜在问题修复 </p>\n        <p>- 一些细节调整  </p>\n        <p>- 关于linux的一系列修复 @pugaizai </p>\n        <p>- tips: ios和macos用户请到action更新测试或者下载上游仓库版本</p>\n      </description>\n    </release>\n  </releases>\n  <content_rating type=\"oars-1.1\"/>\n  <update_contact>i@pugai.life</update_contact>\n</component>\n"
  },
  {
    "path": "simple_live_app/assets/io.github.SlotSun.dart_simple_live.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=Slive\nGenericName=Livestream Player\nIcon=io.github.SlotSun.dart_simple_live\nExec=Slive %U\nCategories=AudioVideo;Audio;Video;Network\nKeywords=Livestream;Video\nStartupNotify=true\n"
  },
  {
    "path": "simple_live_app/assets/io.github.SlotSun.dart_simple_live.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop\">\n  <id>io.github.SlotSun.dart_simple_live</id>\n  <launchable type=\"desktop-id\">io.github.SlotSun.dart_simple_live.desktop</launchable>\n  <name>Slive</name>\n  <developer id=\"io.github.slotsun\">\n    <name>SlotSun</name>\n  </developer>\n  <summary>Watch live streams simply</summary>\n  <summary xml:lang=\"zh_CN\">我就默默看你表演</summary>\n  <metadata_license>CC0-1.0</metadata_license>\n  <project_license>GPL-3.0</project_license>\n  <url type=\"homepage\">https://github.com/SlotSun/dart_simple_live/</url>\n  <url type=\"bugtracker\">https://github.com/SlotSun/dart_simple_live/issues</url>\n  <description>\n    <p>Slive is a lightweight and user-friendly application for watching live streams across multiple platforms, offering a seamless watching experience with support for popular streaming services.</p>\n    <p xml:lang=\"zh_CN\">Slive 是一款轻量级且用户友好的直播观看应用，支持多个主流直播平台，提供流畅的观看体验。</p>\n    <p>Slive support platforms:</p>\n    <p xml:lang=\"zh_CN\">支持直播平台：</p>\n    <ul>\n        <li>Huya</li>\n        <li xml:lang=\"zh_CN\">虎牙</li>\n        <li>Douyu</li>\n        <li xml:lang=\"zh_CN\">斗鱼</li>\n        <li>Bilibili</li>\n        <li xml:lang=\"zh_CN\">哔哩哔哩</li>\n        <li>Douyin</li>\n        <li xml:lang=\"zh_CN\">抖音</li>\n    </ul>\n  </description>\n  <screenshots>\n    <screenshot type=\"default\">\n      <caption>Light Mode</caption>\n      <image type=\"source\">https://raw.githubusercontent.com/SlotSun/dart_simple_live/v1.7.18/assets/screenshot_light.jpg</image>\n    </screenshot>\n    <screenshot type=\"default\">\n      <caption>Dark Mode</caption>\n      <image type=\"source\">https://raw.githubusercontent.com/SlotSun/dart_simple_live/v1.7.18/assets/screenshot_dark.jpg</image>\n    </screenshot>\n  </screenshots>\n  <releases>\n    <release version=\"1.8.4\" date=\"2025-12-18\">\n      <description>\n        <p>### 已修改包名slotsun.slive,相关事宜请查看 #93 </p>\n        <p>- fix：huya </p>\n        <p>- 优化弹幕去重功能 </p>\n        <p>- 关于linux的一系列修复 @pugaizai</p>\n        <p>- fix: 一些代码和逻辑错误</p>\n        <p>- tips: ios和macos用户请到action更新测试或者下载上游仓库版本</p>\n      </description>\n    </release>\n  </releases>\n  <content_rating type=\"oars-1.1\"/>\n  <update_contact>i@pugai.life</update_contact>\n</component>\n"
  },
  {
    "path": "simple_live_app/assets/lotties/empty.json",
    "content": "{\"v\":\"4.7.0\",\"fr\":25,\"ip\":0,\"op\":50,\"w\":120,\"h\":120,\"nm\":\"Comp 1\",\"ddd\":0,\"assets\":[],\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"ruoi\",\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.967]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p967_0p167_0p033\"],\"t\":35,\"s\":[100],\"e\":[0]},{\"t\":49}]},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0,\"y\":0},\"n\":\"0p833_0p833_0_0\",\"t\":0,\"s\":[57.361,61.016,0],\"e\":[57.699,41.796,0],\"to\":[-4.67500305175781,-4.12800598144531,0],\"ti\":[-13.9099960327148,5.27300262451172,0]},{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0.167,\"y\":0.167},\"n\":\"0p833_0p833_0p167_0p167\",\"t\":10.219,\"s\":[57.699,41.796,0],\"e\":[79.084,33.982,0],\"to\":[12.8159942626953,-4.85800170898438,0],\"ti\":[-4.54498291015625,3.73400115966797,0]},{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0.167,\"y\":0.167},\"n\":\"0p833_0p833_0p167_0p167\",\"t\":19.445,\"s\":[79.084,33.982,0],\"e\":[59.691,9.121,0],\"to\":[6.61601257324219,-5.43799591064453,0],\"ti\":[20.0290069580078,1.20700073242188,0]},{\"t\":35}]},\"a\":{\"a\":0,\"k\":[60.531,10.945,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-0.994,0],[0,-0.994],[0.995,0],[0,0.994]],\"o\":[[0.995,0],[0,0.994],[-0.994,0],[0,-0.994]],\"v\":[[-0.001,-1.801],[1.801,-0.001],[-0.001,1.801],[-1.801,-0.001]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[62.4,13.144],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 1\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-1.422,0],[0,-1.422],[1.421,0],[0,1.422]],\"o\":[[1.421,0],[0,1.422],[-1.422,0],[0,-1.422]],\"v\":[[0.001,-2.574],[2.574,0],[0.001,2.574],[-2.574,0]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":0.7},\"lc\":1,\"lj\":1,\"ml\":10,\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[1,1,1,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[64.145,9.606],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 2\",\"np\":3,\"cix\":2,\"ix\":2,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-1.996,0],[0,-1.996],[1.996,0],[0,1.996]],\"o\":[[1.996,0],[0,1.996],[-1.996,0],[0,-1.996]],\"v\":[[0,-3.614],[3.614,0],[0,3.614],[-3.614,0]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":0.7},\"lc\":1,\"lj\":1,\"ml\":10,\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[1,1,1,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[57.957,10.552],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 3\",\"np\":3,\"cix\":2,\"ix\":3,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60.531,10.941],\"ix\":2},\"a\":{\"a\":0,\"k\":[60.531,10.941],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"ruoi\",\"np\":3,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Shape Layer 2\",\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.967]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p967_0p167_0p033\"],\"t\":35,\"s\":[100],\"e\":[0]},{\"t\":49}]},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":0,\"k\":[-0.75,-0.75,0]},\"a\":{\"a\":0,\"k\":[0,0,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[-13.91,5.273],[-4.545,3.734],[20.029,1.207]],\"o\":[[-4.675,-4.128],[12.816,-4.858],[6.616,-5.438],[0,0]],\"v\":[[-7.383,24.76],[-7.046,5.54],[14.34,-2.273],[-3.178,-24.76]],\"c\":false}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.34901960784313724,0.3686274509803922,0.4,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":1},\"lc\":2,\"lj\":2,\"d\":[{\"n\":\"d\",\"nm\":\"dash\",\"v\":{\"a\":0,\"k\":2.028}},{\"n\":\"g\",\"nm\":\"gap\",\"v\":{\"a\":0,\"k\":2.028}},{\"n\":\"o\",\"nm\":\"offset\",\"v\":{\"a\":0,\"k\":0}}],\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[67.87,37.631],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 6\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tm\",\"s\":{\"a\":0,\"k\":0,\"ix\":1},\"e\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.953]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p953_0p167_0p033\"],\"t\":0,\"s\":[0],\"e\":[100]},{\"t\":35}],\"ix\":2},\"o\":{\"a\":0,\"k\":0,\"ix\":3},\"m\":1,\"ix\":2,\"nm\":\"Trim Paths 1\",\"mn\":\"ADBE Vector Filter - Trim\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"im_emptyBox Outlines\",\"ks\":{\"o\":{\"a\":0,\"k\":100},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":0,\"k\":[60,60,0]},\"a\":{\"a\":0,\"k\":[60,60,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[-0.001,-16.607],[-32.143,-0.002],[-0.001,16.607],[32.144,-0.002]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.8,0.82,0.851,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,55.75],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 7\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[12.856,-23.249],[0,-16.605],[-12.857,-23.249],[-45,-6.641],[-32.144,0.001],[-45,6.645],[-12.857,23.249],[0,16.609],[12.856,23.249],[45,6.645],[32.143,0.001],[45,-6.641]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9372549019607843,0.9372549019607843,0.9372549019607843,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,55.748],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 8\",\"np\":2,\"cix\":2,\"ix\":2,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[-16.072,24.171],[16.072,11.312],[16.072,-24.171],[-16.072,-24.171]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9529411764705882,0.9529411764705882,0.9529411764705882,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[76.072,83.33],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 9\",\"np\":2,\"cix\":2,\"ix\":3,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[-32.143,-24.171],[-32.143,11.311],[-0.001,24.171],[32.144,11.311],[32.144,-24.171]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.8,0.82,0.851,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,83.33],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 10\",\"np\":2,\"cix\":2,\"ix\":4,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,60.186],\"ix\":2},\"a\":{\"a\":0,\"k\":[60,60.186],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"box\",\"np\":4,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1}]}"
  },
  {
    "path": "simple_live_app/assets/lotties/error.json",
    "content": "{\"v\":\"5.8.1\",\"fr\":29.9700012207031,\"ip\":0,\"op\":301.000012259981,\"w\":1080,\"h\":900,\"nm\":\"Composition 1\",\"ddd\":0,\"assets\":[{\"id\":\"comp_0\",\"nm\":\"Nuage\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 11\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[54,54],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-22,-239],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 12\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[544.675,315.475,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-54.5,-226.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[80,80,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[31,31],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-54.5,-226.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[31,31],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-54.5,-226.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[100,20],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":20,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-26,-216],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_1\",\"nm\":\"éolienne\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":0,\"nm\":\"Hélices\",\"refId\":\"comp_2\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.137],\"y\":[1]},\"o\":{\"x\":[0.567],\"y\":[0]},\"t\":1,\"s\":[0]},{\"t\":300.00001221925,\"s\":[1440]}],\"ix\":10},\"p\":{\"a\":0,\"k\":[800,440,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[800,440,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Socle eolienne\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[264.75,-95],[257,-95],[242,252],[288,251]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_2\",\"nm\":\"Hélices\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 11\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":-239.6,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":-122.747,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[800.5,439.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[266.5,-94.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[27,27],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[266.5,-94.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_3\",\"nm\":\"plot base\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[541,387.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[1,-152.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[13,-223],[-13,-223],[-52,-82],[54,-82]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,502,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,-38,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[58,-56],[-59,-56],[-70,-20],[70,-20]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 5\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[539.75,606.25,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-0.25,66.25,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[256.5,28.5],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.7647058823529411,0.3215686274509804,0.23137254901960785,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-0.25,66.25],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 6\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,572,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,32,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[78,3],[-76,3],[-93,60],[93,61]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_4\",\"nm\":\"Tree\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-171.5,-79.5],[-152.5,-45]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980451995,0.84313731474,0.84313731474,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":7,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-154.5,-23.5],[-137.5,-48.5]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980451995,0.84313731474,0.84313731474,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":7,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[386,620,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-154,80,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-154,256],[-154,-96]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980392157,0.844306078144,0.844306078144,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":10,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[384,475,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-156,-65,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[96,222],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":62,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.949019667682,0.949019667682,0.949019667682,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-156,-65],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_5\",\"nm\":\"ground\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 2\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[515,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[662,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[817,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[78,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 3\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[752,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[89,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[270,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[102,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]}],\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":0,\"nm\":\"Nuage\",\"refId\":\"comp_0\",\"sr\":1,\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.833],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":51,\"s\":[100]},{\"i\":{\"x\":[0.833],\"y\":[1]},\"o\":{\"x\":[0.167],\"y\":[0]},\"t\":234,\"s\":[100]},{\"t\":299.00001217852,\"s\":[0]}],\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.284,\"y\":1},\"o\":{\"x\":0.387,\"y\":0},\"t\":0,\"s\":[704,380,0],\"to\":[-36.667,0,0],\"ti\":[36.667,0,0]},{\"t\":299.00001217852,\"s\":[484,380,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[514,308,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],\"o\":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],\"v\":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.83137254902,0.821591725069,0.821591725069,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":0,\"nm\":\"éolienne\",\"refId\":\"comp_1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[804,796,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[804,796,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":0,\"nm\":\"plot base\",\"refId\":\"comp_3\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":7.368,\"s\":[6]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":14.736,\"s\":[-5]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":22.264,\"s\":[4]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":29.633,\"s\":[-2]},{\"t\":37.0000015070409,\"s\":[0]}],\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":0,\"s\":[540,792,0],\"to\":[0,-2.667,0],\"ti\":[0,2,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":7.368,\"s\":[540,776,0],\"to\":[0,-2,0],\"ti\":[0,-1.333,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":14.736,\"s\":[540,780,0],\"to\":[0,1.333,0],\"ti\":[0,-1.333,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":22.264,\"s\":[540,784,0],\"to\":[0,1.333,0],\"ti\":[0,-2,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":29.633,\"s\":[540,788,0],\"to\":[0,2,0],\"ti\":[0,-1.333,0]},{\"t\":37.0000015070409,\"s\":[540,796,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,616,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":5,\"ty\":0,\"nm\":\"éolienne\",\"refId\":\"comp_1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[670,796,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[804,796,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[63,63,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":6,\"ty\":0,\"nm\":\"Tree\",\"refId\":\"comp_4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[280,790,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[384,790,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[82,82,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":7,\"ty\":0,\"nm\":\"Tree\",\"refId\":\"comp_4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":8,\"ty\":4,\"nm\":\"Arbuste\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[68,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],\"o\":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],\"v\":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":9,\"ty\":0,\"nm\":\"ground\",\"refId\":\"comp_5\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":10,\"ty\":0,\"nm\":\"Nuage\",\"refId\":\"comp_0\",\"sr\":1,\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":51,\"s\":[100]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":234,\"s\":[100]},{\"t\":299.00001217852,\"s\":[0]}],\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":0,\"s\":[193,606,0],\"to\":[56.5,0,0],\"ti\":[-56.5,0,0]},{\"t\":299.00001217852,\"s\":[532,606,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[514,308,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[60,60,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":11,\"ty\":4,\"nm\":\"Calque de forme 6\",\"td\":1,\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[572,712,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[784,628],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.909803921569,0.909803921569,0.909803921569,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-36,-234],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":12,\"ty\":4,\"nm\":\"Calque de forme 5\",\"tt\":1,\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,716,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[728,728],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.976470588235,0.976470588235,0.976470588235,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[8,-140],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":14,\"ty\":1,\"nm\":\"Blanc uni 1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"sw\":1080,\"sh\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}],\"markers\":[]}"
  },
  {
    "path": "simple_live_app/assets/lotties/loadding.json",
    "content": "{\n    \"v\": \"5.5.8\",\n    \"fr\": 50,\n    \"ip\": 0,\n    \"op\": 147,\n    \"w\": 800,\n    \"h\": 600,\n    \"nm\": \"Paperplane\",\n    \"ddd\": 0,\n    \"assets\": [\n        {\n            \"id\": \"comp_0\",\n            \"layers\": [\n                {\n                    \"ddd\": 0,\n                    \"ind\": 1,\n                    \"ty\": 4,\n                    \"nm\": \"planete Outlines - Group 4\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 38,\n                                    \"s\": [\n                                        50\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 88,\n                                    \"s\": [\n                                        50\n                                    ]\n                                },\n                                {\n                                    \"t\": 120,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 0,\n                            \"k\": 0,\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.833,\n                                        \"y\": 0.833\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.167,\n                                        \"y\": 0.167\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        468.336,\n                                        323.378,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        -29,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        29,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 102,\n                                    \"s\": [\n                                        294.336,\n                                        323.378,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                453.672,\n                                304.756,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                50,\n                                50,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [\n                                                    6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0.741,\n                                                    -0.14\n                                                ],\n                                                [\n                                                    0,\n                                                    0.074\n                                                ],\n                                                [\n                                                    13.484,\n                                                    0\n                                                ],\n                                                [\n                                                    1.669,\n                                                    -0.361\n                                                ],\n                                                [\n                                                    19.79,\n                                                    0\n                                                ],\n                                                [\n                                                    3.317,\n                                                    -19.082\n                                                ],\n                                                [\n                                                    2.691,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -0.048,\n                                                    -0.629\n                                                ],\n                                                [\n                                                    2.405,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.742\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.743\n                                                ]\n                                            ],\n                                            \"o\": [\n                                                [\n                                                    -0.781,\n                                                    0\n                                                ],\n                                                [\n                                                    0.001,\n                                                    -0.074\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -1.778,\n                                                    0\n                                                ],\n                                                [\n                                                    -3.594,\n                                                    -18.742\n                                                ],\n                                                [\n                                                    -20.03,\n                                                    0\n                                                ],\n                                                [\n                                                    -2.421,\n                                                    -0.804\n                                                ],\n                                                [\n                                                    -13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0.642\n                                                ],\n                                                [\n                                                    -1.89,\n                                                    -1.199\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.743\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.742\n                                                ]\n                                            ],\n                                            \"v\": [\n                                                [\n                                                    75.134,\n                                                    16.175\n                                                ],\n                                                [\n                                                    72.85,\n                                                    16.396\n                                                ],\n                                                [\n                                                    72.856,\n                                                    16.175\n                                                ],\n                                                [\n                                                    48.44,\n                                                    -8.241\n                                                ],\n                                                [\n                                                    43.262,\n                                                    -7.685\n                                                ],\n                                                [\n                                                    3.406,\n                                                    -40.591\n                                                ],\n                                                [\n                                                    -36.571,\n                                                    -6.995\n                                                ],\n                                                [\n                                                    -44.269,\n                                                    -8.241\n                                                ],\n                                                [\n                                                    -68.685,\n                                                    16.175\n                                                ],\n                                                [\n                                                    -68.604,\n                                                    18.079\n                                                ],\n                                                [\n                                                    -75.133,\n                                                    16.175\n                                                ],\n                                                [\n                                                    -87.341,\n                                                    28.383\n                                                ],\n                                                [\n                                                    -75.133,\n                                                    40.592\n                                                ],\n                                                [\n                                                    75.134,\n                                                    40.592\n                                                ],\n                                                [\n                                                    87.342,\n                                                    28.383\n                                                ]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.815686334348,\n                                            0.823529471603,\n                                            0.827451040231,\n                                            1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 5\n                                    },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            453.672,\n                                            304.756\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0,\n                                            0\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            100,\n                                            100\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 4\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 2,\n                    \"ty\": 4,\n                    \"nm\": \"Merged Shape Layer\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 0,\n                            \"k\": 100,\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.547\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.845\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 77,\n                                    \"s\": [\n                                        35\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        390.319,\n                                        298.2,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        -2.583,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 44,\n                                    \"s\": [\n                                        390.319,\n                                        282.7,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 110,\n                                    \"s\": [\n                                        390.319,\n                                        319.25,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        390.319,\n                                        298.2,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                664.319,\n                                256.2,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                100,\n                                100,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            18.967,\n                                                            -3.189\n                                                        ],\n                                                        [\n                                                            -18.967,\n                                                            19.935\n                                                        ],\n                                                        [\n                                                            -0.949,\n                                                            -19.935\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.223528981209,\n                                                    0.192156970501,\n                                                    0.674510002136,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    236.879,\n                                                    292.737\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 1\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            633.939,\n                                            275.369\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            236.879,\n                                            292.737\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 1\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        },\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            -98.335,\n                                                            64.79\n                                                        ],\n                                                        [\n                                                            -105.619,\n                                                            4.984\n                                                        ],\n                                                        [\n                                                            105.619,\n                                                            -64.79\n                                                        ],\n                                                        [\n                                                            -80.316,\n                                                            24.919\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.278430998325,\n                                                    0.294117987156,\n                                                    0.847059011459,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    316.247,\n                                                    247.882\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 2\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            673.623,\n                                            252.941\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            316.247,\n                                            247.882\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 2\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 2,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        },\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            -133.812,\n                                                            -42.171\n                                                        ],\n                                                        [\n                                                            133.812,\n                                                            -75.141\n                                                        ],\n                                                        [\n                                                            5.765,\n                                                            75.141\n                                                        ],\n                                                        [\n                                                            -61.708,\n                                                            18.402\n                                                        ],\n                                                        [\n                                                            124.227,\n                                                            -71.307\n                                                        ],\n                                                        [\n                                                            -87.011,\n                                                            -1.534\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.365000009537,\n                                                    0.407999992371,\n                                                    0.976000010967,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    297.638,\n                                                    254.4\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 3\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            664.319,\n                                            256.2\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            297.638,\n                                            254.4\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 3\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 3,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 3,\n                    \"ty\": 4,\n                    \"nm\": \"planete Outlines - Group 5\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 45,\n                                    \"s\": [\n                                        100\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 102,\n                                    \"s\": [\n                                        100\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 0,\n                            \"k\": 0,\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.833,\n                                        \"y\": 0.833\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.167,\n                                        \"y\": 0.167\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        327.38,\n                                        267.583,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        25.833,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        -25.833,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        482.38,\n                                        267.583,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                171.76,\n                                193.166,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                50,\n                                50,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [\n                                                    13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    4.38,\n                                                    -4.171\n                                                ],\n                                                [\n                                                    21.913,\n                                                    0\n                                                ],\n                                                [\n                                                    3.575,\n                                                    -18.765\n                                                ],\n                                                [\n                                                    1.851,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -0.011,\n                                                    -0.291\n                                                ],\n                                                [\n                                                    1.599,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.743\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    13.485\n                                                ]\n                                            ],\n                                            \"o\": [\n                                                [\n                                                    -6.526,\n                                                    0\n                                                ],\n                                                [\n                                                    -0.793,\n                                                    -21.719\n                                                ],\n                                                [\n                                                    -19.806,\n                                                    0\n                                                ],\n                                                [\n                                                    -1.734,\n                                                    -0.391\n                                                ],\n                                                [\n                                                    -13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0.293\n                                                ],\n                                                [\n                                                    -1.4,\n                                                    -0.559\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.742\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ]\n                                            ],\n                                            \"v\": [\n                                                [\n                                                    59.669,\n                                                    -8.242\n                                                ],\n                                                [\n                                                    42.84,\n                                                    -1.506\n                                                ],\n                                                [\n                                                    2.287,\n                                                    -40.592\n                                                ],\n                                                [\n                                                    -37.576,\n                                                    -7.638\n                                                ],\n                                                [\n                                                    -42.962,\n                                                    -8.242\n                                                ],\n                                                [\n                                                    -67.378,\n                                                    16.174\n                                                ],\n                                                [\n                                                    -67.356,\n                                                    17.049\n                                                ],\n                                                [\n                                                    -71.878,\n                                                    16.174\n                                                ],\n                                                [\n                                                    -84.086,\n                                                    28.383\n                                                ],\n                                                [\n                                                    -71.878,\n                                                    40.591\n                                                ],\n                                                [\n                                                    59.669,\n                                                    40.591\n                                                ],\n                                                [\n                                                    84.086,\n                                                    16.174\n                                                ]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.816000007181,\n                                            0.823999980852,\n                                            0.827000038297,\n                                            1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 5\n                                    },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            171.76,\n                                            193.166\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0,\n                                            0\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            100,\n                                            100\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 5\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                }\n            ]\n        }\n    ],\n    \"layers\": [\n        {\n            \"ddd\": 0,\n            \"ind\": 1,\n            \"ty\": 0,\n            \"nm\": \"Pre-comp 1\",\n            \"refId\": \"comp_0\",\n            \"sr\": 1,\n            \"ks\": {\n                \"o\": {\n                    \"a\": 0,\n                    \"k\": 100,\n                    \"ix\": 11\n                },\n                \"r\": {\n                    \"a\": 0,\n                    \"k\": 0,\n                    \"ix\": 10\n                },\n                \"p\": {\n                    \"a\": 0,\n                    \"k\": [\n                        406,\n                        306,\n                        0\n                    ],\n                    \"ix\": 2\n                },\n                \"a\": {\n                    \"a\": 0,\n                    \"k\": [\n                        400,\n                        300,\n                        0\n                    ],\n                    \"ix\": 1\n                },\n                \"s\": {\n                    \"a\": 0,\n                    \"k\": [\n                        179,\n                        179,\n                        100\n                    ],\n                    \"ix\": 6\n                }\n            },\n            \"ao\": 0,\n            \"w\": 800,\n            \"h\": 600,\n            \"ip\": 0,\n            \"op\": 147,\n            \"st\": 0,\n            \"bm\": 0\n        }\n    ],\n    \"markers\": []\n}"
  },
  {
    "path": "simple_live_app/assets/statement.txt",
    "content": "在使用本软件之前，请您仔细阅读以下内容，并确保您充分理解并同意以下条款：\n1、本软件为开源软件，您可以免费获取并使用该软件。\n2、本软件完全基于您个人意愿使用，您应该对自己的使用行为和所有结果承担全部责任。\n3、本软件仅供学习交流、科研等非商业性质的用途，严禁将本软件用于商业目的。如有任何商业行为，均与本软件无关。\n4、本软件并不保证与所有操作系统或硬件设备兼容。本软件作者或贡献者不对因使用本软件而产生的任何技术或安全问题承担责任。\n5、本软件作者或贡献者不承担因使用本软件而造成的任何直接、间接、特殊或后果性的损失或损害的责任，包括但不限于财产损失、商业利润损失、信息或数据丢失或损坏等。\n6、本软件使用者应遵守国家相关法律法规和使用规范，不得利用本软件从事任何违法违规行为。如因使用本软件而导致的违法行为，使用者应承担相应的法律责任。\n7、本软件不会收集、存储、使用任何用户的个人信息，包括但不限于姓名、地址、电子邮件地址、电话号码等。在使用本软件过程中，不会进行任何形式的个人信息采集。如用户提供任何个人信息，将被视为用户已自愿提供，并且用户将自行承担由此产生的所有法律责任。\n8、本软件作者或贡献者保留随时修改、增加、删除本免责声明中的内容而不另行通知的权利。\n9、如果本软件存在侵犯您的合法权益的情况，请及时与作者联系，作者将会及时删除有关内容。\n如您不同意本免责声明中的任何内容，请勿使用本软件。使用本软件即代表您已完全理解并同意上述内容。"
  },
  {
    "path": "simple_live_app/distribute_options.yaml",
    "content": "output: build/dist/"
  },
  {
    "path": "simple_live_app/flutter_rust_bridge.yaml",
    "content": "rust_input: crate::api\nrust_root: rust/\ndart_output: lib/src/rust"
  },
  {
    "path": "simple_live_app/integration_test/simple_test.dart",
    "content": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:simple_live_app/main.dart';\nimport 'package:simple_live_app/src/rust/frb_generated.dart';\nimport 'package:integration_test/integration_test.dart';\n\nvoid main() {\n  IntegrationTestWidgetsFlutterBinding.ensureInitialized();\n  setUpAll(() async => await RustLib.init());\n  testWidgets('Can call rust function', (WidgetTester tester) async {\n    await tester.pumpWidget(const MyApp());\n    expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "simple_live_app/ios/.gitignore",
    "content": "**/dgph\n*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/DerivedData/\nIcon?\n**/Pods/\n**/.symlinks/\nprofile\nxcuserdata\n**/.generated/\nFlutter/App.framework\nFlutter/Flutter.framework\nFlutter/Flutter.podspec\nFlutter/Generated.xcconfig\nFlutter/ephemeral/\nFlutter/app.flx\nFlutter/app.zip\nFlutter/flutter_assets/\nFlutter/flutter_export_environment.sh\nServiceDefinitions.json\nRunner/GeneratedPluginRegistrant.*\n\n# Exceptions to above rules.\n!default.mode1v3\n!default.mode2v3\n!default.pbxuser\n!default.perspectivev3\n"
  },
  {
    "path": "simple_live_app/ios/Flutter/AppFrameworkInfo.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>App</string>\n  <key>CFBundleIdentifier</key>\n  <string>io.flutter.flutter.app</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>App</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>1.0</string>\n  <key>MinimumOSVersion</key>\n  <string>13.0</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/ios/Flutter/Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/ios/Flutter/Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/ios/Podfile",
    "content": "# Uncomment this line to define a global platform for your project\nplatform :ios, '15.0'\n\n# CocoaPods analytics sends network stats synchronously affecting flutter build latency.\nENV['COCOAPODS_DISABLE_STATS'] = 'true'\n\nproject 'Runner', {\n  'Debug' => :debug,\n  'Profile' => :release,\n  'Release' => :release,\n}\n\ndef flutter_root\n  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)\n  unless File.exist?(generated_xcode_build_settings_path)\n    raise \"#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first\"\n  end\n\n  File.foreach(generated_xcode_build_settings_path) do |line|\n    matches = line.match(/FLUTTER_ROOT\\=(.*)/)\n    return matches[1].strip if matches\n  end\n  raise \"FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_ios_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))\nend\n\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_ios_build_settings(target)\n    target.build_configurations.each do |config|\n      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [\n        '$(inherited)',\n\n        ## dart: PermissionGroup.calendar\n        # 'PERMISSION_EVENTS=1',\n\n        ## dart: PermissionGroup.reminders\n        # 'PERMISSION_REMINDERS=1',\n\n        ## dart: PermissionGroup.contacts\n        # 'PERMISSION_CONTACTS=1',\n\n        ## dart: PermissionGroup.camera\n        #'PERMISSION_CAMERA=1',\n\n        ## dart: PermissionGroup.microphone\n        # 'PERMISSION_MICROPHONE=1',\n\n        ## dart: PermissionGroup.speech\n        # 'PERMISSION_SPEECH_RECOGNIZER=1',\n\n        ## dart: PermissionGroup.photos\n        'PERMISSION_PHOTOS=1',\n\n        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]\n        #'PERMISSION_LOCATION=1',\n\n        ## dart: PermissionGroup.notification\n        #'PERMISSION_NOTIFICATIONS=1',\n\n        ## dart: PermissionGroup.mediaLibrary\n        # 'PERMISSION_MEDIA_LIBRARY=1',\n\n        ## dart: PermissionGroup.sensors\n        # 'PERMISSION_SENSORS=1',   \n\n        ## dart: PermissionGroup.bluetooth\n        # 'PERMISSION_BLUETOOTH=1',\n\n        ## dart: PermissionGroup.appTrackingTransparency\n        # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',\n\n        ## dart: PermissionGroup.criticalAlerts\n        # 'PERMISSION_CRITICAL_ALERTS=1'\n      ]\n\n    end \n  end\nend\n"
  },
  {
    "path": "simple_live_app/ios/Runner/AppDelegate.swift",
    "content": "import UIKit\nimport Flutter\n\n@main\n@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n\n  func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {\n    GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)\n  }\n\n}\n"
  },
  {
    "path": "simple_live_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n    \"images\": [\n        {\n            \"size\": \"20x20\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-20@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"20x20\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-20@3x.png\",\n            \"scale\": \"3x\"\n        },\n        {\n            \"size\": \"29x29\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-29.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"29x29\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-29@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"29x29\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-29@3x.png\",\n            \"scale\": \"3x\"\n        },\n        {\n            \"size\": \"40x40\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-40@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"40x40\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-40@3x.png\",\n            \"scale\": \"3x\"\n        },\n        {\n            \"size\": \"60x60\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-60@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"60x60\",\n            \"idiom\": \"iphone\",\n            \"filename\": \"icon-60@3x.png\",\n            \"scale\": \"3x\"\n        },\n        {\n            \"size\": \"20x20\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-20-ipad.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"20x20\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-20@2x-ipad.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"29x29\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-29-ipad.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"29x29\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-29@2x-ipad.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"40x40\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-40.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"40x40\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-40@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"76x76\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-76.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"76x76\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-76@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"83.5x83.5\",\n            \"idiom\": \"ipad\",\n            \"filename\": \"icon-83.5@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"1024x1024\",\n            \"idiom\": \"ios-marketing\",\n            \"filename\": \"icon-1024.png\",\n            \"scale\": \"1x\"\n        }\n    ],\n    \"info\": {\n        \"version\": 1,\n        \"author\": \"icon.wuruihong.com\"\n    }\n}"
  },
  {
    "path": "simple_live_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "simple_live_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "content": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in this directory.\n\nYou can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images."
  },
  {
    "path": "simple_live_app/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16G29\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Ydg-fD-yQy\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xbc-2k-c8Z\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" image=\"LaunchImage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRO-k0-Ey4\">\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"1a2-6s-vTC\"/>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"4X2-HB-R7a\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"LaunchImage\" width=\"168\" height=\"185\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "simple_live_app/ios/Runner/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--Flutter View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"FlutterViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "simple_live_app/ios/Runner/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CADisableMinimumFrameDurationOnPhone</key>\n\t<true/>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Simple Live</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>simple_live_app</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(FLUTTER_BUILD_NAME)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n\t<key>UIApplicationSupportsIndirectInputEvents</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>audio</string>\n\t</array>\n\t<key>NSPhotoLibraryUsageDescription</key>\n\t<string>保存图片至相册</string>\n\t<key>UISupportsDocumentBrowser</key>\n\t<true/>\n\t<key>io.flutter.embedded_views_preview</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>用于扫描二维码</string>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneClassName</key><string>UIWindowScene</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key><string>FlutterSceneDelegate</string>\n\t\t\t\t\t<key>UISceneConfigurationName</key><string>flutter</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key><string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/ios/Runner/Runner-Bridging-Header.h",
    "content": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };\n\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };\n\t\t73C9599770D417F3E7B681E2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */; };\n\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };\n\t\t97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };\n\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };\n\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t9705A1C41CF9048500538489 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t0874FB99E210639E7D21C1F0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.profile.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = \"<group>\"; };\n\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = \"<group>\"; };\n\t\t2778CC04696D7C0E532931A0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.debug.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = \"<group>\"; };\n\t\t60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t6C36D91D13E89663DBB13E51 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.release.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Runner-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = \"<group>\"; };\n\t\t97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t97C146EB1CF9000F007C117D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t73C9599770D417F3E7B681E2 /* Pods_Runner.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t65B8FB167D986F3BCF168FB6 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9740EEB11CF90186004384FC /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */,\n\t\t\t);\n\t\t\tname = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146E51CF9000F007C117D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9740EEB11CF90186004384FC /* Flutter */,\n\t\t\t\t97C146F01CF9000F007C117D /* Runner */,\n\t\t\t\t97C146EF1CF9000F007C117D /* Products */,\n\t\t\t\tFD158AC2F4211953A42B4A25 /* Pods */,\n\t\t\t\t65B8FB167D986F3BCF168FB6 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146EF1CF9000F007C117D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146EE1CF9000F007C117D /* Runner.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146F01CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FA1CF9000F007C117D /* Main.storyboard */,\n\t\t\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */,\n\t\t\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,\n\t\t\t\t97C147021CF9000F007C117D /* Info.plist */,\n\t\t\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,\n\t\t\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,\n\t\t\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */,\n\t\t\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD158AC2F4211953A42B4A25 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2778CC04696D7C0E532931A0 /* Pods-Runner.debug.xcconfig */,\n\t\t\t\t6C36D91D13E89663DBB13E51 /* Pods-Runner.release.xcconfig */,\n\t\t\t\t0874FB99E210639E7D21C1F0 /* Pods-Runner.profile.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t97C146ED1CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tEEC3C9B6719E92514BD4D205 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t9740EEB61CF901F6004384FC /* Run Script */,\n\t\t\t\t97C146EA1CF9000F007C117D /* Sources */,\n\t\t\t\t97C146EB1CF9000F007C117D /* Frameworks */,\n\t\t\t\t97C146EC1CF9000F007C117D /* Resources */,\n\t\t\t\t9705A1C41CF9048500538489 /* Embed Frameworks */,\n\t\t\t\t3B06AD1E1E4923F5004D2608 /* Thin Binary */,\n\t\t\t\t6D32CBFCD866586D78A69BE1 /* [CP] Embed Pods Frameworks */,\n\t\t\t\t92FA5F4E31AA12D8C9AA408A /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 97C146EE1CF9000F007C117D /* Runner.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t97C146E61CF9000F007C117D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1510;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t97C146ED1CF9000F007C117D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 97C146E51CF9000F007C117D;\n\t\t\tproductRefGroup = 97C146EF1CF9000F007C117D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t97C146ED1CF9000F007C117D /* Runner */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t97C146EC1CF9000F007C117D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,\n\t\t\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,\n\t\t\t\t97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\",\n\t\t\t);\n\t\t\tname = \"Thin Binary\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" embed_and_thin\";\n\t\t};\n\t\t6D32CBFCD866586D78A69BE1 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t92FA5F4E31AA12D8C9AA408A /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t9740EEB61CF901F6004384FC /* Run Script */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Run Script\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" build\";\n\t\t};\n\t\tEEC3C9B6719E92514BD4D205 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t97C146EA1CF9000F007C117D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,\n\t\t\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t97C146FA1CF9000F007C117D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FB1CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C147001CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t249021D3217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t249021D4217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tDEVELOPMENT_TEAM = 9R87RMF9C9;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.slotsun.slive;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t97C147031CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147041CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t97C147061CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tDEVELOPMENT_TEAM = 9R87RMF9C9;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.slotsun.slive;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147071CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tDEVELOPMENT_TEAM = 9R87RMF9C9;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.slotsun.slive;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147031CF9000F007C117D /* Debug */,\n\t\t\t\t97C147041CF9000F007C117D /* Release */,\n\t\t\t\t249021D3217E4FDB00AE95B9 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147061CF9000F007C117D /* Debug */,\n\t\t\t\t97C147071CF9000F007C117D /* Release */,\n\t\t\t\t249021D4217E4FDB00AE95B9 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 97C146E61CF9000F007C117D /* Project object */;\n}\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1510\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n               BuildableName = \"Runner.app\"\n               BlueprintName = \"Runner\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Runner.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/lib/app/app_style.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:get/get.dart';\n\nclass AppColors {\n  static ColorScheme lightColorScheme = ColorScheme.fromSeed(\n    // primarySwatch: Colors.blue,\n    seedColor: const Color(0xff3498db),\n    brightness: Brightness.light,\n  );\n  static ColorScheme darkColorScheme = ColorScheme.fromSeed(\n    seedColor: const Color(0xff3498db),\n    brightness: Brightness.dark,\n  );\n\n  static const Color black333 = Color(0xFF333333);\n}\n\nclass AppStyle {\n  static ThemeData light({String? fontFamily}) {\n    return ThemeData(\n      colorScheme: AppColors.lightColorScheme,\n      useMaterial3: true,\n      fontFamily: fontFamily,\n      visualDensity: VisualDensity.standard,\n      appBarTheme: AppBarTheme(\n        //elevation: 0,\n        centerTitle: true,\n        titleTextStyle: TextStyle(\n          fontFamily: fontFamily,\n          fontSize: 16,\n          color: AppColors.black333,\n        ),\n        foregroundColor: AppColors.black333,\n        systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(\n          systemNavigationBarColor: Colors.transparent,\n        ),\n      ),\n    );\n  }\n\n  static ThemeData darkTheme({String? fontFamily}) {\n    return ThemeData.dark().copyWith(\n      colorScheme: AppColors.darkColorScheme,\n      visualDensity: VisualDensity.standard,\n      textTheme: ThemeData.dark().textTheme.apply(\n            fontFamily: fontFamily,\n          ),\n      primaryTextTheme: ThemeData().textTheme.apply(\n            fontFamily: fontFamily,\n          ),\n      appBarTheme: AppBarTheme(\n        //elevation: 0,\n\n        centerTitle: true,\n        titleTextStyle: TextStyle(\n          fontFamily: fontFamily,\n          fontSize: 16,\n          color: Colors.white,\n        ),\n        foregroundColor: Colors.white,\n        systemOverlayStyle: SystemUiOverlayStyle.light.copyWith(\n          systemNavigationBarColor: Colors.transparent,\n        ),\n      ),\n      // radioTheme: RadioThemeData(\n      //   fillColor: MaterialStateProperty.all(AppColors.darkColorScheme.primary),\n      // ),\n      // checkboxTheme: CheckboxThemeData(\n      //   fillColor: MaterialStateProperty.all(AppColors.darkColorScheme.primary),\n      // ),\n      // tabBarTheme: TabBarTheme(\n      //   labelColor: AppColors.darkColorScheme.primary,\n      //   unselectedLabelColor: Colors.white70,\n      //   indicator: RectangularIndicator(\n      //     color: Colors.white.withAlpha(50),\n      //     topLeftRadius: 24,\n      //     bottomLeftRadius: 24,\n      //     topRightRadius: 24,\n      //     bottomRightRadius: 24,\n      //     verticalPadding: 8,\n      //     horizontalPadding: 0,\n      //   ),\n      // ),\n    );\n  }\n\n  static const vGap4 = SizedBox(\n    height: 4,\n  );\n  static const vGap8 = SizedBox(\n    height: 8,\n  );\n  static const vGap12 = SizedBox(\n    height: 12,\n  );\n  static const vGap24 = SizedBox(\n    height: 24,\n  );\n  static const vGap32 = SizedBox(\n    height: 32,\n  );\n  static const vGap48 = SizedBox(\n    height: 48,\n  );\n\n  static const hGap4 = SizedBox(\n    width: 4,\n  );\n  static const hGap8 = SizedBox(\n    width: 8,\n  );\n  static const hGap12 = SizedBox(\n    width: 12,\n  );\n  static const hGap16 = SizedBox(\n    width: 16,\n  );\n\n  static const hGap24 = SizedBox(\n    width: 24,\n  );\n  static const hGap32 = SizedBox(\n    width: 32,\n  );\n  static const hGap48 = SizedBox(\n    width: 48,\n  );\n\n  static const edgeInsetsH4 = EdgeInsets.symmetric(horizontal: 4);\n  static const edgeInsetsH8 = EdgeInsets.symmetric(horizontal: 8);\n  static const edgeInsetsH12 = EdgeInsets.symmetric(horizontal: 12);\n  static const edgeInsetsH16 = EdgeInsets.symmetric(horizontal: 16);\n  static const edgeInsetsH20 = EdgeInsets.symmetric(horizontal: 20);\n  static const edgeInsetsH24 = EdgeInsets.symmetric(horizontal: 24);\n\n  static const edgeInsetsV4 = EdgeInsets.symmetric(vertical: 4);\n  static const edgeInsetsV8 = EdgeInsets.symmetric(vertical: 8);\n  static const edgeInsetsV12 = EdgeInsets.symmetric(vertical: 12);\n  static const edgeInsetsV24 = EdgeInsets.symmetric(vertical: 24);\n\n  static const edgeInsetsA4 = EdgeInsets.all(4);\n  static const edgeInsetsA8 = EdgeInsets.all(8);\n  static const edgeInsetsA12 = EdgeInsets.all(12);\n  static const edgeInsetsA16 = EdgeInsets.all(16);\n  static const edgeInsetsA20 = EdgeInsets.all(20);\n  static const edgeInsetsA24 = EdgeInsets.all(24);\n\n  static const edgeInsetsR4 = EdgeInsets.only(right: 4);\n  static const edgeInsetsR8 = EdgeInsets.only(right: 8);\n  static const edgeInsetsR12 = EdgeInsets.only(right: 12);\n  static const edgeInsetsR16 = EdgeInsets.only(right: 16);\n  static const edgeInsetsR20 = EdgeInsets.only(right: 20);\n  static const edgeInsetsR24 = EdgeInsets.only(right: 24);\n\n  static const edgeInsetsL4 = EdgeInsets.only(left: 4);\n  static const edgeInsetsL8 = EdgeInsets.only(left: 8);\n  static const edgeInsetsL12 = EdgeInsets.only(left: 12);\n  static const edgeInsetsL16 = EdgeInsets.only(left: 16);\n  static const edgeInsetsL20 = EdgeInsets.only(left: 20);\n  static const edgeInsetsL24 = EdgeInsets.only(left: 24);\n\n  static const edgeInsetsT4 = EdgeInsets.only(top: 4);\n  static const edgeInsetsT8 = EdgeInsets.only(top: 8);\n  static const edgeInsetsT12 = EdgeInsets.only(top: 12);\n  static const edgeInsetsT24 = EdgeInsets.only(top: 24);\n\n  static const edgeInsetsB4 = EdgeInsets.only(bottom: 4);\n  static const edgeInsetsB8 = EdgeInsets.only(bottom: 8);\n  static const edgeInsetsB12 = EdgeInsets.only(bottom: 12);\n  static const edgeInsetsB24 = EdgeInsets.only(bottom: 24);\n\n  static BorderRadius radius4 = BorderRadius.circular(4);\n  static BorderRadius radius8 = BorderRadius.circular(8);\n  static BorderRadius radius12 = BorderRadius.circular(12);\n  static BorderRadius radius24 = BorderRadius.circular(24);\n  static BorderRadius radius32 = BorderRadius.circular(32);\n  static BorderRadius radius48 = BorderRadius.circular(48);\n\n  /// 顶部状态栏的高度\n  static double get statusBarHeight => MediaQuery.of(Get.context!).padding.top;\n\n  /// 底部导航条的高度\n  static double get bottomBarHeight =>\n      MediaQuery.of(Get.context!).padding.bottom;\n\n  static Divider get divider => Divider(\n        height: 1,\n        thickness: 1,\n        indent: 16,\n        endIndent: 16,\n        color: Colors.grey.withAlpha(25),\n      );\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/constant.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:remixicon/remixicon.dart';\n\nclass Constant {\n  static const String kUpdateFollow = \"UpdateFollow\";\n  static const String kUpdateHistory = \"UpdateHistory\";\n\n  static final Map<String, HomePageItem> allHomePages = {\n    \"recommend\": HomePageItem(\n      iconData: Remix.home_smile_line,\n      title: \"首页\",\n      index: 0,\n    ),\n    \"follow\": HomePageItem(\n      iconData: Remix.heart_line,\n      title: \"关注\",\n      index: 1,\n    ),\n    \"category\": HomePageItem(\n      iconData: Remix.apps_line,\n      title: \"分类\",\n      index: 2,\n    ),\n    \"user\": HomePageItem(\n      iconData: Remix.user_smile_line,\n      title: \"我的\",\n      index: 3,\n    ),\n  };\n\n  static const String kBiliBili = \"bilibili\";\n  static const String kDouyu = \"douyu\";\n  static const String kHuya = \"huya\";\n  static const String kDouyin = \"douyin\";\n  static const String kTwitch = \"twitch\";\n}\n\nclass HomePageItem {\n  final IconData iconData;\n  final String title;\n  final int index;\n  HomePageItem({\n    required this.iconData,\n    required this.title,\n    required this.index,\n  });\n}\n\nenum DownloadState {\n  notDownloaded,\n  downloading,\n  downloaded,\n}\n\n// 排序方法\nenum SortMethod {\n  watchDuration,\n  siteId,\n  recently,\n  userNameASC,\n  userNameDESC,\n}\n\nextension SortMethodStore on SortMethod {\n  String get storeValue => name;\n  static SortMethod fromStore(String? v) {\n    if (v == null) return SortMethod.watchDuration;\n    return SortMethod.values.firstWhere(\n          (e) => e.name == v,\n      orElse: () => SortMethod.watchDuration,\n    );\n  }\n}"
  },
  {
    "path": "simple_live_app/lib/app/controller/app_settings_controller.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\n\nclass AppSettingsController extends GetxController {\n  static AppSettingsController get instance =>\n      Get.find<AppSettingsController>();\n\n  /// 缩放模式\n  var scaleMode = 0.obs;\n\n  var themeMode = 0.obs;\n\n  var firstRun = false;\n\n  var dbVer = 0;\n\n  @override\n  void onInit() {\n    themeMode.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kThemeMode, 0);\n    firstRun = LocalStorageService.instance\n        .getValue(LocalStorageService.kFirstRun, true);\n    danmuSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuSize, 16.0);\n    danmuOpacity.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuOpacity, 1.0);\n    danmuArea.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuArea, 0.8);\n    danmuSpeed.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuSpeed, 10.0);\n    danmuEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuEnable, true);\n    danmakuMaskEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmakuMaskEnable, false);\n    danmuStrokeWidth.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuStrokeWidth, 2.0);\n    danmuTopMargin.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuTopMargin, 0.0);\n    danmuBottomMargin.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuBottomMargin, 0.0);\n    danmuFontWeight.value = LocalStorageService.instance.getValue(\n        LocalStorageService.kDanmuFontWeight, FontWeight.normal.index);\n\n    hardwareDecode.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kHardwareDecode, true);\n    chatTextSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kChatTextSize, 14.0);\n\n    chatTextGap.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kChatTextGap, 4.0);\n\n    chatBubbleStyle.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kChatBubbleStyle,\n      false,\n    );\n\n    qualityLevel.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kQualityLevel, 2);\n    qualityLevelCellular.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kQualityLevelCellular, 1);\n\n    autoExitEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoExitEnable, false);\n\n    autoExitDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoExitDuration, 60);\n\n    roomAutoExitDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kRoomAutoExitDuration, 60);\n\n    playerCompatMode.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerCompatMode, false);\n\n    playerAutoPause.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerAutoPause, false);\n\n    playerForceHttps.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerForceHttps, false);\n\n    douyinHlsFirst.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDouyinHlsFirst, false);\n\n    autoFullScreen.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoFullScreen, false);\n\n    // ignore: invalid_use_of_protected_member\n    shieldList.value = LocalStorageService.instance.shieldBox.values.toSet();\n\n    scaleMode.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kPlayerScaleMode,\n      0,\n    );\n\n    playerVolume.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kPlayerVolume,\n      100.0,\n    );\n    pipHideDanmu.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPIPHideDanmu, true);\n\n\n\n    bilibiliLoginTip.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kBilibiliLoginTip, true);\n\n    playerBufferSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerBufferSize, 32);\n\n    logEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kLogEnable, false);\n    if (logEnable.value) {\n      Log.initWriter();\n    }\n\n    firebaseEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kFirebaseEnable, true);\n\n    customPlayerOutput.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kCustomPlayerOutput, false);\n\n    videoOutputDriver.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kVideoOutputDriver,\n      Platform.isAndroid ? \"mediacodec_embed\" : \"libmpv\",\n    );\n\n    audioOutputDriver.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kAudioOutputDriver,\n      Platform.isAndroid\n          ? \"audiotrack\"\n          : Platform.isLinux\n              ? \"pulse\"\n              : Platform.isWindows\n                  ? \"wasapi\"\n                  : Platform.isIOS\n                      ? \"audiounit\"\n                      : Platform.isMacOS\n                          ? \"coreaudio\"\n                          : \"sdl\",\n    );\n\n    videoHardwareDecoder.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kVideoHardwareDecoder,\n      Platform.isAndroid ? \"mediacodec\" : \"auto\",\n    );\n\n    videoDoubleBuffering.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kVideoDoubleBuffering,\n      false,\n    );\n\n    autoUpdateFollowEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoUpdateFollowEnable, true);\n\n    autoUpdateFollowDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kUpdateFollowDuration, 10);\n\n    updateFollowThreadCount.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kUpdateFollowThreadCount, 4);\n\n    // danmaku-去重参数\n    danmuFrequencyControl.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuFrequencyControl, false);\n\n    danmuMaxFrequency.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuMaxFrequency, 3);\n\n    danmuTextNormalization.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuTextNormalization, true);\n\n    danmuWindowMs.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuWindowMs, 15);\n    dbVer = LocalStorageService.instance\n        .getValue(LocalStorageService.kHiveDbVer, 10708);\n\n    followSortMethod.value = SortMethodStore.fromStore(\n        LocalStorageService.instance.getValue(\n            LocalStorageService.kFollowSortMethod,\n            SortMethod.watchDuration.storeValue));\n\n    followStyleNotGrid.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kFollowStyleNotGrid, true);\n\n    initSiteSort();\n    initHomeSort();\n\n    super.onInit();\n  }\n\n  void initSiteSort() {\n    var sort = LocalStorageService.instance\n        .getValue(\n          LocalStorageService.kSiteSort,\n          Sites.allSites.keys.join(\",\"),\n        )\n        .split(\",\");\n    //如果数量与allSites的数量不一致，将缺失的添加上\n    if (sort.length != Sites.allSites.length) {\n      var keys = Sites.allSites.keys.toList();\n      for (var i = 0; i < keys.length; i++) {\n        if (!sort.contains(keys[i])) {\n          sort.add(keys[i]);\n        }\n      }\n    }\n\n    siteSort.value = sort;\n  }\n\n  void initHomeSort() {\n    var sort = LocalStorageService.instance\n        .getValue(\n          LocalStorageService.kHomeSort,\n          Constant.allHomePages.keys.join(\",\"),\n        )\n        .split(\",\");\n    //如果数量与allSites的数量不一致，将缺失的添加上\n    if (sort.length != Constant.allHomePages.length) {\n      var keys = Constant.allHomePages.keys.toList();\n      for (var i = 0; i < keys.length; i++) {\n        if (!sort.contains(keys[i])) {\n          sort.add(keys[i]);\n        }\n      }\n    }\n\n    homeSort.value = sort;\n  }\n\n  void setNoFirstRun() {\n    LocalStorageService.instance.setValue(LocalStorageService.kFirstRun, false);\n  }\n\n\n\n\n\n  var hardwareDecode = true.obs;\n\n  void setHardwareDecode(bool e) {\n    hardwareDecode.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kHardwareDecode, e);\n  }\n\n  var chatTextSize = 14.0.obs;\n\n  void setChatTextSize(double e) {\n    chatTextSize.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kChatTextSize, e);\n  }\n\n  var chatTextGap = 4.0.obs;\n\n  void setChatTextGap(double e) {\n    chatTextGap.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kChatTextGap, e);\n  }\n\n  var chatBubbleStyle = false.obs;\n\n  void setChatBubbleStyle(bool e) {\n    chatBubbleStyle.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kChatBubbleStyle, e);\n  }\n\n  var danmuSize = 16.0.obs;\n\n  void setDanmuSize(double e) {\n    danmuSize.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuSize, e);\n  }\n\n  var danmuSpeed = 10.0.obs;\n\n  void setDanmuSpeed(double e) {\n    danmuSpeed.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuSpeed, e);\n  }\n\n  var danmuArea = 0.8.obs;\n\n  void setDanmuArea(double e) {\n    danmuArea.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuArea, e);\n  }\n\n  var danmuOpacity = 1.0.obs;\n\n  void setDanmuOpacity(double e) {\n    danmuOpacity.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuOpacity, e);\n  }\n\n  var danmuEnable = true.obs;\n\n  void setDanmuEnable(bool e) {\n    danmuEnable.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuEnable, e);\n  }\n\n  var danmakuMaskEnable = false.obs;\n\n  void setDanmakuMaskEnable(bool e) {\n    danmakuMaskEnable.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmakuMaskEnable, e);\n  }\n\n  var danmuStrokeWidth = 2.0.obs;\n\n  void setDanmuStrokeWidth(double e) {\n    danmuStrokeWidth.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuStrokeWidth, e);\n  }\n\n  var danmuFontWeight = FontWeight.normal.index.obs;\n\n  void setDanmuFontWeight(int e) {\n    danmuFontWeight.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuFontWeight, e);\n  }\n\n  var qualityLevel = 1.obs;\n\n  void setQualityLevel(int level) {\n    qualityLevel.value = level;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kQualityLevel, level);\n  }\n\n  var qualityLevelCellular = 1.obs;\n\n  void setQualityLevelCellular(int level) {\n    qualityLevelCellular.value = level;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kQualityLevelCellular, level);\n  }\n\n  var autoExitEnable = false.obs;\n\n  void setAutoExitEnable(bool e) {\n    autoExitEnable.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoExitEnable, e);\n  }\n\n  var autoExitDuration = 60.obs;\n\n  void setAutoExitDuration(int e) {\n    autoExitDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoExitDuration, e);\n  }\n\n  var roomAutoExitDuration = 60.obs;\n\n  void setRoomAutoExitDuration(int e) {\n    roomAutoExitDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kRoomAutoExitDuration, e);\n  }\n\n  var playerCompatMode = false.obs;\n\n  void setPlayerCompatMode(bool e) {\n    playerCompatMode.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerCompatMode, e);\n  }\n\n  var playerBufferSize = 32.obs;\n\n  void setPlayerBufferSize(int e) {\n    playerBufferSize.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerBufferSize, e);\n  }\n\n  var playerAutoPause = false.obs;\n\n  void setPlayerAutoPause(bool e) {\n    playerAutoPause.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerAutoPause, e);\n  }\n\n  var autoFullScreen = false.obs;\n\n  void setAutoFullScreen(bool e) {\n    autoFullScreen.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoFullScreen, e);\n  }\n\n  RxSet<String> shieldList = <String>{}.obs;\n\n  void addShieldList(String e) {\n    shieldList.add(e);\n    LocalStorageService.instance.shieldBox.put(e, e);\n  }\n\n  void removeShieldList(String e) {\n    shieldList.remove(e);\n    LocalStorageService.instance.shieldBox.delete(e);\n  }\n\n  Future clearShieldList() async {\n    shieldList.clear();\n    await LocalStorageService.instance.shieldBox.clear();\n  }\n\n  void setScaleMode(int value) {\n    scaleMode.value = value;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kPlayerScaleMode,\n      value,\n    );\n  }\n\n  RxList<String> siteSort = RxList<String>();\n\n  void setSiteSort(List<String> e) {\n    siteSort.value = e;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kSiteSort,\n      siteSort.join(\",\"),\n    );\n  }\n\n  RxList<String> homeSort = RxList<String>();\n\n  void setHomeSort(List<String> e) {\n    homeSort.value = e;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kHomeSort,\n      homeSort.join(\",\"),\n    );\n  }\n\n  Rx<double> playerVolume = 100.0.obs;\n\n  void setPlayerVolume(double value) {\n    playerVolume.value = value;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kPlayerVolume,\n      value,\n    );\n  }\n\n  var pipHideDanmu = true.obs;\n\n  void setPIPHideDanmu(bool e) {\n    pipHideDanmu.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kPIPHideDanmu, e);\n  }\n\n  var danmuTopMargin = 0.0.obs;\n\n  void setDanmuTopMargin(double e) {\n    danmuTopMargin.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuTopMargin, e);\n  }\n\n  var danmuBottomMargin = 0.0.obs;\n\n  void setDanmuBottomMargin(double e) {\n    danmuBottomMargin.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuBottomMargin, e);\n  }\n\n  /// 弹幕去重参数设置\n  var danmuTextNormalization = true.obs;\n\n  void setDanmuTextNormalization(bool e) {\n    danmuTextNormalization.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuTextNormalization, e);\n  }\n\n  var danmuMaxFrequency = 3.obs;\n\n  void setDanmuMaxFrequency(int e) {\n    danmuMaxFrequency.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuMaxFrequency, e);\n  }\n\n  var danmuFrequencyControl = true.obs;\n\n  void setDanmuFrequencyControl(bool e) {\n    danmuFrequencyControl.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuFrequencyControl, e);\n  }\n\n  var danmuWindowMs = 15.obs;\n\n  void setDanmuWindowMs(int e) {\n    danmuWindowMs.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuWindowMs, e);\n  }\n\n  var bilibiliLoginTip = true.obs;\n\n  void setBiliBiliLoginTip(bool e) {\n    bilibiliLoginTip.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliLoginTip, e);\n  }\n\n  var logEnable = false.obs;\n\n  void setLogEnable(bool e) {\n    logEnable.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kLogEnable, e);\n  }\n\n  var firebaseEnable = true.obs;\n\n  void setFirebaseEnable(bool e) {\n    firebaseEnable.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kFirebaseEnable, e);\n  }\n\n  var customPlayerOutput = false.obs;\n\n  void setCustomPlayerOutput(bool e) {\n    customPlayerOutput.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kCustomPlayerOutput, e);\n  }\n\n  var videoOutputDriver = \"\".obs;\n\n  void setVideoOutputDriver(String e) {\n    videoOutputDriver.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kVideoOutputDriver, e);\n  }\n\n  var audioOutputDriver = \"\".obs;\n\n  void setAudioOutputDriver(String e) {\n    audioOutputDriver.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAudioOutputDriver, e);\n  }\n\n  var videoHardwareDecoder = \"\".obs;\n\n  void setVideoHardwareDecoder(String e) {\n    videoHardwareDecoder.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kVideoHardwareDecoder, e);\n  }\n\n  var videoDoubleBuffering = false.obs;\n\n  void setVideoDoubleBuffering(bool e) {\n    videoDoubleBuffering.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kVideoDoubleBuffering, e);\n  }\n\n  var autoUpdateFollowEnable = false.obs;\n\n  void setAutoUpdateFollowEnable(bool e) {\n    autoUpdateFollowEnable.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoUpdateFollowEnable, e);\n  }\n\n  var autoUpdateFollowDuration = 10.obs;\n\n  void setAutoUpdateFollowDuration(int e) {\n    autoUpdateFollowDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kUpdateFollowDuration, e);\n  }\n\n  var updateFollowThreadCount = 4.obs;\n\n  void setUpdateFollowThreadCount(int e) {\n    updateFollowThreadCount.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kUpdateFollowThreadCount, e);\n  }\n\n  var playerForceHttps = false.obs;\n\n  void setPlayerForceHttps(bool e) {\n    playerForceHttps.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerForceHttps, e);\n  }\n\n  var douyinHlsFirst = false.obs;\n\n  void setDouyinHlsFirst(bool e) {\n    douyinHlsFirst.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDouyinHlsFirst, e);\n  }\n\n  var followSortMethod = SortMethod.watchDuration.obs;\n\n  void setFollowSortMethod(SortMethod e) {\n    followSortMethod.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kFollowSortMethod, e.storeValue);\n  }\n  // 关注样式是否卡片化\n  var followStyleNotGrid = true.obs;\n\n  void setFollowStyleNotGrid(bool e){\n    followStyleNotGrid.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kFollowStyleNotGrid, e);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/controller/base_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/widgets.dart';\n\nimport 'package:simple_live_app/app/log.dart';\n\nimport 'package:flutter_easyrefresh/easy_refresh.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\n\nclass BaseController extends GetxController {\n  /// 加载中，更新页面\n  var pageLoadding = false.obs;\n\n  /// 加载中,不会更新页面\n  var loadding = false;\n\n  /// 空白页面\n  var pageEmpty = false.obs;\n\n  /// 页面错误\n  var pageError = false.obs;\n\n  /// 未登录\n  var notLogin = false.obs;\n\n  /// 错误信息\n  var errorMsg = \"\".obs;\n\n  /// 显示错误\n  /// * [msg] 错误信息\n  /// * [showPageError] 显示页面错误\n  /// * 只在第一页加载错误时showPageError=true，后续页加载错误时使用Toast弹出通知\n  void handleError(Object exception, {bool showPageError = false}) {\n    Log.e(exception.toString(), StackTrace.current);\n    var msg = exceptionToString(exception);\n\n    if (showPageError) {\n      pageError.value = true;\n      errorMsg.value = msg;\n    } else {\n      SmartDialog.showToast(exceptionToString(msg));\n    }\n  }\n\n  String exceptionToString(Object exception) {\n    return exception.toString().replaceAll(\"Exception:\", \"\");\n  }\n\n  void onLogin() {}\n  void onLogout() {}\n}\n\nclass BasePageController<T> extends BaseController {\n  final ScrollController scrollController = ScrollController();\n  final EasyRefreshController easyRefreshController = EasyRefreshController();\n  int currentPage = 1;\n  int count = 0;\n  int maxPage = 0;\n  int pageSize = 24;\n  var canLoadMore = false.obs;\n  var list = <T>[].obs;\n\n  Future refreshData() async {\n    currentPage = 1;\n    list.value = [];\n    await loadData();\n  }\n\n  Future loadData() async {\n    try {\n      if (loadding) return;\n      loadding = true;\n      pageError.value = false;\n      pageEmpty.value = false;\n      notLogin.value = false;\n      pageLoadding.value = currentPage == 1;\n\n      var result = await getData(currentPage, pageSize);\n      //是否可以加载更多\n      if (result.isNotEmpty) {\n        currentPage++;\n        canLoadMore.value = true;\n        pageEmpty.value = false;\n      } else {\n        canLoadMore.value = false;\n        if (currentPage == 1) {\n          pageEmpty.value = true;\n        }\n      }\n      // 赋值数据\n      if (currentPage == 1) {\n        list.value = result;\n      } else {\n        list.addAll(result);\n      }\n    } catch (e) {\n      handleError(e, showPageError: currentPage == 1);\n    } finally {\n      loadding = false;\n      pageLoadding.value = false;\n    }\n  }\n\n  Future<List<T>> getData(int page, int pageSize) async {\n    return [];\n  }\n\n  void scrollToTopOrRefresh() {\n    if (scrollController.offset > 0) {\n      scrollController.animateTo(\n        0,\n        duration: const Duration(milliseconds: 200),\n        curve: Curves.linear,\n      );\n    } else {\n      easyRefreshController.callRefresh();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/custom_throttle.dart",
    "content": "/// 这个类的目的是简化 throttle 的操作，以便更好的理解代码\n/// 主要作用：节流，如果在很短时间内都会调用同一个方法，除了第一个方法有用以外\n/// 剩下的方法将会被舍弃，在 [eachDelayMilli] 时间后，才会允许下一次调用\n/// 会保存一个方法，在最后还会调用一次，和普通的 throttle 不太一样\nclass DelayedThrottle {\n  bool isInvoking = false;\n  int eachDelayMilli;\n  Future Function()? storeFunc;\n\n  DelayedThrottle(this.eachDelayMilli);\n\n  void invoke(Future Function() longCostFunc) {\n    if (isInvoking) {\n      storeFunc = longCostFunc;\n      return;\n    }\n    storeFunc = null;\n    isInvoking = true;\n    longCostFunc().then((value) {\n      Future.delayed(Duration(milliseconds: eachDelayMilli), () {\n        isInvoking = false;\n        if (storeFunc != null) {\n          invoke(storeFunc!);\n        }\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/event_bus.dart",
    "content": "import 'dart:async';\n\nimport 'package:simple_live_app/app/log.dart';\n\n/// 全局事件\nclass EventBus {\n  /// 点击了底部导航\n  static const String kBottomNavigationBarClicked =\n      \"BottomNavigationBarClicked\";\n\n  /// 用户按了Esc\n  static const String kEscapePressed = \"EscapePressed\";\n  static EventBus? _instance;\n\n  static EventBus get instance {\n    _instance ??= EventBus();\n    return _instance!;\n  }\n\n  final Map<String, StreamController> _streams = {};\n\n  /// 触发事件\n  void emit<T>(String name, T data) {\n    if (!_streams.containsKey(name)) {\n      _streams.addAll({name: StreamController.broadcast()});\n    }\n    Log.d(\"Emit Event：$name\\r\\n$data\");\n\n    _streams[name]!.add(data);\n  }\n\n  /// 监听事件\n  StreamSubscription<dynamic> listen(String name, Function(dynamic)? onData) {\n    if (!_streams.containsKey(name)) {\n      _streams.addAll({name: StreamController.broadcast()});\n    }\n    return _streams[name]!.stream.listen(onData);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/log.dart",
    "content": "import 'dart:io';\n\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:intl/intl.dart';\nimport 'package:logger/logger.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/utils.dart';\n\nclass Log {\n  static LogFileWriter? logFileWriter;\n  static void initWriter() {\n    logFileWriter = LogFileWriter();\n  }\n\n  static void disposeWriter() {\n    logFileWriter?.close();\n    logFileWriter = null;\n  }\n\n  static void writeLog(Object content, [Level level = Level.info]) {\n    logFileWriter\n        ?.write(\"[${level.name.toUpperCase()}] $_currentTime：$content\");\n  }\n\n  static RxList<DebugLogModel> debugLogs = <DebugLogModel>[].obs;\n\n  static void addDebugLog(String content, Color? color) {\n    if (kReleaseMode) {\n      return;\n    }\n    if (content.contains(\"请求响应\")) {\n      content = content.split(\"\\n\").join('\\n💡 ');\n    }\n    try {\n      debugLogs.insert(0, DebugLogModel(DateTime.now(), content, color: color));\n    } catch (e) {\n      if (kDebugMode) {\n        print(e);\n      }\n    }\n  }\n\n  static Logger logger = Logger(\n    printer: PrettyPrinter(\n      methodCount: 0,\n      errorMethodCount: 8,\n      lineLength: 120,\n      colors: true,\n      printEmojis: true,\n      dateTimeFormat: DateTimeFormat.none,\n    ),\n  );\n\n  static void d(String message, [bool writeFile = true]) {\n    addDebugLog(message, Colors.orange);\n    logger.d(\"${DateTime.now().toString()}\\n$message\");\n    if (writeFile) {\n      writeLog(message, Level.debug);\n    }\n  }\n\n  static void i(String message, [bool writeFile = true]) {\n    addDebugLog(message, Colors.blue);\n    logger.i(\"${DateTime.now().toString()}\\n$message\");\n    if (writeFile) {\n      logFileWriter?.write(\"[INFO] $_currentTime：$message\");\n      writeLog(message, Level.info);\n    }\n  }\n\n  static void e(String message, StackTrace stackTrace,\n      [bool writeFile = true]) {\n    addDebugLog('$message\\r\\n\\r\\n$stackTrace', Colors.red);\n    logger.e(\"${DateTime.now().toString()}\\n$message\", stackTrace: stackTrace);\n    if (writeFile) {\n      writeLog(\"$message\\n$stackTrace\", Level.error);\n    }\n  }\n\n  static void w(String message, [bool writeFile = true]) {\n    addDebugLog(message, Colors.pink);\n    logger.w(\"${DateTime.now().toString()}\\n$message\");\n    if (writeFile) {\n      writeLog(message, Level.warning);\n    }\n  }\n\n  static void logPrint(dynamic obj, [bool writeFile = true]) {\n    addDebugLog(obj.toString(), Colors.red);\n    if (writeFile) {\n      writeLog(obj, Level.info);\n    }\n    //logger.e(obj.toString(), obj, obj?.stackTrace);\n    if (kDebugMode) {\n      print(obj);\n    }\n  }\n\n  static String get _currentTime => Utils.timeFormat.format(DateTime.now());\n}\n\nclass LogFileWriter {\n  late String fileName;\n  LogFileWriter() {\n    var dt = DateFormat(\"yyyy-MM-dd HH-mm-ss\").format(DateTime.now());\n    fileName = \"$dt.log\";\n    initFile();\n  }\n  IOSink? fileWriter;\n  void initFile() async {\n    var supportDir = await getApplicationSupportDirectory();\n    var logDir = Directory(\"${supportDir.path}/log\");\n    if (!await logDir.exists()) {\n      await logDir.create();\n    }\n    var logFile = File(\"${logDir.path}/$fileName\");\n    fileWriter = logFile.openWrite(mode: FileMode.append);\n    writeSystemInfo();\n  }\n\n  void write(String content) {\n    fileWriter?.write(content);\n    fileWriter?.write(\"\\r\\n\");\n  }\n\n  Future close() async {\n    await fileWriter?.close();\n  }\n\n  void writeSystemInfo() async {\n    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n    write(\"System Info:\");\n    write(\"Current Time: ${DateTime.now()}\");\n    write(\"Platform: ${Platform.operatingSystem}\");\n    write(\"Version: ${Platform.operatingSystemVersion}\");\n    write(\"Local: ${Platform.localeName}\");\n    write(\n        \"App Version: ${Utils.packageInfo.version}+${Utils.packageInfo.buildNumber}\");\n    if (Platform.isAndroid) {\n      write((await deviceInfo.androidInfo).data.toString());\n    } else if (Platform.isIOS) {\n      write((await deviceInfo.iosInfo).data.toString());\n    } else if (Platform.isLinux) {\n      write((await deviceInfo.linuxInfo).data.toString());\n    } else if (Platform.isMacOS) {\n      write((await deviceInfo.macOsInfo).data.toString());\n    } else if (Platform.isWindows) {\n      write((await deviceInfo.windowsInfo).data.toString());\n    }\n    write(\"End System Info\");\n  }\n}\n\nclass DebugLogModel {\n  final String content;\n  final DateTime datetime;\n  final Color? color;\n  DebugLogModel(this.datetime, this.content, {this.color});\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/sites.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/icons/live_icons.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass Sites {\n  static final Map<String, Site> allSites = {\n    Constant.kBiliBili: Site(\n      id: Constant.kBiliBili,\n      iconData: RemixIcons.bilibili_line,\n      logo: \"assets/images/bilibili_2.png\",\n      name: \"哔哩哔哩\",\n      liveSite: BiliBiliSite(),\n    ),\n    Constant.kDouyu: Site(\n      id: Constant.kDouyu,\n      iconData: LiveIcons.douyu,\n      logo: \"assets/images/douyu.png\",\n      name: \"斗鱼直播\",\n      liveSite: DouyuSite(),\n    ),\n    Constant.kHuya: Site(\n      id: Constant.kHuya,\n      iconData: LiveIcons.huya,\n      logo: \"assets/images/huya.png\",\n      name: \"虎牙直播\",\n      liveSite: HuyaSite(),\n    ),\n    Constant.kDouyin: Site(\n      id: Constant.kDouyin,\n      iconData: RemixIcons.tiktok_line,\n      logo: \"assets/images/douyin.png\",\n      name: \"抖音直播\",\n      liveSite: DouyinSite(),\n    ),\n    Constant.kTwitch: Site(\n      id: Constant.kTwitch,\n      iconData: RemixIcons.twitch_line,\n      logo: \"assets/images/Twitch.png\",\n      name: \"Twitch\",\n      liveSite: TwitchSite(),\n    )\n  };\n\n  static List<Site> get supportSites {\n    return AppSettingsController.instance.siteSort\n        .where((key) => Sites.allSites[key]?.name != 'Twitch')\n        .map((key) => allSites[key]!)\n        .toList();\n  }\n}\n\nclass Site {\n  final String id;\n  final String name;\n  final String logo;\n  final IconData iconData;\n  final LiveSite liveSite;\n\n  Site({\n    required this.id,\n    required this.liveSite,\n    required this.logo,\n    required this.name,\n    required this.iconData,\n  });\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/archive.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\nimport 'package:archive/archive_io.dart';\nimport 'package:path/path.dart';\n\nextension ArchiveExt on Archive {\n  void addDirectoryToArchive(String dirPath, String parentPath) {\n    final dir = Directory(dirPath);\n    final entities = dir.listSync(recursive: false);\n    for (final entity in entities) {\n      final relativePath = relative(entity.path, from: parentPath);\n      if (entity is File) {\n        final data = entity.readAsBytesSync();\n        final archiveFile = ArchiveFile(relativePath, data.length, data);\n        addFile(archiveFile);\n      } else if (entity is Directory) {\n        addDirectoryToArchive(entity.path, parentPath);\n      }\n    }\n  }\n\n  void add<T>(String name, T raw) {\n    final data = json.encode(raw);\n    addFile(\n      // 这样会出现问题 不清楚原因\n      ArchiveFile(name, data.length, utf8.encode(data)),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/document.dart",
    "content": "import 'dart:io';\n\nimport 'package:simple_live_app/app/log.dart';\n\n// 扩展 Directory 类，添加清空文件夹的功能并验证是否为文件夹\nextension DirectoryCleaner on Directory {\n  Future<void> clear() async {\n    // 首先判断是否为文件夹\n    if (await exists() && await FileSystemEntity.isDirectory(path)) {\n      // 列出文件夹中的所有文件和子文件夹\n      List<FileSystemEntity> files = listSync();\n\n      // 遍历文件列表并删除每个文件或子文件夹\n      for (FileSystemEntity file in files) {\n        if (file is File) {\n          await file.delete();\n          Log.i('删除文件: ${file.path}');\n        } else if (file is Directory) {\n          await Directory(file.path).delete(recursive: true);\n          Log.i('删除文件夹: ${file.path}');\n        }\n      }\n\n      Log.i('文件夹清空完成');\n    } else {\n      Log.i('$path 不是一个有效的文件夹');\n    }\n  }\n\n  // 阻塞主线程\n  void clearSync() {\n    if (existsSync() && FileSystemEntity.isDirectorySync(path)) {\n      List<FileSystemEntity> files = listSync();\n      for (FileSystemEntity file in files) {\n        if (file is File) {\n          file.deleteSync();\n          Log.i('删除文件: ${file.path}');\n        } else if (file is Directory) {\n          Directory(file.path).deleteSync(recursive: true);\n          Log.i('删除文件夹: ${file.path}');\n        }\n      }\n\n      Log.i('文件夹清空完成');\n    } else {\n      Log.i('$path 不是一个有效的文件夹');\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/duration_2_str_utils.dart",
    "content": "extension DurationStringExtensions on String {\n  /// 将 \"HH:MM:SS\" 格式的字符串转换为 Duration\n  Duration toDuration() {\n    final parts = split(':');\n    if (parts.length != 3) {\n      throw FormatException('Invalid duration format: $this');\n    }\n\n    final hours = int.tryParse(parts[0]) ?? 0;\n    final minutes = int.tryParse(parts[1]) ?? 0;\n    final seconds = int.tryParse(parts[2]) ?? 0;\n\n    return Duration(hours: hours, minutes: minutes, seconds: seconds);\n  }\n}\n\nextension DurationExtensions on Duration {\n  /// 将 Duration 转换为紧凑格式的字符串（如 \"2h30m15s\"）\n  String toHMSString() {\n    final hours = inHours; // 计算总小时数\n    final minutes = inMinutes.remainder(60); // 计算剩余分钟数\n    final seconds = inSeconds.remainder(60); // 计算剩余秒数\n\n    // 格式化分钟和秒为两位数\n    final minutesStr = minutes.toString().padLeft(2, '0');\n    final secondsStr = seconds.toString().padLeft(2, '0');\n\n    return '$hours:$minutesStr:$secondsStr';\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/dynamic_filter.dart",
    "content": "import 'package:simple_live_app/app/log.dart';\n\n// 定义筛选条件之间的逻辑关系\nenum LogicalOperator { and, or }\n\n// 定义支持的筛选比较运算符\nenum FilterOperator {\n  equals, // ==\n  notEquals, // !=\n  greaterThan, // >\n  lessThan, // <\n  greaterThanOrEqual, // >=\n  lessThanOrEqual, // <=\n  contains, // 包含（用于List或String）\n}\n\n/// 表示一个单独的筛选条件。\nclass Condition {\n  final String field;\n  final FilterOperator operator;\n  final dynamic value;\n\n  /// (可选) 字段转换器\n  ///\n  /// 字段转换器在比较前将数据项中的原始值转换为一个`Comparable`类型。\n  /// 目的对historyModel数据以非标准格式（时长字符串 \"HH:MM:SS\"）存储。\n  ///\n  /// 该函数接收来自数据项的原始值，通过转换器返回一个`Comparable`对象\n  /// (例如, `Duration`, `int`, `DateTime`)。\n  /// 此`Condition`的`value`字段应为相同`Comparable`类型。\n  final Comparable? Function(dynamic rawValue)? comparableValueProvider;\n\n  Condition(\n    this.field,\n    this.operator,\n    this.value, {\n    this.comparableValueProvider,\n  });\n}\n\n/// 接口:标记可以被转换为Map的对象。\n/// 数据模型类应该实现这个接口\nabstract class Mappable {\n  /// 将对象转换为Map<String, dynamic>。\n  Map<String, dynamic> toMap();\n}\n\n/// (可选) 高级接口用于让模型类自定义实现筛选逻辑。\n///\n/// 模型实现了这个接口，`dynamicFilter` 将会调用其 `evaluate` 方法来判断条件，\n/// 用于实现最高效或最特殊的比较逻辑。\nabstract class Filterable {\n  /// 模型自己判断是否满足某个条件。\n  /// 返回 `true` 表示满足，`false` 表示不满足。\n  bool evaluate(Condition condition);\n}\n\n/// 一个用于动态多条件过滤列表的工具。\n///\n/// 根据一组动态条件过滤一个 `Mappable` 对象列表。\n///\n/// 此函数采用“渐进式增强”的设计：\n/// - 对于简单的模型（只实现 `Mappable`），它会自动通过 `toMap()` 进行筛选。\n/// - 对于复杂的模型（额外实现了 `Filterable`），它会将筛选逻辑的控制权完全交给模型自身的 `evaluate()` 方法。\n///\n/// [T]: 必须是实现了 `Mappable` 接口的类型。\n/// [list]: 要过滤的对象列表。\n/// [conditions]: `Condition` 对象列表，定义了过滤规则。\n/// [logic]: 条件间的逻辑关系 (`and` 或 `or`)。\n/// [takeLast]: (可选) 从结果中获取最后N个元素。\n///\n/// 返回一个 `List<T>`，其中包含通过所有筛选条件的原始对象。\nList<T> dynamicFilter<T extends Mappable>(\n  List<T> list,\n  List<Condition> conditions, {\n  LogicalOperator logic = LogicalOperator.and,\n  int? takeLast = 15,\n}) {\n  // 1. 内容筛选\n  var filteredList = list.where((item) {\n    if (conditions.isEmpty) {\n      return true;\n    }\n\n    bool check(Condition c) {\n      if (item is Filterable) {\n        return (item as Filterable).evaluate(c);\n      } else {\n        // 使用默认逻辑\n        late final Map<String, dynamic> itemMap;\n        try {\n          itemMap = item.toMap();\n        } catch (e, s) {\n          Log.e(\n              \"Filter:Failed to convert item to map for default filtering.\", s);\n          return false;\n        }\n        return checkConditionOnMap(itemMap, c);\n      }\n    }\n\n    if (logic == LogicalOperator.and) {\n      return conditions.every(check);\n    } else {\n      return conditions.any(check);\n    }\n  }).toList();\n\n  // 2. 位置筛选\n  if (takeLast != null && takeLast > 0) {\n    if (takeLast >= filteredList.length) {\n      return filteredList;\n    }\n    return filteredList.sublist(filteredList.length - takeLast);\n  }\n\n  return filteredList;\n}\n\n/// 默认的、基于Map的条件检查逻辑。\n/// 当一个对象没有实现`Filterable`接口时，`dynamicFilter`会调用此函数。\nbool checkConditionOnMap(Map<String, dynamic> itemMap, Condition condition) {\n  if (!itemMap.containsKey(condition.field)) {\n    return true;\n  }\n\n  final itemValue = itemMap[condition.field];\n  final operand = condition.value;\n\n  // 统一处理需要转换的场景\n  final dynamic transformedItemValue;\n  if (condition.comparableValueProvider != null) {\n    transformedItemValue = condition.comparableValueProvider!(itemValue);\n  } else {\n    transformedItemValue = itemValue;\n  }\n\n  switch (condition.operator) {\n    case FilterOperator.equals:\n      return transformedItemValue == operand;\n    case FilterOperator.notEquals:\n      return transformedItemValue != operand;\n\n    case FilterOperator.greaterThan:\n    case FilterOperator.lessThan:\n    case FilterOperator.greaterThanOrEqual:\n    case FilterOperator.lessThanOrEqual:\n      {\n        if (transformedItemValue == null ||\n            !_isComparable(transformedItemValue, operand)) {\n          return false;\n        }\n        final comparison =\n            (transformedItemValue as Comparable).compareTo(operand);\n\n        if (condition.operator == FilterOperator.greaterThan) {\n          return comparison > 0;\n        }\n        if (condition.operator == FilterOperator.lessThan) {\n          return comparison < 0;\n        }\n        if (condition.operator == FilterOperator.greaterThanOrEqual) {\n          return comparison >= 0;\n        }\n        if (condition.operator == FilterOperator.lessThanOrEqual) {\n          return comparison <= 0;\n        }\n        return false;\n      }\n\n    case FilterOperator.contains:\n      // 'contains' 通常不适用于自定义转换，它在原始值上操作\n      if (itemValue is List) return itemValue.contains(operand);\n      if (itemValue is String && operand is String) {\n        return itemValue.contains(operand);\n      }\n      return false;\n  }\n}\n\n/// 辅助函数，检查两个值是否是可比较的相同类型。\nbool _isComparable(dynamic a, dynamic b) {\n  return a is Comparable && b is Comparable && a.runtimeType == b.runtimeType;\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/dynamic_sort.dart",
    "content": "﻿import 'package:simple_live_app/app/utils/dynamic_filter.dart';\n/// 排序条件\nclass SortCondition<T> {\n  final Comparable Function(T item) valueGetter;\n  final bool ascending;\n\n  SortCondition({\n    required this.valueGetter,\n    this.ascending = true,\n  });\n}\n\nextension MappableListExtension<T extends Mappable> on List<T> {\n  /// 动态排序函数\n  List<T> dynamicSort(List<SortCondition<T>> sortConditions) {\n    sort(\n      (a, b) {\n        for (final cond in sortConditions) {\n          final aValue = cond.valueGetter(a);\n          final bValue = cond.valueGetter(b);\n\n          final cmp = aValue.compareTo(bValue);\n          if (cmp != 0) return cond.ascending ? cmp : -cmp;\n        }\n        return 0;\n      },\n    );\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/listen_fourth_button.dart",
    "content": "import 'package:flutter/gestures.dart';\n\n/// 鼠标侧键点击手势识别器\n/// - https://github.com/flutter/flutter/issues/115641\n/// - https://github.com/witnet/my-wit-wallet/pull/261\nclass FourthButtonTapGestureRecognizer extends BaseTapGestureRecognizer {\n  GestureTapDownCallback? onTapDown;\n\n  @override\n  void handleTapDown({required PointerDownEvent down}) {\n    final TapDownDetails details = TapDownDetails(\n      globalPosition: down.position,\n      localPosition: down.localPosition,\n      kind: getKindForPointer(down.pointer),\n    );\n    switch (down.buttons) {\n      case 8:\n        if (onTapDown != null) {\n          invokeCallback<void>('onTapDown', () => onTapDown!(details));\n        }\n        break;\n      default:\n    }\n  }\n\n  @override\n  void handleTapCancel(\n      {required PointerDownEvent down,\n      PointerCancelEvent? cancel,\n      required String reason}) {}\n\n  @override\n  void handleTapUp(\n      {required PointerDownEvent down, required PointerUpEvent up}) {}\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/permission_handler.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';\n\nexport 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart'\n    show\n        Permission,\n        PermissionStatus,\n        PermissionStatusGetters,\n        PermissionWithService,\n        FuturePermissionStatusGetters,\n        ServiceStatus,\n        ServiceStatusGetters,\n        FutureServiceStatusGetters;\n\nPermissionHandlerPlatform get _handler => PermissionHandlerPlatform.instance;\n\n/// Opens the app settings page.\n///\n/// Returns [true] if the app settings page could be opened, otherwise [false].\nFuture<bool> openAppSettings() => _handler.openAppSettings();\n\n/// Actions that can be executed on a permission.\nextension PermissionActions on Permission {\n  /// Callback for when permission is denied.\n  static FutureOr<void>? Function()? _onDenied;\n\n  /// Callback for when permission is granted.\n  static FutureOr<void>? Function()? _onGranted;\n\n  /// Callback for when permission is permanently denied.\n  static FutureOr<void>? Function()? _onPermanentlyDenied;\n\n  /// Callback for when permission is restricted.\n  static FutureOr<void>? Function()? _onRestricted;\n\n  /// Callback for when permission is limited.\n  static FutureOr<void>? Function()? _onLimited;\n\n  /// Callback for when permission is Provisional.\n  static FutureOr<void>? Function()? _onProvisional;\n\n  /// Method to set a callback for when permission is denied.\n  Permission onDeniedCallback(FutureOr<void>? Function()? callback) {\n    _onDenied = callback;\n    return this;\n  }\n\n  /// Method to set a callback for when permission is granted.\n  Permission onGrantedCallback(FutureOr<void>? Function()? callback) {\n    _onGranted = callback;\n    return this;\n  }\n\n  /// Method to set a callback for when permission is permanently denied.\n  Permission onPermanentlyDeniedCallback(FutureOr<void>? Function()? callback) {\n    _onPermanentlyDenied = callback;\n    return this;\n  }\n\n  /// Method to set a callback for when permission is restricted.\n  Permission onRestrictedCallback(FutureOr<void>? Function()? callback) {\n    _onRestricted = callback;\n    return this;\n  }\n\n  /// Method to set a callback for when permission is limited.\n  Permission onLimitedCallback(FutureOr<void>? Function()? callback) {\n    _onLimited = callback;\n    return this;\n  }\n\n  /// Method to set a callback for when permission is provisional.\n  Permission onProvisionalCallback(FutureOr<void>? Function()? callback) {\n    _onProvisional = callback;\n    return this;\n  }\n\n  /// Checks the current status of the given [Permission].\n  ///\n  /// Notes about specific permissions:\n  /// - **[Permission.bluetooth]**\n  ///   - iOS 13.0 only:\n  ///     - The method will **always** return [PermissionStatus.denied],\n  ///       regardless of the actual status. For the actual permission state,\n  ///       use [Permission.bluetooth.request]. Note that this will show a\n  ///       permission dialog if the permission was not yet requested.\n  Future<PermissionStatus> get status => _handler.checkPermissionStatus(this);\n\n  /// If you should show a rationale for requesting permission.\n  ///\n  /// This is only implemented on Android, calling this on iOS always returns\n  /// [false].\n  Future<bool> get shouldShowRequestRationale async {\n    if (defaultTargetPlatform != TargetPlatform.android) {\n      return false;\n    }\n\n    return _handler.shouldShowRequestPermissionRationale(this);\n  }\n\n  /// Request the user for access to this [Permission], if access hasn't already\n  /// been grant access before.\n  ///\n  /// Returns the new [PermissionStatus].\n  Future<PermissionStatus> request() async {\n    final permissionStatus =\n        (await [this].request())[this] ?? PermissionStatus.denied;\n\n    if (permissionStatus.isDenied) {\n      _onDenied?.call();\n    } else if (permissionStatus.isGranted) {\n      _onGranted?.call();\n    } else if (permissionStatus.isPermanentlyDenied) {\n      _onPermanentlyDenied?.call();\n    } else if (permissionStatus.isRestricted) {\n      _onRestricted?.call();\n    } else if (permissionStatus.isLimited) {\n      _onLimited?.call();\n    } else if (permissionStatus.isProvisional) {\n      _onProvisional?.call();\n    }\n\n    return permissionStatus;\n  }\n}\n\n/// Shortcuts for checking the [status] of a [Permission].\nextension PermissionCheckShortcuts on Permission {\n  /// If the user granted this permission.\n  Future<bool> get isGranted => status.isGranted;\n\n  /// If the user denied this permission.\n  Future<bool> get isDenied => status.isDenied;\n\n  /// If the OS denied this permission. The user cannot change the status,\n  /// possibly due to active restrictions such as parental controls being in\n  /// place.\n  /// *Only supported on iOS.*\n  Future<bool> get isRestricted => status.isRestricted;\n\n  /// User has authorized this application for limited access.\n  /// *Only supported on iOS.(iOS14+ for photos, ios18+ for contacts)*\n  Future<bool> get isLimited => status.isLimited;\n\n  /// Returns `true` when permissions are denied permanently.\n  ///\n  /// When permissions are denied permanently, no new permission dialog will\n  /// be showed to the user. Consuming Apps should redirect the user to the\n  /// App settings to change permissions.\n  Future<bool> get isPermanentlyDenied => status.isPermanentlyDenied;\n\n  /// If the application is provisionally authorized to post noninterruptive user notifications.\n  /// *Only supported on iOS.*\n  Future<bool> get isProvisional => status.isProvisional;\n}\n\n/// Actions that apply only to permissions that have an associated service.\nextension ServicePermissionActions on PermissionWithService {\n  /// Checks the current status of the service associated with the given\n  /// [Permission].\n  ///\n  /// Notes about specific permissions:\n  /// - **[Permission.phone]**\n  ///   - Android:\n  ///     - The method will return [ServiceStatus.notApplicable] when:\n  ///       - the device lacks the TELEPHONY feature\n  ///       - TelephonyManager.getPhoneType() returns PHONE_TYPE_NONE\n  ///       - when no Intents can be resolved to handle the `tel:` scheme\n  ///     - The method will return [ServiceStatus.disabled] when:\n  ///       - the SIM card is missing\n  ///   - iOS:\n  ///     - The method will return [ServiceStatus.notApplicable] when:\n  ///       - the native code can not find a handler for the `tel:` scheme\n  ///     - The method will return [ServiceStatus.disabled] when:\n  ///       - the mobile network code (MNC) is either 0 or 65535. See\n  ///          https://stackoverflow.com/a/11595365 for details\n  ///   - **PLEASE NOTE that this is still not a perfect indication** of the\n  ///     device's capability to place & connect phone calls as it also depends\n  ///     on the network condition.\n  /// - **[Permission.bluetooth]**\n  ///   - iOS:\n  ///     - The method will **always** return [ServiceStatus.disabled] when the\n  ///       Bluetooth permission was denied by the user. It is impossible to\n  ///       obtain the actual Bluetooth service status without having the\n  ///       Bluetooth permission granted.\n  ///     - The method will prompt the user for Bluetooth permission if the\n  ///       permission was not yet requested.\n  Future<ServiceStatus> get serviceStatus => _handler.checkServiceStatus(this);\n}\n\n/// Actions that can be taken on a [List] of [Permission]s.\nextension PermissionListActions on List<Permission> {\n  /// Requests the user for access to these permissions, if they haven't already\n  /// been granted before.\n  ///\n  /// Returns a [Map] containing the status per requested [Permission].\n  Future<Map<Permission, PermissionStatus>> request() =>\n      _handler.requestPermissions(this);\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/sandbox.dart",
    "content": "import 'dart:io';\n\n/// Returns `true` if the app is running in a sandbox, eg. Flatpak, Snap, Docker, Podman.\nbool runningInSandbox() {\n  return Platform.environment.containsKey('FLATPAK_ID') ||\n      Platform.environment.containsKey('SNAP') ||\n      (Platform.environment['container']?.isNotEmpty == true) ||\n      FileSystemEntity.isFileSync('/.dockerenv');\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils/string_normalizer.dart",
    "content": "﻿extension StringNormalizer on String {\n  static final Map<String, String> _toneMap = {\n    // a\n    'ā': 'a', 'á': 'a', 'ǎ': 'a', 'à': 'a',\n    // o\n    'ō': 'o', 'ó': 'o', 'ǒ': 'o', 'ò': 'o',\n    // e\n    'ē': 'e', 'é': 'e', 'ě': 'e', 'è': 'e',\n    // i\n    'ī': 'i', 'í': 'i', 'ǐ': 'i', 'ì': 'i',\n    // u\n    'ū': 'u', 'ú': 'u', 'ǔ': 'u', 'ù': 'u',\n    // ü / v\n    'ü': 'v', 'ǖ': 'v', 'ǘ': 'v', 'ǚ': 'v', 'ǜ': 'v',\n  };\n\n  /// 去拼音声调 + ü→v + 转小写\n  String normalize() {\n    final buffer = StringBuffer();\n\n    for (final rune in toLowerCase().runes) {\n      final char = String.fromCharCode(rune);\n      buffer.write(_toneMap[char] ?? char);\n    }\n\n    return buffer.toString();\n  }\n}"
  },
  {
    "path": "simple_live_app/lib/app/utils/url_parse.dart",
    "content": "import 'package:dio/dio.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/sites.dart';\n\nclass UrlParse {\n  static UrlParse? _urlParse;\n\n  static UrlParse get instance {\n    _urlParse ??= UrlParse();\n    return _urlParse!;\n  }\n\n  /// 链接解析工具\n  Future<List> parse(String url) async {\n    var id = \"\";\n    if (url.contains(\"bilibili.com\")) {\n      var regExp = RegExp(r\"bilibili\\.com/([\\d|\\w]+)\");\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n      return [id, Sites.allSites[Constant.kBiliBili]!];\n    }\n\n    if (url.contains(\"b23.tv\")) {\n      var btvReg = RegExp(r\"https?:\\/\\/b23.tv\\/[0-9a-z-A-Z]+\");\n      var u = btvReg.firstMatch(url)?.group(0) ?? \"\";\n      var location = await _getLocation(u);\n\n      return await parse(location);\n    }\n\n    if (url.contains(\"douyu.com\")) {\n      var regExp = RegExp(r\"douyu\\.com/([\\d|\\w]+)\");\n      // 适配 topic_url\n      if (url.contains(\"topic\")) {\n        regExp = RegExp(r\"[?&]rid=([\\d]+)\");\n      }\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n\n      return [id, Sites.allSites[Constant.kDouyu]!];\n    }\n    if (url.contains(\"huya.com\")) {\n      var regExp = RegExp(r\"huya\\.com/([\\d|\\w]+)\");\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n\n      return [id, Sites.allSites[Constant.kHuya]!];\n    }\n    if (url.contains(\"live.douyin.com\")) {\n      var regExp = RegExp(r\"live\\.douyin\\.com/([\\d|\\w]+)\");\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n\n      return [id, Sites.allSites[Constant.kDouyin]!];\n    }\n    if (url.contains(\"webcast.amemv.com\")) {\n      var regExp = RegExp(r\"reflow/(\\d+)\");\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n      return [id, Sites.allSites[Constant.kDouyin]!];\n    }\n    if (url.contains(\"twitch.tv/\")) {\n      final regExp = RegExp(r'twitch\\.tv/([^/?]+)');\n      id = regExp.firstMatch(url)?.group(1) ?? \"\";\n      return [id, Sites.allSites[Constant.kTwitch]!];\n    }\n    if (url.contains(\"v.douyin.com\")) {\n      var regExp = RegExp(r\"http.?://v.douyin.com/[\\d\\w]+/\");\n      var u = regExp.firstMatch(url)?.group(0) ?? \"\";\n      var location = await _getLocation(u);\n      return await parse(location);\n    }\n\n    return [];\n  }\n\n  Future<String> _getLocation(String url) async {\n    try {\n      if (url.isEmpty) return \"\";\n      await Dio().get(\n        url,\n        options: Options(\n          followRedirects: false,\n        ),\n      );\n    } on DioException catch (e) {\n      if (e.response!.statusCode == 302) {\n        var redirectUrl = e.response!.headers.value(\"Location\");\n        if (redirectUrl != null) {\n          return redirectUrl;\n        }\n      }\n    } catch (e) {\n      Log.logPrint(e);\n    }\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/app/utils.dart",
    "content": "import 'dart:io';\n\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:intl/intl.dart';\nimport 'package:package_info_plus/package_info_plus.dart';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils/permission_handler.dart';\nimport 'package:simple_live_app/requests/common_request.dart';\nimport 'package:url_launcher/url_launcher_string.dart';\n\ntypedef TextValidate = bool Function(String text);\n\nclass Utils {\n  static late PackageInfo packageInfo;\n  static DateFormat dateFormat = DateFormat(\"MM-dd HH:mm\");\n  static DateFormat dateFormatWithYear = DateFormat(\"yyyy-MM-dd HH:mm\");\n  static DateFormat timeFormat = DateFormat(\"HH:mm:ss\");\n\n  /// 处理时间\n  static String parseTime(DateTime? dt) {\n    if (dt == null) {\n      return \"\";\n    }\n\n    var dtNow = DateTime.now();\n    if (dt.year == dtNow.year &&\n        dt.month == dtNow.month &&\n        dt.day == dtNow.day) {\n      return \"${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}\";\n    }\n\n    if (dt.year == dtNow.year) {\n      return dateFormat.format(dt);\n    }\n\n    return dateFormatWithYear.format(dt);\n  }\n\n  /// 提示弹窗\n  /// - `content` 内容\n  /// - `title` 弹窗标题\n  /// - `confirm` 确认按钮内容，留空为确定\n  /// - `cancel` 取消按钮内容，留空为取消\n  static Future<bool> showAlertDialog(\n    String content, {\n    String title = '',\n    String confirm = '',\n    String cancel = '',\n    bool selectable = false,\n    List<Widget>? actions,\n  }) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: Container(\n          constraints: const BoxConstraints(\n            maxHeight: 400,\n          ),\n          child: SingleChildScrollView(\n            child: Padding(\n              padding: AppStyle.edgeInsetsV12,\n              child: selectable ? SelectableText(content) : Text(content),\n            ),\n          ),\n        ),\n        actions: [\n          ...?actions,\n          TextButton(\n            onPressed: (() => Get.back(result: false)),\n            child: Text(cancel.isEmpty ? \"取消\" : cancel),\n          ),\n          TextButton(\n            onPressed: (() => Get.back(result: true)),\n            child: Text(confirm.isEmpty ? \"确定\" : confirm),\n          ),\n        ],\n      ),\n    );\n    return result ?? false;\n  }\n\n  /// 提示弹窗\n  /// - `content` 内容\n  /// - `title` 弹窗标题\n  /// - `confirm` 确认按钮内容，留空为确定\n  static Future<bool> showMessageDialog(String content,\n      {String title = '', String confirm = '', bool selectable = false}) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: Padding(\n          padding: AppStyle.edgeInsetsV12,\n          child: selectable ? SelectableText(content) : Text(content),\n        ),\n        actions: [\n          TextButton(\n            onPressed: (() => Get.back(result: true)),\n            child: Text(confirm.isEmpty ? \"确定\" : confirm),\n          ),\n        ],\n      ),\n    );\n    return result ?? false;\n  }\n\n  static void showRightDialog({\n    required String title,\n    Function()? onDismiss,\n    required Widget child,\n    double width = 320,\n    bool useSystem = false,\n  }) {\n    SmartDialog.show(\n      alignment: Alignment.topRight,\n      animationBuilder: (controller, child, animationParam) {\n        //从右到左\n        return SlideTransition(\n          position: Tween<Offset>(\n            begin: const Offset(1, 0),\n            end: Offset.zero,\n          ).animate(controller.view),\n          child: child,\n        );\n      },\n      useSystem: useSystem,\n      maskColor: Colors.transparent,\n      animationTime: const Duration(milliseconds: 200),\n      builder: (context) => Container(\n        width: width + MediaQuery.of(context).padding.right,\n        padding: EdgeInsets.only(right: MediaQuery.of(context).padding.right),\n        decoration: BoxDecoration(\n          color: Get.theme.cardColor,\n          borderRadius: const BorderRadius.only(\n            topLeft: Radius.circular(4),\n            bottomLeft: Radius.circular(4),\n          ),\n        ),\n        child: SafeArea(\n          left: false,\n          right: false,\n          child: MediaQuery(\n            data: const MediaQueryData(padding: EdgeInsets.zero),\n            child: Column(\n              children: [\n                ListTile(\n                  visualDensity: VisualDensity.compact,\n                  contentPadding: EdgeInsets.zero,\n                  leading: IconButton(\n                    onPressed: () {\n                      SmartDialog.dismiss(status: SmartStatus.allCustom).then(\n                        (value) => onDismiss?.call(),\n                      );\n                    },\n                    icon: const Icon(Icons.arrow_back),\n                  ),\n                  title: Text(\n                    title,\n                    style: Get.textTheme.titleMedium,\n                  ),\n                ),\n                Divider(\n                  height: 1,\n                  color: Colors.grey.withAlpha(25),\n                ),\n                Expanded(\n                  child: child,\n                ),\n              ],\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n\n  static void hideRightDialog() {\n    SmartDialog.dismiss(status: SmartStatus.allCustom);\n  }\n\n  static Future showBottomSheet({\n    required String title,\n    required Widget child,\n    double maxWidth = 600,\n  }) async {\n    var result = await showModalBottomSheet(\n      context: Get.context!,\n      constraints: BoxConstraints(\n        maxWidth: maxWidth,\n      ),\n      shape: const RoundedRectangleBorder(\n        borderRadius: BorderRadius.only(\n          topLeft: Radius.circular(12),\n          topRight: Radius.circular(12),\n        ),\n      ),\n      builder: (_) => Column(\n        children: [\n          ListTile(\n            contentPadding: const EdgeInsets.only(\n              left: 12,\n            ),\n            title: Text(title),\n            trailing: IconButton(\n              onPressed: Get.back,\n              icon: const Icon(Remix.close_line),\n            ),\n          ),\n          Expanded(\n            child: child,\n          ),\n        ],\n      ),\n    );\n    return result;\n  }\n\n  /// 文本编辑的弹窗\n  /// - `content` 编辑框默认的内容\n  /// - `title` 弹窗标题\n  /// - `confirm` 确认按钮内容\n  /// - `cancel` 取消按钮内容\n  static Future<String?> showEditTextDialog(\n    String content, {\n    String title = '',\n    String? hintText,\n    String confirm = '',\n    String cancel = '',\n    TextValidate? validate,\n  }) async {\n    final TextEditingController textEditingController =\n        TextEditingController(text: content);\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: Padding(\n          padding: AppStyle.edgeInsetsT12,\n          child: TextField(\n            controller: textEditingController,\n            decoration: InputDecoration(\n              border: const OutlineInputBorder(),\n              //prefixText: title,\n              contentPadding: AppStyle.edgeInsetsA12,\n              hintText: hintText ?? title,\n            ),\n            // style: TextStyle(\n            //     height: 1.0,\n            //     color: Get.isDarkMode ? Colors.white : Colors.black),\n            autofocus: true,\n          ),\n        ),\n        actions: [\n          TextButton(\n            onPressed: Get.back,\n            child: const Text(\"取消\"),\n          ),\n          TextButton(\n            onPressed: () {\n              if (validate != null && !validate(textEditingController.text)) {\n                return;\n              }\n\n              Get.back(result: textEditingController.text);\n            },\n            child: const Text(\"确定\"),\n          ),\n        ],\n      ),\n      // barrierColor:\n      //     Get.isDarkMode ? Colors.grey.withOpacity(.3) : Colors.black38,\n    );\n    return result;\n  }\n\n  static Future<T?> showOptionDialog<T>(\n    List<T> contents,\n    T value, {\n    String title = '',\n  }) async {\n    var result = await Get.dialog(\n      SimpleDialog(\n        title: Text(title),\n        children: [\n          RadioGroup<T>(\n            groupValue: value,\n            onChanged: (e) {\n              Get.back(result: e);\n            },\n            child: Column(\n              children: contents\n                  .map(\n                    (e) => RadioListTile<T>(\n                      title: Text(e.toString()),\n                      value: e,\n                    ),\n                  )\n                  .toList(),\n            ),\n          ),\n        ],\n      ),\n    );\n    return result;\n  }\n\n  static Future<T?> showInformationHelpDialog<T>({\n    required List<Widget> content,\n    Widget? title,\n    List<Widget>? actions,\n  }) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: title ?? const Text(\"帮助\"),\n        scrollable: true,\n        content: SingleChildScrollView(child: ListBody(children: content)),\n        actions: actions ??\n            [\n              TextButton(\n                onPressed: Get.back,\n                child: const Text(\"确定\"),\n              ),\n            ],\n      ),\n    );\n    return result;\n  }\n\n  static Future showStatement() async {\n    var text = await rootBundle.loadString(\"assets/statement.txt\");\n\n    var result = await showAlertDialog(\n      text,\n      selectable: true,\n      title: \"免责声明\",\n      confirm: \"已阅读并同意\",\n      cancel: \"退出\",\n    );\n    if (!result) {\n      exit(0);\n    }\n  }\n\n  static Future<T?> showMapOptionDialog<T>(\n    Map<T, String> contents,\n    T value, {\n    String title = '',\n  }) async {\n    var result = await Get.dialog(\n      SimpleDialog(\n        title: Text(title),\n        children: [\n          RadioGroup<T>(\n            groupValue: value,\n            onChanged: (e) {\n              Get.back(result: e);\n            },\n            child: Column(\n              children: contents.keys\n                  .map(\n                    (e) => RadioListTile<T>(\n                      title: Text((contents[e] ?? '-').tr),\n                      value: e,\n                    ),\n                  )\n                  .toList(),\n            ),\n          ),\n        ],\n      ),\n    );\n    return result;\n  }\n\n  static void checkUpdate({bool showMsg = false}) async {\n    try {\n      int currentVer = Utils.parseVersion(packageInfo.version);\n      CommonRequest request = CommonRequest();\n      var versionInfo = await request.checkUpdate();\n      if (versionInfo.versionNum > currentVer) {\n        Get.dialog(\n          AlertDialog(\n            title: Text(\n              \"发现新版本 ${versionInfo.version}\",\n              textAlign: TextAlign.center,\n              style: const TextStyle(fontSize: 18),\n            ),\n            content: Text(\n              versionInfo.versionDesc,\n              style: const TextStyle(fontSize: 14, height: 1.4),\n            ),\n            actionsPadding: AppStyle.edgeInsetsH12,\n            actions: [\n              Row(\n                mainAxisAlignment: MainAxisAlignment.spaceBetween,\n                children: [\n                  Expanded(\n                    child: TextButton(\n                      onPressed: () {\n                        Get.back();\n                      },\n                      child: const Text(\"取消\"),\n                    ),\n                  ),\n                  AppStyle.hGap12,\n                  Expanded(\n                    child: ElevatedButton(\n                      style: ElevatedButton.styleFrom(\n                        elevation: 0,\n                      ),\n                      onPressed: () {\n                        launchUrlString(\n                          versionInfo.downloadUrl,\n                          mode: LaunchMode.externalApplication,\n                        );\n                      },\n                      child: const Text(\"更新\"),\n                    ),\n                  ),\n                ],\n              ),\n            ],\n          ),\n        );\n      } else {\n        if (showMsg) {\n          SmartDialog.showToast(\"当前已经是最新版本了\");\n        }\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      if (showMsg) {\n        SmartDialog.showToast(\"检查更新失败\");\n      }\n    }\n  }\n\n  static int parseVersion(String version) {\n    var sp = version.split('.');\n    var num = \"\";\n    for (var item in sp) {\n      num = num + item.padLeft(2, '0');\n    }\n    return int.parse(num);\n  }\n\n  static String onlineToString(int num) {\n    if (num >= 10000) {\n      return \"${(num / 10000.0).toStringAsFixed(1)}万\";\n    }\n    return num.toString();\n  }\n\n  /// 检查相册权限\n  static Future<bool> checkPhotoPermission() async {\n    try {\n      if (!Platform.isIOS) {\n        return true;\n      }\n      var status = await Permission.photos.status;\n      if (status == PermissionStatus.granted) {\n        return true;\n      }\n      status = await Permission.photos.request();\n      if (status.isGranted) {\n        return true;\n      } else {\n        SmartDialog.showToast(\n          \"请授予相册访问权限\",\n        );\n        return false;\n      }\n    } catch (e) {\n      return false;\n    }\n  }\n\n  static final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n\n  /// 检查文件权限\n  static Future<bool> checkStorgePermission() async {\n    try {\n      if (!Platform.isAndroid) {\n        return true;\n      }\n      Permission permission = Permission.storage;\n      var androidIndo = await deviceInfo.androidInfo;\n      if (androidIndo.version.sdkInt >= 33) {\n        permission = Permission.manageExternalStorage;\n      }\n\n      var status = await permission.status;\n      if (status == PermissionStatus.granted) {\n        return true;\n      }\n      status = await permission.request();\n      if (status.isGranted) {\n        return true;\n      } else {\n        SmartDialog.showToast(\n          \"请授予文件访问权限\",\n        );\n        return false;\n      }\n    } catch (e) {\n      return false;\n    }\n  }\n\n  ///16进制颜色转换\n  static Color convertHexColor(String hexColor) {\n    hexColor = hexColor.replaceAll(\"#\", \"\");\n    if (hexColor.length == 4) {\n      hexColor = \"00$hexColor\";\n    }\n\n    if (hexColor.length == 6) {\n      var R = int.parse(hexColor.substring(0, 2), radix: 16);\n      var G = int.parse(hexColor.substring(2, 4), radix: 16);\n      var B = int.parse(hexColor.substring(4, 6), radix: 16);\n      return Color.fromARGB(255, R, G, B);\n    }\n    if (hexColor.length == 8) {\n      var A = int.parse(hexColor.substring(0, 2), radix: 16);\n      var R = int.parse(hexColor.substring(2, 4), radix: 16);\n      var G = int.parse(hexColor.substring(4, 6), radix: 16);\n      var B = int.parse(hexColor.substring(6, 8), radix: 16);\n\n      return Color.fromARGB(A, R, G, B);\n    }\n\n    return Colors.white;\n  }\n\n  /// 复制内容到剪贴板\n  static void copyToClipboard(String text) async {\n    try {\n      await Clipboard.setData(ClipboardData(text: text));\n      SmartDialog.showToast(\"已复制到剪贴板\");\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"复制到剪贴板失败: $e\");\n    }\n  }\n\n  /// 获取剪贴板内容\n  static Future<String?> getClipboard() async {\n    try {\n      var content = await Clipboard.getData(Clipboard.kTextPlain);\n      if (content == null) {\n        SmartDialog.showToast(\"无法读取剪贴板内容\");\n        return null;\n      }\n      return content.text;\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"读取剪切板内容失败：$e\");\n    }\n    return null;\n  }\n\n  static bool isRegexFormat(String keyword) {\n    return keyword.startsWith('/') &&\n        keyword.endsWith('/') &&\n        keyword.length > 2;\n  }\n\n  static String removeRegexFormat(String keyword) {\n    return keyword.substring(1, keyword.length - 1);\n  }\n\n  static String parseFileSize(int size) {\n    if (size < 1024) {\n      return \"$size B\";\n    }\n    if (size < 1024 * 1024) {\n      return \"${(size / 1024).toStringAsFixed(2)} KB\";\n    }\n    if (size < 1024 * 1024 * 1024) {\n      return \"${(size / 1024 / 1024).toStringAsFixed(2)} MB\";\n    }\n    return \"${(size / 1024 / 1024 / 1024).toStringAsFixed(2)} GB\";\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/firebase_options.dart",
    "content": "import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;\nimport 'package:flutter/foundation.dart'\n    show defaultTargetPlatform, kIsWeb, TargetPlatform;\nclass DefaultFirebaseOptions {\n  static FirebaseOptions get currentPlatform {\n    if (kIsWeb) {\n      throw UnsupportedError(\n        'DefaultFirebaseOptions have not been configured for web - '\n        'you can reconfigure this by running the FlutterFire CLI again.',\n      );\n    }\n    switch (defaultTargetPlatform) {\n      case TargetPlatform.android:\n        return android;\n      case TargetPlatform.iOS:\n        throw UnsupportedError(\n          'DefaultFirebaseOptions have not been configured for ios - '\n          'you can reconfigure this by running the FlutterFire CLI again.',\n        );\n      case TargetPlatform.macOS:\n        throw UnsupportedError(\n          'DefaultFirebaseOptions have not been configured for macos - '\n          'you can reconfigure this by running the FlutterFire CLI again.',\n        );\n      case TargetPlatform.windows:\n        throw UnsupportedError(\n          'DefaultFirebaseOptions have not been configured for windows - '\n          'you can reconfigure this by running the FlutterFire CLI again.',\n        );\n      case TargetPlatform.linux:\n        throw UnsupportedError(\n          'DefaultFirebaseOptions have not been configured for linux - '\n          'you can reconfigure this by running the FlutterFire CLI again.',\n        );\n      default:\n        throw UnsupportedError(\n          'DefaultFirebaseOptions are not supported for this platform.',\n        );\n    }\n  }\n\n  static const FirebaseOptions android = FirebaseOptions(\n    apiKey: '0',\n    appId: '1:000000000000:android:0000000000000000',\n    messagingSenderId: '000000000000',\n    projectId: 'com-slotsun-slive',\n    storageBucket: 'com-slotsun-slive.firebasestorage.app',\n  );\n\n}"
  },
  {
    "path": "simple_live_app/lib/icons/live_icons.dart",
    "content": "//  This file is automatically generated. DO NOT EDIT, all your changes would be lost.\n//  https://pub.dartlang.org/packages/iconfont_convert\n\nimport 'package:flutter/material.dart';\n\nclass LiveIcons {\n  static const String _family = 'iconfont';\n  \n  LiveIcons._();\n  \n  static const IconData douyu = IconData(0xe613, fontFamily: _family); // douyu\n  static const IconData huya = IconData(0xe614, fontFamily: _family); // 虎牙\n}\n\nclass _PreviewIcon {\n  const _PreviewIcon(this.icon, this.name, this.propName);\n\n  final IconData icon;\n  final String name;\n  final String propName;\n}\n\nclass LiveIconsPreview extends StatelessWidget {\n  const LiveIconsPreview({super.key});\n\n  static const iconList = <_PreviewIcon>[\n    _PreviewIcon(LiveIcons.douyu, \"douyu\", \"douyu\"),\n    _PreviewIcon(LiveIcons.huya, \"huya\", \"虎牙\"),\n  ];\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('LiveIcons'),\n      ),\n      body: GridView.count(\n        shrinkWrap: true,\n        crossAxisCount: 4,\n        children: iconList.map((e) {\n          return InkWell(\n            onTap: () {\n              //\n            },\n            child: Column(\n              mainAxisAlignment: MainAxisAlignment.center,\n              children: [\n                Container(\n                  margin: const EdgeInsets.only(bottom: 8),\n                  child: Icon(e.icon),\n                ),\n                Text(e.name, style: const TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, maxLines: 1),\n                Text(e.propName, style: const TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, maxLines: 1),\n              ],\n            ),\n          );\n        }).toList(),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/main.dart",
    "content": "import 'dart:async';\nimport 'dart:io';\n\nimport 'package:dynamic_color/dynamic_color.dart';\nimport 'package:firebase_core/firebase_core.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_localizations/flutter_localizations.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:hive_flutter/hive_flutter.dart';\nimport 'package:logger/logger.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:package_info_plus/package_info_plus.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/listen_fourth_button.dart';\nimport 'package:simple_live_app/firebase_options.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/modules/other/debug_log_page.dart';\nimport 'package:simple_live_app/modules/settings/appstyle_settings/appstyle_setting_contorller.dart';\nimport 'package:simple_live_app/routes/app_analytics_observer.dart';\nimport 'package:simple_live_app/routes/app_pages.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/douyin_account_service.dart';\nimport 'package:simple_live_app/services/firebase_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/services/history_service.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\nimport 'package:simple_live_app/services/migration_service.dart';\nimport 'package:simple_live_app/services/sync_service.dart';\nimport 'package:simple_live_app/services/window_service.dart';\nimport 'package:simple_live_app/src/rust/frb_generated.dart';\nimport 'package:simple_live_app/widgets/status/app_loadding_widget.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:window_manager/window_manager.dart';\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  // init-queue:\n  // window(first)->migration->media_kit->Hive->services->start\n  // window(second)->open\n  await RustLib.init();\n  await MigrationService.migrateData();\n  MediaKit.ensureInitialized();\n  await Hive.initFlutter(\n    (!Platform.isAndroid && !Platform.isIOS)\n        ? (await getApplicationSupportDirectory()).path\n        : null,\n  );\n  //初始化服务\n  await initServices();\n  await initWindow();\n\n  await MigrationService.migrateDataByVersion();\n  SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);\n  //设置状态栏为透明\n  SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle(\n    statusBarColor: Colors.transparent,\n    statusBarIconBrightness: Brightness.dark,\n    systemNavigationBarColor: Colors.transparent,\n  );\n  SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);\n  runApp(const MyApp());\n}\n\nFuture initWindow() async {\n  if (!(Platform.isMacOS || Platform.isWindows || Platform.isLinux)) {\n    return;\n  }\n  await windowManager.ensureInitialized();\n  WindowService.instance.init();\n}\n\nFuture initServices() async {\n  Hive.registerAdapter(FollowUserAdapter());\n  Hive.registerAdapter(HistoryAdapter());\n  Hive.registerAdapter(FollowUserTagAdapter());\n\n  //包信息\n  Utils.packageInfo = await PackageInfo.fromPlatform();\n  //本地存储\n  Log.d(\"Init LocalStorage Service\");\n  await Get.put(LocalStorageService()).init();\n  await Get.put(DBService()).init();\n  //初始化设置控制器\n  Get.put(AppSettingsController());\n\n  await Get.put(AppStyleSettingController()).init();\n\n  Get.put(BiliBiliAccountService());\n\n  Get.put(DouyinAccountService());\n\n  Get.put(SyncService());\n\n  Get.put(FollowService());\n\n  Get.put(HistoryService());\n\n  // 移动平台不使用 windowManager\n  if(!Platform.isAndroid && !Platform.isIOS){\n    Get.put(WindowService());\n  }\n\n  // only android use firebase\n  if(Platform.isAndroid){\n    await Firebase.initializeApp(\n      options: DefaultFirebaseOptions.currentPlatform,\n    );\n    Get.put(FirebaseService());\n  }\n\n  initCoreLog();\n}\n\nvoid initCoreLog() {\n  //日志信息\n  CoreLog.enableLog =\n      !kReleaseMode || AppSettingsController.instance.logEnable.value;\n  CoreLog.requestLogType = RequestLogType.short;\n  CoreLog.onPrintLog = (level, msg) {\n    switch (level) {\n      case Level.debug:\n        Log.d(msg);\n        break;\n      case Level.error:\n        Log.e(msg, StackTrace.current);\n        break;\n      case Level.info:\n        Log.i(msg);\n        break;\n      case Level.warning:\n        Log.w(msg);\n        break;\n      default:\n        Log.logPrint(msg);\n    }\n  };\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    bool isDynamicColor = AppStyleSettingController.instance.isDynamic.value;\n    Color styleColor = Color(AppStyleSettingController.instance.styleColor.value);\n    return DynamicColorBuilder(\n        builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {\n      ColorScheme? lightColorScheme;\n      ColorScheme? darkColorScheme;\n      if (lightDynamic != null && darkDynamic != null && isDynamicColor) {\n        lightColorScheme = lightDynamic;\n        darkColorScheme = darkDynamic;\n      } else {\n        lightColorScheme = ColorScheme.fromSeed(\n          seedColor: styleColor,\n          brightness: Brightness.light,\n        );\n        darkColorScheme = ColorScheme.fromSeed(\n            seedColor: styleColor, brightness: Brightness.dark);\n      }\n      return Obx(\n        () => GetMaterialApp(\n          title: \"Slive\",\n          theme: AppStyle.light(\n            fontFamily: AppStyleSettingController.instance.curFontName.value,\n          ).copyWith(colorScheme: lightColorScheme),\n          darkTheme: AppStyle.darkTheme(\n            fontFamily: AppStyleSettingController.instance.curFontName.value,\n          ).copyWith(colorScheme: darkColorScheme),\n          themeMode: ThemeMode\n              .values[Get.find<AppSettingsController>().themeMode.value],\n          initialRoute: RoutePath.kIndex,\n          getPages: AppPages.routes,\n          //国际化\n          locale: const Locale(\"zh\", \"CN\"),\n          localizationsDelegates: const [\n            GlobalMaterialLocalizations.delegate,\n            GlobalWidgetsLocalizations.delegate,\n            GlobalCupertinoLocalizations.delegate,\n          ],\n          supportedLocales: const [Locale(\"zh\", \"CN\")],\n          logWriterCallback: (text, {bool? isError}) {\n            Log.addDebugLog(text, (isError ?? false) ? Colors.red : Colors.grey);\n            Log.writeLog(text, (isError ?? false) ? Level.error : Level.info);\n          },\n          //debugShowCheckedModeBanner: false,\n          navigatorObservers: [\n            FlutterSmartDialog.observer,\n            if (Platform.isAndroid) AppAnalyticsObserver.observer\n          ],\n          builder: FlutterSmartDialog.init(\n            loadingBuilder: ((msg) => const AppLoaddingWidget()),\n            //字体大小不跟随系统变化\n            builder: (context, child) => MediaQuery(\n              data: MediaQuery.of(context)\n                  .copyWith(textScaler: const TextScaler.linear(1.0)),\n              child: Stack(\n                children: [\n                  //侧键返回\n                  RawGestureDetector(\n                    excludeFromSemantics: true,\n                    gestures: <Type, GestureRecognizerFactory>{\n                      FourthButtonTapGestureRecognizer:\n                          GestureRecognizerFactoryWithHandlers<\n                              FourthButtonTapGestureRecognizer>(\n                        () => FourthButtonTapGestureRecognizer(),\n                        (FourthButtonTapGestureRecognizer instance) {\n                          instance.onTapDown = (TapDownDetails details) async {\n                            //如果处于全屏状态，退出全屏\n                            if (!Platform.isAndroid && !Platform.isIOS) {\n                              if (await windowManager.isFullScreen()) {\n                                await windowManager.setFullScreen(false);\n                                return;\n                              }\n                            }\n                            Get.back();\n                          };\n                        },\n                      ),\n                    },\n                    child: KeyboardListener(\n                      focusNode: FocusNode(),\n                      onKeyEvent: (KeyEvent event) async {\n                        if (event is KeyDownEvent &&\n                            event.logicalKey == LogicalKeyboardKey.escape) {\n                          // ESC退出全屏\n                          // 如果处于全屏状态，退出全屏\n                          if (!Platform.isAndroid && !Platform.isIOS) {\n                            if (await windowManager.isFullScreen()) {\n                              await windowManager.setFullScreen(false);\n                              EventBus.instance.emit(EventBus.kEscapePressed, 0);\n                              return;\n                            }\n                          }\n                        }\n                      },\n                      child: child!,\n                    ),\n                  ),\n\n                  //查看DEBUG日志按钮\n                  //只在Debug、Profile模式显示\n                  Visibility(\n                    visible: !kReleaseMode,\n                    child: Positioned(\n                      right: 12,\n                      bottom: 100 + context.mediaQueryViewPadding.bottom,\n                      child: Opacity(\n                        opacity: 0.4,\n                        child: ElevatedButton(\n                          child: const Text(\"DEBUG LOG\"),\n                          onPressed: () {\n                            Get.bottomSheet(\n                              const DebugLogPage(),\n                            );\n                          },\n                        ),\n                      ),\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n        ),\n      );\n    }));\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/account/bilibili_user_info_page.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass BiliBiliUserInfoModel {\n  BiliBiliUserInfoModel({\n    this.mid,\n    this.uname,\n    this.userid,\n    this.sign,\n    this.birthday,\n    this.sex,\n    this.nickFree,\n    this.rank,\n  });\n\n  factory BiliBiliUserInfoModel.fromJson(Map<String, dynamic> json) =>\n      BiliBiliUserInfoModel(\n        mid: asT<int?>(json['mid']),\n        uname: asT<String?>(json['uname']),\n        userid: asT<String?>(json['userid']),\n        sign: asT<String?>(json['sign']),\n        birthday: asT<String?>(json['birthday']),\n        sex: asT<String?>(json['sex']),\n        nickFree: asT<bool?>(json['nick_free']),\n        rank: asT<String?>(json['rank']),\n      );\n\n  int? mid;\n  String? uname;\n  String? userid;\n  String? sign;\n  String? birthday;\n  String? sex;\n  bool? nickFree;\n  String? rank;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'mid': mid,\n        'uname': uname,\n        'userid': userid,\n        'sign': sign,\n        'birthday': birthday,\n        'sex': sex,\n        'nick_free': nickFree,\n        'rank': rank,\n      };\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/account/douyin_user_info.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass DouyinUserInfoModel {\n  DouyinUserInfoModel({\n    this.id,\n    this.nickname,\n    this.shortId,\n    this.sign,\n    this.birthday,\n    this.gender,\n  });\n\n  factory DouyinUserInfoModel.fromJson(Map<String, dynamic> json) =>\n      DouyinUserInfoModel(\n        id: asT<String?>(json['id_str']),\n        nickname: asT<String?>(json['nickname']),\n        shortId: asT<String?>(json['short_id']),\n        sign: asT<String?>(json['sign']),\n        birthday: asT<String?>(json['birthday']),\n        gender: asT<String?>(json['gender']),\n      );\n\n  String? id;\n  String? nickname;\n  String? shortId;\n  String? sign;\n  String? birthday;\n  String? gender;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'id': id,\n        'nickname': nickname,\n        'short_id': shortId,\n        'sign': sign,\n        'birthday': birthday,\n        'gender': gender,\n      };\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/follow_user.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:hive/hive.dart';\nimport 'package:simple_live_app/app/utils/dynamic_filter.dart';\n\npart 'follow_user.g.dart';\n\n@HiveType(typeId: 1)\nclass FollowUser implements Mappable {\n  FollowUser(\n      {required this.id,\n      required this.roomId,\n      required this.siteId,\n      required this.userName,\n      required this.face,\n      required this.addTime,\n      this.watchDuration = \"00:00:00\",\n      this.tag = \"全部\",\n      this.remark = \"\",\n      this.romanName = \"\"});\n\n  ///id=siteId_roomId\n  @HiveField(0)\n  String id;\n\n  @HiveField(1)\n  String roomId;\n\n  @HiveField(2)\n  String siteId;\n\n  @HiveField(3)\n  String userName;\n\n  @HiveField(4)\n  String face;\n\n  @HiveField(5)\n  DateTime addTime;\n\n  @HiveField(6)\n  String? watchDuration; // \"00:00:00\"\n\n  @HiveField(7)\n  String tag;\n\n  @HiveField(8)\n  String? remark;\n\n  @HiveField(9)\n  String? romanName;\n\n  /// 直播状态\n  /// 0=未知(加载中) 1=未开播 2=直播中\n  Rx<int> liveStatus = 0.obs;\n\n  /// 直播封面\n  Rx<String> cover = \"\".obs;\n\n  /// 直播标题\n  Rx<String> title = \"\".obs;\n\n  Rx<int> online = 0.obs;\n\n  factory FollowUser.fromJson(Map<String, dynamic> json) => FollowUser(\n      id: json['id'],\n      roomId: json['roomId'],\n      siteId: json['siteId'],\n      userName: json['userName'],\n      face: json['face'],\n      addTime: DateTime.parse(json['addTime']),\n      watchDuration: json[\"watchDuration\"] ?? \"00:00:00\",\n      tag: json[\"tag\"] ?? \"全部\",\n      remark: json[\"remark\"] ?? \"\",\n      romanName: json[\"romanName\"] ?? \"\");\n\n  Map<String, dynamic> toJson() => {\n        'id': id,\n        'roomId': roomId,\n        'siteId': siteId,\n        'userName': userName,\n        'face': face,\n        'addTime': addTime.toString(),\n        \"watchDuration\": watchDuration ?? \"00:00:00\",\n        \"tag\": tag,\n        \"remark\": remark,\n        \"romanName\": romanName\n      };\n\n  @override\n  Map<String, dynamic> toMap() => toJson();\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/follow_user.g.dart",
    "content": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'follow_user.dart';\n\n// **************************************************************************\n// TypeAdapterGenerator\n// **************************************************************************\n\nclass FollowUserAdapter extends TypeAdapter<FollowUser> {\n  @override\n  final int typeId = 1;\n\n  @override\n  FollowUser read(BinaryReader reader) {\n    final numOfFields = reader.readByte();\n    final fields = <int, dynamic>{\n      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),\n    };\n    return FollowUser(\n        id: fields[0] as String,\n        roomId: fields[1] as String,\n        siteId: fields[2] as String,\n        userName: fields[3] as String,\n        face: fields[4] as String,\n        addTime: fields[5] as DateTime,\n        watchDuration: fields[6] as String?,\n        tag: fields[7] ?? \"\",\n        remark: fields[8] as String?,\n        romanName: fields[9] as String?\n    );\n  }\n\n  @override\n  void write(BinaryWriter writer, FollowUser obj) {\n    writer\n      ..writeByte(9)\n      ..writeByte(0)\n      ..write(obj.id)\n      ..writeByte(1)\n      ..write(obj.roomId)\n      ..writeByte(2)\n      ..write(obj.siteId)\n      ..writeByte(3)\n      ..write(obj.userName)\n      ..writeByte(4)\n      ..write(obj.face)\n      ..writeByte(5)\n      ..write(obj.addTime)\n      ..writeByte(6)\n      ..write(obj.watchDuration)\n      ..writeByte(7)\n      ..write(obj.tag)\n      ..writeByte(8)\n      ..write(obj.remark)\n      ..writeByte(9)\n      ..write(obj.romanName);\n  }\n\n  @override\n  int get hashCode => typeId.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      other is FollowUserAdapter &&\n          runtimeType == other.runtimeType &&\n          typeId == other.typeId;\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/follow_user_tag.dart",
    "content": "import 'package:hive/hive.dart';\n\npart 'follow_user_tag.g.dart';\n\n@HiveType(typeId: 3)\nclass FollowUserTag {\n  @HiveField(1)\n  String id;\n\n  // 用户自定义tag\n  @HiveField(2)\n  String tag;\n\n  // followUserId\n  @HiveField(3)\n  List<String> userId;\n\n  FollowUserTag({\n    required this.id,\n    required this.tag,\n    required this.userId,\n  });\n\n  factory FollowUserTag.fromJson(Map<String, dynamic> json) {\n    return FollowUserTag(\n      id: json['id'],\n      tag: json['tag'],\n      userId: List<String>.from(json['userId']),\n    );\n  }\n\n  Map<String, dynamic> toJson() {\n    return {\n      'id': id,\n      'tag': tag,\n      'userId': userId,\n    };\n  }\n\n  FollowUserTag copyWith({\n    String? id,\n    String? tag,\n    List<String>? userId,\n  }) {\n    return FollowUserTag(\n      id: id ?? this.id,\n      tag: tag ?? this.tag,\n      userId: userId ?? this.userId,\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/follow_user_tag.g.dart",
    "content": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'follow_user_tag.dart';\n\n// **************************************************************************\n// TypeAdapterGenerator\n// **************************************************************************\n\nclass FollowUserTagAdapter extends TypeAdapter<FollowUserTag> {\n  @override\n  final int typeId = 3;\n\n  @override\n  FollowUserTag read(BinaryReader reader) {\n    final numOfFields = reader.readByte();\n    final fields = <int, dynamic>{\n      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),\n    };\n    return FollowUserTag(\n      id: fields[1] as String,\n      tag: fields[2] as String,\n      userId: (fields[3] as List).cast<String>(),\n    );\n  }\n\n  @override\n  void write(BinaryWriter writer, FollowUserTag obj) {\n    writer\n      ..writeByte(3)\n      ..writeByte(1)\n      ..write(obj.id)\n      ..writeByte(2)\n      ..write(obj.tag)\n      ..writeByte(3)\n      ..write(obj.userId);\n  }\n\n  @override\n  int get hashCode => typeId.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      other is FollowUserTagAdapter &&\n          runtimeType == other.runtimeType &&\n          typeId == other.typeId;\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/history.dart",
    "content": "import 'package:hive/hive.dart';\nimport 'package:simple_live_app/app/utils/duration_2_str_utils.dart';\nimport 'package:simple_live_app/app/utils/dynamic_filter.dart';\n\npart 'history.g.dart';\n\n@HiveType(typeId: 2)\nclass History implements Mappable {\n  History({\n    required this.id,\n    required this.roomId,\n    required this.siteId,\n    required this.userName,\n    required this.face,\n    required this.updateTime,\n    this.watchDuration = \"00:00:00\",\n  });\n\n  ///id=siteId_roomId\n  @HiveField(0)\n  String id;\n\n  @HiveField(1)\n  String roomId;\n\n  @HiveField(2)\n  String siteId;\n\n  @HiveField(3)\n  String userName;\n\n  @HiveField(4)\n  String face;\n\n  @HiveField(5)\n  DateTime updateTime;\n\n  @HiveField(6)\n  String? watchDuration; // \"00:00:00\"\n\n  Duration get duration => watchDuration!.toDuration(); //for filter\n\n  factory History.fromJson(Map<String, dynamic> json) => History(\n        id: json[\"id\"],\n        roomId: json[\"roomId\"],\n        siteId: json[\"siteId\"],\n        userName: json[\"userName\"],\n        face: json[\"face\"],\n        updateTime: DateTime.parse(json[\"updateTime\"]),\n        watchDuration: json[\"watchDuration\"] ?? \"00:00:00\",\n      );\n\n  Map<String, dynamic> toJson() => {\n        \"id\": id,\n        \"roomId\": roomId,\n        \"siteId\": siteId,\n        \"userName\": userName,\n        \"face\": face,\n        \"updateTime\": updateTime.toString(),\n        \"watchDuration\": watchDuration ?? \"00:00:00\",\n      };\n\n  @override\n  Map<String, dynamic> toMap() => toJson();\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/db/history.g.dart",
    "content": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'history.dart';\n\n// **************************************************************************\n// TypeAdapterGenerator\n// **************************************************************************\n\nclass HistoryAdapter extends TypeAdapter<History> {\n  @override\n  final int typeId = 2;\n\n  @override\n  History read(BinaryReader reader) {\n    final numOfFields = reader.readByte();\n    final fields = <int, dynamic>{\n      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),\n    };\n    return History(\n      id: fields[0] as String,\n      roomId: fields[1] as String,\n      siteId: fields[2] as String,\n      userName: fields[3] as String,\n      face: fields[4] as String,\n      updateTime: fields[5] as DateTime,\n      watchDuration: fields[6] as String?,\n    );\n  }\n\n  @override\n  void write(BinaryWriter writer, History obj) {\n    writer\n      ..writeByte(7)\n      ..writeByte(0)\n      ..write(obj.id)\n      ..writeByte(1)\n      ..write(obj.roomId)\n      ..writeByte(2)\n      ..write(obj.siteId)\n      ..writeByte(3)\n      ..write(obj.userName)\n      ..writeByte(4)\n      ..write(obj.face)\n      ..writeByte(5)\n      ..write(obj.updateTime)\n      ..writeByte(6)\n      ..write(obj.watchDuration);\n  }\n\n  @override\n  int get hashCode => typeId.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      other is HistoryAdapter &&\n          runtimeType == other.runtimeType &&\n          typeId == other.typeId;\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/font_model.dart",
    "content": "class FontModel {\n  final String id;\n  final String name;\n  final List<String> files;\n  final String desc;\n  final String official;\n  final FontLicense? license;\n  bool isDownloaded;\n\n  FontModel({\n    required this.id,\n    required this.name,\n    required this.files,\n    required this.desc,\n    required this.official,\n    this.license,\n    this.isDownloaded = false,\n  });\n\n  factory FontModel.fromJson(Map<String, dynamic> json) {\n    return FontModel(\n      id: json['id'] as String? ?? '',\n      name: json['name'] as String? ?? '',\n      files:\n          (json['files'] as List<dynamic>?)?.map((e) => e as String).toList() ??\n              [],\n      desc: json['desc'] as String? ?? '',\n      official: json['official'] as String? ?? '',\n      license: json['license'] != null\n          ? FontLicense.fromJson(json['license'] as Map<String, dynamic>)\n          : null,\n      isDownloaded: json['isDownloaded'] as bool? ?? false,\n    );\n  }\n\n  Map<String, dynamic> toJson() {\n    return {\n      'id': id,\n      'name': name,\n      'files': files,\n      'desc': desc,\n      'official': official,\n      'license': license?.toJson(),\n      'isDownloaded': isDownloaded,\n    };\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    return other is FontModel && other.id == id;\n  }\n\n  @override\n  int get hashCode => id.hashCode;\n}\n\nclass FontLicense {\n  final String name;\n  final String url;\n\n  const FontLicense({\n    required this.name,\n    required this.url,\n  });\n\n  factory FontLicense.fromJson(Map<String, dynamic> json) {\n    return FontLicense(\n      name: json['name'] as String? ?? '',\n      url: json['url'] as String? ?? '',\n    );\n  }\n\n  Map<String, dynamic> toJson() {\n    return {\n      'name': name,\n      'url': url,\n    };\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/fonts_model.dart",
    "content": "﻿T? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\nclass FontsModel{\n  String version;\n  int versionNum;\n  String versionDesc;\n  String downloadUrl;\n  FontsModel({\n    required this.version,\n    required this.versionNum,\n    required this.versionDesc,\n    required this.downloadUrl,\n  });\n\n}"
  },
  {
    "path": "simple_live_app/lib/models/sync_client_info_model.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass SyncClientInfoModel {\n  SyncClientInfoModel({\n    required this.name,\n    required this.version,\n    required this.address,\n    required this.port,\n    required this.type,\n  });\n\n  factory SyncClientInfoModel.fromJson(Map<String, dynamic> json) =>\n      SyncClientInfoModel(\n        type: asT<String>(json['type'])!,\n        name: asT<String>(json['name'])!,\n        version: asT<String>(json['version'])!,\n        address: asT<String>(json['address'])!,\n        port: asT<int>(json['port'])!,\n      );\n  String type;\n  String name;\n  String version;\n  String address;\n  int port;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'name': name,\n        'version': version,\n        'address': address,\n        'port': port,\n        'type': type,\n      };\n}\n"
  },
  {
    "path": "simple_live_app/lib/models/version_model.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass VersionModel {\n  VersionModel({\n    required this.version,\n    required this.versionNum,\n    required this.versionDesc,\n    required this.downloadUrl,\n  });\n\n  factory VersionModel.fromJson(Map<String, dynamic> json) => VersionModel(\n        version: asT<String>(json['version'])!,\n        versionNum: asT<int>(json['version_num'])!,\n        versionDesc: asT<String>(json['version_desc'])!,\n        downloadUrl: asT<String>(json['download_url'])!,\n      );\n\n  String version;\n  int versionNum;\n  String versionDesc;\n  String downloadUrl;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'version': version,\n        'version_num': versionNum,\n        'version_desc': versionDesc,\n        'download_url': downloadUrl,\n      };\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/category_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/category/category_list_controller.dart';\n\nclass CategoryController extends GetxController\n    with GetSingleTickerProviderStateMixin {\n  late TabController tabController;\n  CategoryController() {\n    tabController =\n        TabController(length: Sites.supportSites.length, vsync: this);\n  }\n  StreamSubscription<dynamic>? streamSubscription;\n  @override\n  void onInit() {\n    streamSubscription = EventBus.instance.listen(\n      EventBus.kBottomNavigationBarClicked,\n      (index) {\n        if (index == 2) {\n          refreshOrScrollTop();\n        }\n      },\n    );\n    for (var site in Sites.supportSites) {\n      Get.put(CategoryListController(site), tag: site.id);\n    }\n\n    super.onInit();\n  }\n\n  void refreshOrScrollTop() {\n    var tabIndex = tabController.index;\n    BasePageController controller;\n    controller =\n        Get.find<CategoryListController>(tag: Sites.supportSites[tabIndex].id);\n    controller.scrollToTopOrRefresh();\n  }\n\n  @override\n  void onClose() {\n    streamSubscription?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/category_list_controller.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass CategoryListController extends BasePageController<AppLiveCategory> {\n  final Site site;\n  CategoryListController(this.site);\n\n  @override\n  Future<List<AppLiveCategory>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getCategores();\n\n    return result.map((e) => AppLiveCategory.fromLiveCategory(e)).toList();\n  }\n}\n\nclass AppLiveCategory extends LiveCategory {\n  var showAll = false.obs;\n  AppLiveCategory({\n    required super.id,\n    required super.name,\n    required super.children,\n  }) {\n    showAll.value = children.length < 19;\n  }\n\n  List<LiveSubCategory> get take15 => children.take(15).toList();\n\n  factory AppLiveCategory.fromLiveCategory(LiveCategory item) {\n    return AppLiveCategory(\n      children: item.children,\n      id: item.id,\n      name: item.name,\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/category_list_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_easyrefresh/easy_refresh.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/category/category_list_controller.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_app/widgets/shadow_card.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:sticky_headers/sticky_headers.dart';\n\nclass CategoryListView extends StatelessWidget {\n  final String tag;\n  const CategoryListView(this.tag, {super.key});\n  CategoryListController get controller =>\n      Get.find<CategoryListController>(tag: tag);\n  @override\n  Widget build(BuildContext context) {\n    return KeepAliveWrapper(\n      child: Obx(\n        () => EasyRefresh(\n          firstRefresh: true,\n          controller: controller.easyRefreshController,\n          onRefresh: controller.refreshData,\n          header: MaterialHeader(\n            completeDuration: const Duration(milliseconds: 400),\n          ),\n          child: ListView.builder(\n            padding: AppStyle.edgeInsetsA12,\n            itemCount: controller.list.length,\n            controller: controller.scrollController,\n            itemBuilder: (_, i) {\n              var item = controller.list[i];\n              return Column(\n                children: [\n                  StickyHeader(\n                    header: Container(\n                      padding: AppStyle.edgeInsetsV8.copyWith(left: 4),\n                      color: Theme.of(context).scaffoldBackgroundColor,\n                      alignment: Alignment.centerLeft,\n                      child: Text(\n                        item.name,\n                        style: const TextStyle(\n                            fontSize: 18, fontWeight: FontWeight.bold),\n                      ),\n                    ),\n                    content: Obx(\n                      () => GridView.count(\n                        shrinkWrap: true,\n                        padding: AppStyle.edgeInsetsV8,\n                        physics: const NeverScrollableScrollPhysics(),\n                        crossAxisCount: MediaQuery.of(context).size.width ~/ 80,\n                        crossAxisSpacing: 8,\n                        mainAxisSpacing: 8,\n                        children: item.showAll.value\n                            ? (item.children\n                                .map(\n                                  (e) => buildSubCategory(e),\n                                )\n                                .toList())\n                            : (item.take15\n                                .map(\n                                  (e) => buildSubCategory(e),\n                                )\n                                .toList()\n                              ..add(buildShowMore(item))),\n                      ),\n                    ),\n                  ),\n                ],\n              );\n            },\n          ),\n        ),\n      ),\n    );\n  }\n\n  Widget buildSubCategory(LiveSubCategory item) {\n    return ShadowCard(\n      onTap: () {\n        AppNavigator.toCategoryDetail(site: controller.site, category: item);\n      },\n      child: Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        children: [\n          NetImage(\n            item.pic ?? \"\",\n            width: 40,\n            height: 40,\n            borderRadius: 8,\n          ),\n          AppStyle.vGap4,\n          Text(\n            item.name,\n            maxLines: 1,\n            textAlign: TextAlign.center,\n            style: const TextStyle(fontSize: 12),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildShowMore(AppLiveCategory item) {\n    return ShadowCard(\n      onTap: () {\n        item.showAll.value = true;\n      },\n      child: const Center(\n        child: Text(\n          \"显示全部\",\n          maxLines: 1,\n          textAlign: TextAlign.center,\n          style: TextStyle(fontSize: 12),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/category_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/category/category_controller.dart';\nimport 'package:simple_live_app/modules/category/category_list_view.dart';\n\nclass CategoryPage extends GetView<CategoryController> {\n  const CategoryPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        titleSpacing: 8,\n        title: TabBar(\n          controller: controller.tabController,\n          padding: EdgeInsets.zero,\n          tabAlignment: TabAlignment.center,\n          tabs: Sites.supportSites\n              .map(\n                (e) => Tab(\n                  //text: e.name,\n                  child: Row(\n                    children: [\n                      Image.asset(\n                        e.logo,\n                        width: 24,\n                      ),\n                      AppStyle.hGap8,\n                      Text(e.name),\n                    ],\n                  ),\n                ),\n              )\n              .toList(),\n          labelPadding: AppStyle.edgeInsetsH20,\n          isScrollable: true,\n          indicatorSize: TabBarIndicatorSize.label,\n        ),\n      ),\n      body: TabBarView(\n        controller: controller.tabController,\n        children: Sites.supportSites\n            .map(\n              (e) => CategoryListView(\n                e.id,\n              ),\n            )\n            .toList(),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/detail/category_detail_controller.dart",
    "content": "import 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass CategoryDetailController extends BasePageController<LiveRoomItem> {\n  final Site site;\n  final LiveSubCategory subCategory;\n  CategoryDetailController({\n    required this.site,\n    required this.subCategory,\n  });\n\n  @override\n  Future<List<LiveRoomItem>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getCategoryRooms(subCategory, page: page);\n    return result.items;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/category/detail/category_detail_page.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/category/detail/category_detail_controller.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/live_room_card.dart';\nimport 'package:simple_live_app/widgets/page_grid_view.dart';\n\nclass CategoryDetailPage extends GetView<CategoryDetailController> {\n  const CategoryDetailPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    var c = MediaQuery.of(context).size.width ~/ 200;\n    if (c < 2) {\n      c = 2;\n    }\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(controller.subCategory.name),\n      ),\n      body: KeepAliveWrapper(\n        child: PageGridView(\n          pageController: controller,\n          padding: AppStyle.edgeInsetsA12,\n          firstRefresh: true,\n          mainAxisSpacing: 12,\n          crossAxisSpacing: 12,\n          crossAxisCount: c,\n          itemBuilder: (_, i) {\n            var item = controller.list[i];\n            return LiveRoomCard(controller.site, item);\n          },\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_app_setting/follow_app_settings_controller.dart",
    "content": "﻿import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:fractional_indexing_dart/fractional_indexing_dart.dart';\nimport 'package:get/get.dart' hide Condition;\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/duration_2_str_utils.dart';\nimport 'package:simple_live_app/app/utils/dynamic_filter.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\n\nclass FollowAppSettingsController extends BaseController {\n  final appC = Get.find<AppSettingsController>();\n\n  // 用户自定义标签\n  RxList<FollowUserTag> userTagList = <FollowUserTag>[].obs;\n\n  // 用户自定义条件\n  Rx<int> takeLast = 15.obs;\n  Rx<int> minutes = 30.obs;\n\n  @override\n  void onInit() {\n    updateTagList();\n    super.onInit();\n  }\n\n  // 标签管理\n  void updateTagList() {\n    userTagList.assignAll(FollowService.instance.followTagList);\n  }\n\n  Future removeTag(FollowUserTag tag) async {\n    await FollowService.instance.removeFollowUserTag(tag);\n    updateTagList();\n    Log.i('删除tag${tag.tag}');\n  }\n\n  void addTag(String tag) async {\n    await FollowService.instance.addFollowUserTag(tag);\n    updateTagList();\n  }\n\n  Future<void> updateTag(FollowUserTag followUserTag) async {\n    await FollowService.instance.updateFollowUserTag(followUserTag);\n  }\n\n  void updateTagName(FollowUserTag followUserTag, String newTagName) {\n    // 未操作\n    if (followUserTag.tag == newTagName) {\n      return;\n    }\n    // 避免重名\n    if (userTagList.any((item) => item.tag == newTagName)) {\n      SmartDialog.showToast(\"标签名重复，修改失败\");\n      return;\n    }\n    FollowService.instance.updateTagName(followUserTag, newTagName);\n    SmartDialog.showToast(\"标签名修改成功\");\n    updateTagList();\n  }\n\n  Future<void> updateTagOrder(int oldIndex, int newIndex) async {\n    if (newIndex > oldIndex) newIndex -= 1; // 处理索引调整\n    final item = userTagList.removeAt(oldIndex);\n    String newTagKey = FractionalIndexing.generateKeyBetween(\n        newIndex > 0 ? userTagList[newIndex - 1].id : null,\n        newIndex < userTagList.length ? userTagList[newIndex].id : null);\n    final newTag = FollowUserTag(id: newTagKey, tag: item.tag, userId: item.userId);\n    userTagList.insert(newIndex, newTag);\n    await FollowService.instance.updateFollowTagOrder(item, newTag);\n  }\n\n  Future<void> followDataCheck() async {\n    await FollowService.instance.followUserAllDataCheck();\n    SmartDialog.showToast(\"数据校准完成\");\n  }\n\n  // 标签管理弹窗\n  void showTagsManager() {\n    Utils.showBottomSheet(\n      title: '标签管理',\n      child: Column(\n          mainAxisSize: MainAxisSize.min,\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: [\n            AppStyle.divider,\n            ListTile(\n              title: const Text(\"添加标签\"),\n              leading: const Icon(Icons.add),\n              onTap: () {\n                editTagDialog(\"添加标签\");\n              },\n            ),\n            AppStyle.divider,\n            // 列表内容\n            Expanded(\n              child: Obx(\n                () => ReorderableListView.builder(\n                  buildDefaultDragHandles: false,\n                  itemCount: userTagList.length,\n                  itemBuilder: (context, index) {\n                    // 偏移\n                    FollowUserTag item = userTagList[index];\n                    return ListTile(\n                      key: ValueKey(item.id),\n                      title: GestureDetector(\n                        child: Text(item.tag),\n                        onLongPress: () {\n                          {\n                            editTagDialog(\"修改标签\", followUserTag: item);\n                          }\n                        },\n                      ),\n                      leading: IconButton(\n                        icon: const Icon(Icons.delete),\n                        onPressed: () {\n                          removeTag(item);\n                        },\n                      ),\n                      trailing: ReorderableDelayedDragStartListener(\n                        index: index,\n                        child: const Padding(\n                          padding: EdgeInsets.symmetric(horizontal: 12.0),\n                          child: Icon(Icons.drag_handle),\n                        ),\n                      ),\n                    );\n                  },\n                  onReorder: (int oldIndex, int newIndex) {\n                    updateTagOrder(oldIndex, newIndex);\n                  },\n                ),\n              ),\n            ),\n          ]),\n    );\n  }\n\n  void editTagDialog(String title, {FollowUserTag? followUserTag}) {\n    final TextEditingController tagEditController =\n        TextEditingController(text: followUserTag?.tag);\n    bool upMode = title == \"添加标签\" ? true : false;\n    Get.dialog(\n      AlertDialog(\n        contentPadding: const EdgeInsets.fromLTRB(12, 12, 12, 4),\n        shape: RoundedRectangleBorder(\n          borderRadius: BorderRadius.circular(12.0),\n        ),\n        content: SingleChildScrollView(\n          padding: EdgeInsets.only(\n            bottom: MediaQuery.of(Get.context!).viewInsets.bottom,\n          ),\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              Text(\n                title,\n                style: const TextStyle(\n                  fontSize: 18,\n                ),\n              ),\n              TextField(\n                controller: tagEditController,\n                minLines: 1,\n                maxLines: 1,\n                decoration: InputDecoration(\n                  border: const OutlineInputBorder(),\n                  contentPadding: AppStyle.edgeInsetsA12,\n                  enabledBorder: OutlineInputBorder(\n                    borderSide: BorderSide(\n                      color: Colors.grey.withValues(\n                        alpha: .2,\n                      ),\n                    ),\n                  ),\n                ),\n                onSubmitted: (tag) {\n                  upMode\n                      ? addTag(tagEditController.text)\n                      : updateTagName(followUserTag!, tagEditController.text);\n                  Get.back();\n                },\n              ),\n              SizedBox(\n                width: double.infinity,\n                child: Row(\n                  mainAxisAlignment: MainAxisAlignment.end,\n                  children: [\n                    TextButton(\n                      onPressed: () {\n                        Get.back();\n                      },\n                      child: const Text('否'),\n                    ),\n                    TextButton(\n                      onPressed: () {\n                        upMode\n                            ? addTag(tagEditController.text)\n                            : updateTagName(\n                                followUserTag!,\n                                tagEditController.text,\n                              );\n                        Get.back();\n                      },\n                      child: const Text('是'),\n                    ),\n                  ],\n                ),\n              )\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n\n  // 关注清理功能\n  Future<void> cleanFollow(List<FollowUser> cleanPool) async {\n    if (cleanPool.isEmpty) {\n      SmartDialog.showToast(\"没有需要清理的用户\");\n      return;\n    }\n    SmartDialog.showLoading(msg: \"清理中\");\n    for (var follow in cleanPool) {\n      // 取消关注同时删除标签内的 userId\n      if (follow.tag != \"全部\") {\n        var tag = userTagList.firstWhere((tag) => tag.tag == follow.tag);\n        tag.userId.remove(follow.id);\n        await updateTag(tag);\n      }\n      await FollowService.instance.removeFollowUser(follow.id);\n    }\n    SmartDialog.dismiss();\n    EventBus.instance.emit(Constant.kUpdateFollow, 0);\n    SmartDialog.showToast(\"清理完成\");\n  }\n\n  List<FollowUser> buildAutoCleanPool() {\n    var followList = FollowService.instance.followList;\n    var histories = DBService.instance.getHistories();\n    if (histories.isEmpty || followList.isEmpty) return [];\n    // 筛选出历史记录里已关注的\n    final followedIds =\n        followList.map((follow) => follow.id).toSet(); // set性能略优\n    final followedHistories =\n        histories.where((history) => followedIds.contains(history.id)).toList();\n    if (followedHistories.isEmpty) return [];\n\n    List<Condition> conditions = [\n      // Condition('siteId', FilterOperator.equals, Constant.kBiliBili),\n      Condition(\n        'watchDuration',\n        FilterOperator.lessThan,\n        Duration(minutes: minutes.value),\n        comparableValueProvider: (watchDuration) {\n          if (watchDuration is String) {\n            return watchDuration.toDuration();\n          }\n          return null;\n        },\n      ),\n    ];\n    // 根据动态条件筛选出需要清理的 关注id\n    final df =\n        dynamicFilter(followedHistories, conditions, takeLast: takeLast.value);\n    final uidsToClean = df.map((history) => history.id).toSet();\n\n    final autoCleanPool =\n        followList.where((follow) => uidsToClean.contains(follow.id)).toList();\n    return autoCleanPool;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_app_setting/follow_app_settings_page.dart",
    "content": "﻿import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_app_setting/follow_app_settings_controller.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/widgets/settings/settings_action.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_menu_check.dart';\nimport 'package:simple_live_app/widgets/settings/settings_number.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\n\nclass FollowSettingsPage extends GetView<FollowAppSettingsController> {\n  const FollowSettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"关注设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          Column(\n            mainAxisSize: MainAxisSize.min,\n            crossAxisAlignment: CrossAxisAlignment.stretch,\n            children: [\n              Padding(\n                padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n                child: Text(\n                  \"标签管理\",\n                  style: Get.textTheme.titleSmall,\n                ),\n              ),\n              SettingsCard(\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    SettingsAction(\n                      title: \"标签管理\",\n                      onTap: controller.showTagsManager,\n                    ),\n                  ],\n                ),\n              ),\n              Padding(\n                padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n                child: Text(\n                  \"关注清理功能\",\n                  style: Get.textTheme.titleSmall,\n                ),\n              ),\n              SettingsCard(\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    // todo：筛选条件设置\n                    // SettingsAction(\n                    //   title: \"筛选条件设置\",\n                    // ),\n                    SettingsMenuCheck<FollowUser>(\n                      title: '选择要清理的用户',\n                      subtitle: '默认条件为：观看时常低于30分钟，历史观看底部15',\n                      confirmText: '清理',\n                      itemToString: (user) => user.userName, // 告诉组件如何显示用户名\n\n                      // 这里传入您自己的筛选函数\n                      itemsProvider: () async {\n                        return controller.buildAutoCleanPool();\n                      },\n                      // 用户点击“清理”按钮后的回调\n                      onConfirm: (List<FollowUser> selectedUsers) {\n                        controller.cleanFollow(selectedUsers);\n                      },\n                    )\n                  ],\n                ),\n              ),\n              Padding(\n                padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n                child: Text(\n                  \"自动更新设置\",\n                  style: Get.textTheme.titleSmall,\n                ),\n              ),\n              SettingsCard(\n                child: Column(\n                  children: [\n                    Obx(\n                      () => SettingsSwitch(\n                        value: controller.appC.autoUpdateFollowEnable.value,\n                        title: \"自动更新关注直播状态\",\n                        onChanged: (e) {\n                          controller.appC.setAutoUpdateFollowEnable(e);\n                          FollowService.instance.initTimer();\n                        },\n                      ),\n                    ),\n                    Obx(\n                      () => Visibility(\n                        visible: controller.appC.autoUpdateFollowEnable.value,\n                        child: AppStyle.divider,\n                      ),\n                    ),\n                    Obx(\n                      () => Visibility(\n                        visible: controller.appC.autoUpdateFollowEnable.value,\n                        child: SettingsAction(\n                          title: \"自动更新间隔\",\n                          value:\n                              \"${controller.appC.autoUpdateFollowDuration.value ~/ 60}小时${controller.appC.autoUpdateFollowDuration.value % 60}分钟\",\n                          onTap: () {\n                            setTimer(context);\n                          },\n                        ),\n                      ),\n                    ),\n                    AppStyle.divider,\n                    Obx(\n                      () => SettingsNumber(\n                        value: controller.appC.updateFollowThreadCount.value,\n                        title: \"更新线程数\",\n                        subtitle: \"多线程可以能更快的完成加载，但可能会因为请求太频繁导致读取状态失败\",\n                        min: 1,\n                        max: 12,\n                        onChanged: (e) {\n                          controller.appC.setUpdateFollowThreadCount(e);\n                        },\n                      ),\n                    ),\n                  ],\n                ),\n              ),\n              Padding(\n                padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n                child: Text(\n                  \"关注导入导出\",\n                  style: Get.textTheme.titleSmall,\n                ),\n              ),\n              fileImportAndExportBuild(),\n              Padding(\n                padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n                child: Text(\n                  \"数据校准\",\n                  style: Get.textTheme.titleSmall,\n                ),\n              ),\n              SettingsCard(\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    SettingsAction(\n                      title: \"数据校准\",\n                      subtitle: '关注以及标签数据错乱可以点击此功能进行校准，请勿重复点击',\n                      onTap: controller.followDataCheck,\n                    ),\n                  ],\n                ),\n              ),\n            ],\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget fileImportAndExportBuild() {\n    return SettingsCard(\n      child: Column(\n        children: [\n          SettingsAction(\n            leading: const Icon(Remix.save_2_line),\n            title: \"导出文件\",\n            onTap: ()=>FollowService.instance.exportFile(),\n          ),\n          SettingsAction(\n            leading: const Icon(Remix.folder_open_line),\n            title: \"导入文件\",\n            onTap: ()=>FollowService.instance.inputFile(),\n          ),\n          SettingsAction(\n            leading: const Icon(Remix.text),\n            title: \"导出文本\",\n            onTap: ()=>FollowService.instance.exportText(),\n          ),\n          SettingsAction(\n            leading: const Icon(Remix.file_text_line),\n            title: \"导入文本\",\n            onTap: ()=>FollowService.instance.inputText(),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void setTimer(BuildContext context) async {\n    var value = await showTimePicker(\n      context: context,\n      initialTime: TimeOfDay(\n        hour: controller.appC.autoUpdateFollowDuration.value ~/ 60,\n        minute: controller.appC.autoUpdateFollowDuration.value % 60,\n      ),\n      initialEntryMode: TimePickerEntryMode.inputOnly,\n      builder: (_, child) {\n        return MediaQuery(\n          data: MediaQuery.of(context).copyWith(\n            alwaysUse24HourFormat: true,\n          ),\n          child: child!,\n        );\n      },\n    );\n    if (value == null || (value.hour == 0 && value.minute == 0)) {\n      return;\n    }\n    var duration = Duration(hours: value.hour, minutes: value.minute);\n    controller.appC.setAutoUpdateFollowDuration(duration.inMinutes);\n    FollowService.instance.initTimer();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_info_setting/follow_info_controller.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/url_parse.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart' show FollowUser;\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass FollowInfoController extends BasePageController<FollowUser> {\n  final Rxn<FollowUser> followUser = Rxn<FollowUser>();\n\n  // 下拉可选标签：只包含“全部”+用户自定义标签\n  final RxList<FollowUserTag> tagOptions = <FollowUserTag>[].obs;\n  final Rx<FollowUserTag?> selectedTag = Rx<FollowUserTag?>(null);\n\n  // 平台迁移预留：列出除当前平台外的其余平台\n  final RxList<Site> migrationSites = <Site>[].obs;\n\n  // 平台迁移：输入链接\n  final TextEditingController migrationUrlController = TextEditingController();\n\n  @override\n  void onInit() {\n    super.onInit();\n    // 读取传入的 FollowUser\n    final args = Get.arguments;\n    if (args is FollowUser) {\n      followUser.value = args;\n    } else if (args is Map && args['follow'] is FollowUser) {\n      followUser.value = args['follow'] as FollowUser;\n    }\n\n    _initTagOptions();\n    _initMigrationSites();\n  }\n\n  void _initTagOptions() {\n    final List<FollowUserTag> options =\n        FollowService.instance.getTagOptionsWithAll();\n    tagOptions.assignAll(options);\n\n    // 设置选中项\n    final current = followUser.value;\n    if (current != null) {\n      FollowUserTag? matched;\n      for (final e in options) {\n        if (e.tag == current.tag) {\n          matched = e;\n          break;\n        }\n      }\n      selectedTag.value = matched ?? options.first;\n    }\n  }\n\n  void _initMigrationSites() {\n    final current = followUser.value;\n    if (current == null) {\n      migrationSites.clear();\n      return;\n    }\n    final List<Site> all = Sites.supportSites;\n    migrationSites.assignAll(\n      all.where((s) => s.id != current.siteId).toList(),\n    );\n  }\n\n  void changeTag(FollowUserTag newTag) {\n    final current = followUser.value;\n    if (current == null) return;\n    FollowService.instance.setFollowTag(current, newTag);\n    selectedTag.value = newTag;\n    followUser.refresh();\n  }\n\n  void updateRemark(String newRemark) {\n    final current = followUser.value;\n    if (current == null) return;\n    current.remark = newRemark;\n    FollowService.instance.addFollow(current);\n    followUser.refresh();\n  }\n\n  Future<void> pasteFromClipboard() async {\n    final content = await Utils.getClipboard();\n    if (content != null) {\n      migrationUrlController.text = content;\n    }\n  }\n\n  Future<void> parseAndMigrate() async {\n    final url = migrationUrlController.text.trim();\n    if (url.isEmpty) {\n      SmartDialog.showToast('链接不能为空');\n      return;\n    }\n    final result = await UrlParse.instance.parse(url);\n    if (result.isEmpty || result.first == '') {\n      SmartDialog.showToast('无法解析此链接');\n      return;\n    }\n    final String newRoomId = result.first as String;\n    final Site newSite = result[1] as Site;\n\n    final current = followUser.value;\n    if (current == null) return;\n\n    // 防呆\n    bool contain =\n        FollowService.instance.getFollowExist(\"${newSite.id}_$newRoomId\");\n    if (contain == true) {\n      SmartDialog.showToast('目标主播已关注，无需迁移');\n      return;\n    }\n\n    final confirmed = await Get.dialog<bool>(AlertDialog(\n      title: const Text('确认迁移'),\n      content: Column(\n        mainAxisSize: MainAxisSize.min,\n        crossAxisAlignment: CrossAxisAlignment.start,\n        children: [\n          Text(\n              '从：${Sites.allSites[current.siteId]?.name}  房间号：${current.roomId}'),\n          const SizedBox(height: 8),\n          Text('到：${newSite.name}  房间号：$newRoomId'),\n        ],\n      ),\n      actions: [\n        TextButton(\n          onPressed: () => Get.back(result: false),\n          child: const Text('取消'),\n        ),\n        TextButton(\n          onPressed: () => Get.back(result: true),\n          child: const Text('确定'),\n        ),\n      ],\n    ));\n\n    if (confirmed != true) return;\n\n    await _migrateTo(newSite, newRoomId);\n    SmartDialog.showToast('迁移成功');\n  }\n\n  @override\n  Future<void> refreshData() async {\n    pageLoadding.value = true;\n    var site = Sites.allSites[followUser.value?.siteId]!;\n    await _migrateTo(site, followUser.value!.roomId);\n    pageLoadding.value = false;\n    SmartDialog.showToast('已刷新用户信息');\n  }\n\n  Future<void> _migrateTo(Site targetSite, String targetRoomId) async {\n    final current = followUser.value;\n    if (current == null) return;\n    // 获取目标直播间详细信息 用于更新主播名和头像\n    LiveRoomDetail detail =\n        await targetSite.liveSite.getRoomDetail(roomId: targetRoomId);\n    // 复制并更新关键信息\n    final FollowUser newFollow = FollowUser(\n      id: '${targetSite.id}_$targetRoomId',\n      roomId: targetRoomId,\n      siteId: targetSite.id,\n      userName: detail.userName,\n      face: detail.userAvatar,\n      addTime: current.addTime,\n      watchDuration: current.watchDuration,\n      tag: current.tag,\n    );\n    newFollow.liveStatus.value = current.liveStatus.value;\n    // 更新标签归属\n    if (current.tag != '全部') {\n      FollowUserTag? tagObj;\n      for (final t in FollowService.instance.followTagList) {\n        if (t.tag == current.tag) {\n          tagObj = t;\n          break;\n        }\n      }\n      if (tagObj != null) {\n        // 自刷新和迁移逻辑一致：删旧增新\n        tagObj.userId.remove(current.id);\n        tagObj.userId.add(newFollow.id);\n        await FollowService.instance.updateFollowUserTag(tagObj);\n      }\n    }\n\n    // 替换关注\n    await FollowService.instance.removeFollowUser(current.id);\n    FollowService.instance.addFollow(newFollow);\n\n    // 更新关注同时 更新历史记录数据\n    History? oldHistroy = DBService.instance.getHistory(current.id);\n    // null不迁移\n    if (oldHistroy != null) {\n      final History newHistory = History(\n        id: '${targetSite.id}_$targetRoomId',\n        roomId: targetRoomId,\n        siteId: targetSite.id,\n        userName: detail.userName,\n        face: detail.userAvatar,\n        watchDuration: oldHistroy.watchDuration,\n        updateTime: oldHistroy.updateTime,\n      );\n      await DBService.instance.delHistory(oldHistroy.id);\n      DBService.instance.addOrUpdateHistory(newHistory);\n    }\n\n    // 刷新本地数据并更新UI\n    await FollowService.instance.loadData(updateStatus: false);\n    followUser.value = newFollow;\n    _initMigrationSites();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_info_setting/follow_info_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_info_setting/follow_info_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_menu.dart';\n\nclass FollowInfoPage extends GetView<FollowInfoController> {\n  const FollowInfoPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final site = Sites.allSites[controller.followUser.value!.siteId]!;\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"关注信息设置\"),\n        actions: [\n          Obx(\n            () => controller.pageLoadding.value\n                ? const IconButton(\n                    onPressed: null,\n                    icon: SizedBox(\n                      width: 16,\n                      height: 16,\n                      child: CircularProgressIndicator(\n                        strokeWidth: 2,\n                      ),\n                    ),\n                  )\n                : IconButton(\n                    onPressed: () {\n                      controller.refreshData();\n                    },\n                    icon: const Icon(Icons.refresh),\n                  ),\n          ),\n        ],\n      ),\n      body: Column(\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: [\n          // 顶部：头像+平台+房间号\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Obx(\n              () => Row(\n                children: [\n                  CircleAvatar(\n                    radius: 28,\n                    backgroundImage:\n                        NetworkImage(controller.followUser.value!.face),\n                  ),\n                  AppStyle.hGap12,\n                  Expanded(\n                    child: Column(\n                      crossAxisAlignment: CrossAxisAlignment.start,\n                      children: [\n                        Text(\n                          controller.followUser.value!.remark?.isNotEmpty ==\n                                  true\n                              ? '${controller.followUser.value!.userName} (${controller.followUser.value!.remark!})'\n                              : controller.followUser.value!.userName,\n                          style: const TextStyle(\n                            fontSize: 18,\n                            fontWeight: FontWeight.w600,\n                          ),\n                          maxLines: 1,\n                          overflow: TextOverflow.ellipsis,\n                        ),\n                        AppStyle.vGap4,\n                        Row(\n                          children: [\n                            Image.asset(site.logo, width: 18),\n                            AppStyle.hGap8,\n                            Flexible(\n                              child: Text(\n                                '${site.name}  房间号：${controller.followUser.value!.roomId}',\n                                style: TextStyle(\n                                  fontSize: 12,\n                                  color: Theme.of(context)\n                                      .textTheme\n                                      .bodySmall\n                                      ?.color\n                                      ?.withValues(alpha: .7),\n                                ),\n                                maxLines: 1,\n                                overflow: TextOverflow.ellipsis,\n                              ),\n                            ),\n                          ],\n                        ),\n                      ],\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n          AppStyle.divider,\n          // 标签设置：底部弹出选择\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Obx(() {\n              final items = controller.tagOptions;\n              final selected = controller.selectedTag.value;\n              final Map<String, String> valueMap = {\n                for (final t in items) t.tag: t.tag,\n              };\n              return SettingsMenu<String>(\n                title: '标签设置',\n                value: selected?.tag ?? '全部',\n                valueMap: valueMap,\n                onChanged: (value) {\n                  final target = items.firstWhere(\n                    (e) => e.tag == value,\n                    orElse: () => items.first,\n                  );\n                  controller.changeTag(target);\n                },\n              );\n            }),\n          ),\n          AppStyle.divider,\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Obx(() {\n              return ListTile(\n                title:\n                    Text('备注设置', style: Theme.of(context).textTheme.bodyLarge),\n                visualDensity: VisualDensity.compact,\n                shape: RoundedRectangleBorder(\n                  borderRadius: AppStyle.radius8,\n                ),\n                contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8),\n                trailing: Row(\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    Text(\n                      controller.followUser.value?.remark?.isNotEmpty == true\n                          ? controller.followUser.value!.remark!\n                          : '无',\n                      style: Theme.of(context)\n                          .textTheme\n                          .bodyMedium!\n                          .copyWith(color: Colors.grey),\n                    ),\n                    AppStyle.hGap4,\n                    const Icon(\n                      Icons.chevron_right,\n                      color: Colors.grey,\n                    ),\n                  ],\n                ),\n                onTap: () {\n                  final textController = TextEditingController(\n                      text: controller.followUser.value?.remark);\n                  Get.dialog(\n                    AlertDialog(\n                      title: const Text(\"修改备注\"),\n                      content: TextField(\n                        controller: textController,\n                        decoration: const InputDecoration(\n                            border: OutlineInputBorder(), hintText: \"请输入备注名\"),\n                        autofocus: true,\n                        onSubmitted: (value) {\n                          controller.updateRemark(value.trim());\n                          Get.back();\n                        },\n                      ),\n                      actions: [\n                        TextButton(\n                          onPressed: () => Get.back(),\n                          child: const Text(\"取消\"),\n                        ),\n                        TextButton(\n                          onPressed: () {\n                            controller.updateRemark(textController.text.trim());\n                            Get.back();\n                          },\n                          child: const Text(\"确定\"),\n                        ),\n                      ],\n                    ),\n                  );\n                },\n              );\n            }),\n          ),\n          AppStyle.divider,\n          // 平台迁移：输入链接解析\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Column(\n              crossAxisAlignment: CrossAxisAlignment.start,\n              children: [\n                Row(\n                  children: const [\n                    Icon(Remix.link),\n                    SizedBox(width: 8),\n                    Text('平台迁移（输入直播链接进行解析）'),\n                  ],\n                ),\n                AppStyle.vGap8,\n                Row(\n                  children: [\n                    Expanded(\n                      child: TextField(\n                        controller: controller.migrationUrlController,\n                        decoration: const InputDecoration(\n                          hintText: '粘贴主播在新平台的直播间链接，如 https://... ',\n                          border: OutlineInputBorder(),\n                          isDense: true,\n                          contentPadding: EdgeInsets.symmetric(\n                            horizontal: 12,\n                            vertical: 10,\n                          ),\n                        ),\n                        onSubmitted: (_) => controller.parseAndMigrate(),\n                      ),\n                    ),\n                    AppStyle.vGap8,\n                    IconButton(\n                      tooltip: '粘贴',\n                      onPressed: controller.pasteFromClipboard,\n                      icon: const Icon(Remix.clipboard_line),\n                    ),\n                    ElevatedButton.icon(\n                      onPressed: controller.parseAndMigrate,\n                      icon: const Icon(Remix.arrow_right_line),\n                      label: const Text('迁移'),\n                    ),\n                  ],\n                ),\n                AppStyle.vGap12,\n                Text(\n                  \"other todo ...\",\n                  style: TextStyle(color: Colors.grey),\n                )\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_info_setting/readme.md",
    "content": "## 关注信息管理界面\n - 修改主播名\n - 迁移直播间功能\n - 修改标签"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_user_controller.dart",
    "content": "// ignore_for_file: invalid_use_of_protected_member\n\nimport 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\n\nclass FollowUserController extends BasePageController<FollowUser> {\n  StreamSubscription<dynamic>? onUpdatedIndexedStream;\n  StreamSubscription<dynamic>? onUpdatedListStream;\n\n  /// 0:全部 1:直播中 2:未直播\n  var filterMode = FollowUserTag(id: \"0\", tag: \"全部\", userId: []).obs;\n  RxList<FollowUserTag> tagList = [\n    FollowUserTag(id: \"0\", tag: \"全部\", userId: []),\n    FollowUserTag(id: \"1\", tag: \"直播中\", userId: []),\n    FollowUserTag(id: \"2\", tag: \"未开播\", userId: []),\n  ].obs;\n\n  // 用户自定义标签\n  RxList<FollowUserTag> userTagList = <FollowUserTag>[].obs;\n\n  // 用户自定义显示顺序 - default：watchDuration\n  Rx<SortMethod> sortMethod = SortMethod.watchDuration.obs;\n\n  // 排序方式\n  var sortMap = {\n    SortMethod.watchDuration: \"观看时长\",\n    SortMethod.siteId: \"直播平台\",\n    SortMethod.recently: \"最近添加\",\n    SortMethod.userNameASC: \"用户名A-Z\",\n    SortMethod.userNameDESC: \"用户名Z-A\",\n  };\n\n  // 关注列表样式\n  var followStyleMap = {true: \"紧凑模式\", false: \"卡片模式\"};\n\n  @override\n  void onInit() {\n    onUpdatedIndexedStream = EventBus.instance.listen(\n      EventBus.kBottomNavigationBarClicked,\n      (index) {\n        if (index == 1) {\n          scrollToTopOrRefresh();\n        }\n      },\n    );\n    onUpdatedListStream = FollowService.instance.updatedListStream.listen(\n      (event) {\n        updateTagList();\n        filterData();\n      },\n    );\n\n    sortMethod = AppSettingsController.instance.followSortMethod;\n    super.onInit();\n  }\n\n  @override\n  Future refreshData() async {\n    await FollowService.instance.loadData();\n    updateTagList();\n    super.refreshData();\n  }\n\n  @override\n  Future<List<FollowUser>> getData(int page, int pageSize) async {\n    if (page > 1) {\n      return Future.value([]);\n    }\n    if (filterMode.value.tag == \"全部\") {\n      return FollowService.instance.followList.value;\n    } else if (filterMode.value.tag == \"直播中\") {\n      return FollowService.instance.liveList.value;\n    } else if (filterMode.value.tag == \"未开播\") {\n      return FollowService.instance.notLiveList.value;\n    } else {\n      FollowService.instance.filterDataByTag(filterMode.value);\n      return FollowService.instance.curTagFollowList.value;\n    }\n  }\n\n  void updateTagList() {\n    userTagList.assignAll(FollowService.instance.followTagList);\n    tagList.value = tagList.take(3).toList();\n    for (var i in userTagList) {\n      if (!tagList.contains(i)) {\n        tagList.add(i);\n      }\n    }\n  }\n\n  void filterData() {\n    if (filterMode.value.tag == \"全部\") {\n      list.assignAll(FollowService.instance.followList.value);\n    } else if (filterMode.value.tag == \"直播中\") {\n      list.assignAll(FollowService.instance.liveList.value);\n    } else if (filterMode.value.tag == \"未开播\") {\n      list.assignAll(FollowService.instance.notLiveList.value);\n    } else {\n      FollowService.instance.filterDataByTag(filterMode.value);\n      list.assignAll(FollowService.instance.curTagFollowList);\n    }\n  }\n\n  // 用户自定义关注样式\n  Future<void> showFollowStyleDialog() async {\n    var res = await Utils.showMapOptionDialog(\n      title: \"关注样式切换\",\n      followStyleMap,\n      AppSettingsController.instance.followStyleNotGrid.value,\n    );\n    if (res != null) {\n      AppSettingsController.instance.setFollowStyleNotGrid(res);\n    }\n  }\n\n  // 用户自定义顺序dialog\n  Future<void> showSortDialog() async {\n    var res = await Utils.showMapOptionDialog(sortMap, sortMethod.value,\n        title: \"排序方式\");\n    if (res != null) {\n      sortMethod.value = res;\n      AppSettingsController.instance.setFollowSortMethod(sortMethod.value);\n      if (filterMode.value.tag == \"未开播\" ||\n          filterMode.value.tag == \"全部\" ||\n          filterMode.value.tag == \"直播中\") {\n        FollowService.instance.liveListSort();\n      }\n      filterData();\n    }\n  }\n\n  void setFilterMode(FollowUserTag tag) {\n    filterMode.value = tag;\n    filterData();\n  }\n\n  void removeFollow(FollowUser follow) async {\n    var result = await Utils.showAlertDialog(\"确定要取消关注${follow.userName}吗?\",\n        title: \"取消关注\");\n    if (!result) {\n      return;\n    }\n    // 取消关注同时删除标签内的 userId\n    if (follow.tag != \"全部\") {\n      var tag = tagList.firstWhereOrNull((tag) => tag.tag == follow.tag);\n      if (tag != null) {\n        tag.userId.remove(follow.id);\n        updateTag(tag);\n      }\n    }\n    await FollowService.instance.removeFollowUser(follow.id);\n    refreshData();\n  }\n\n  void updateFollow(FollowUser follow) {\n    FollowService.instance.addFollow(follow);\n  }\n\n  void setFollowTag(FollowUser follow, FollowUserTag targetTag) {\n    FollowService.instance.setFollowTag(follow, targetTag);\n    filterData();\n  }\n\n  Future<void> updateTag(FollowUserTag followUserTag) async {\n    await FollowService.instance.updateFollowUserTag(followUserTag);\n  }\n\n  // 弹出底部菜单栏\n  void showBottomMenu(FollowUser item) {\n    Get.bottomSheet(\n      SafeArea(\n        child: Wrap(\n          children: [\n            ListTile(\n              leading: const Icon(Remix.price_tag_3_line),\n              title: const Text('设置标签'),\n              onTap: () {\n                Get.back();\n                setFollowTagDialog(item);\n              },\n            ),\n            ListTile(\n              leading: const Icon(Remix.information_line),\n              title: const Text('查看详情'),\n              onTap: () {\n                Get.back();\n                AppNavigator.toFollowInfo(item);\n              },\n            ),\n          ],\n        ),\n      ),\n      backgroundColor: Get.theme.cardColor,\n    );\n  }\n\n  void setFollowTagDialog(FollowUser follow) {\n    /// 控制单选ui\n    List<FollowUserTag> copiedList = [\n      tagList.first,\n      ...tagList.skip(3),\n    ];\n    Rx<FollowUserTag> checkTag = tagList.indexOf(filterMode.value) < 3\n        ? copiedList.first.obs\n        : filterMode.value.obs;\n    final ScrollController scrollController = ScrollController();\n    Get.dialog(\n      AlertDialog(\n        contentPadding: const EdgeInsets.all(16.0),\n        shape: RoundedRectangleBorder(\n          borderRadius: BorderRadius.circular(12.0),\n        ),\n        content: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            // 标题栏\n            Row(\n              mainAxisAlignment: MainAxisAlignment.spaceBetween,\n              children: [\n                const Text(\n                  '设置标签',\n                  style: TextStyle(\n                    fontSize: 18,\n                  ),\n                ),\n                IconButton(\n                  icon: const Icon(\n                    Icons.check,\n                  ),\n                  onPressed: () {\n                    setFollowTag(follow, checkTag.value);\n                    Get.back();\n                  },\n                ),\n              ],\n            ),\n            const Divider(),\n            Obx(\n              () {\n                int selectedIndex = copiedList.indexOf(checkTag.value);\n                WidgetsBinding.instance.addPostFrameCallback((_) {\n                  if (selectedIndex >= 0) {\n                    scrollController.animateTo(\n                      selectedIndex * 60.0, // 假设每项高度为 60\n                      duration: const Duration(milliseconds: 300),\n                      curve: Curves.easeInOut,\n                    );\n                  }\n                });\n                return SizedBox(\n                  height: 300,\n                  width: 300,\n                  child: RadioGroup<FollowUserTag>(\n                    groupValue: checkTag.value,\n                    onChanged: (value) {\n                      checkTag.value = value!;\n                    },\n                    child: ListView.builder(\n                      controller: scrollController,\n                      itemCount: copiedList.length,\n                      itemBuilder: (context, index) {\n                        var tagItem = copiedList[index];\n                        return Container(\n                          decoration: BoxDecoration(\n                            border: Border(\n                              bottom: BorderSide(\n                                  color: Colors.grey.shade300, width: 1.0),\n                            ),\n                          ),\n                          child: RadioListTile<FollowUserTag>(\n                            title: Text(tagItem.tag),\n                            value: tagItem,\n                          ),\n                        );\n                      },\n                    ),\n                  ),\n                );\n              },\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  @override\n  void onClose() {\n    onUpdatedIndexedStream?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/follow_user/follow_user_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_user_controller.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/widgets/filter_button.dart';\nimport 'package:simple_live_app/widgets/follow_user_item.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/live_room_card.dart';\nimport 'package:simple_live_app/widgets/page_grid_view.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass FollowUserPage extends GetView<FollowUserController> {\n  const FollowUserPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    var count = MediaQuery.of(context).size.width ~/ 500;\n    if (count < 1) count = 1;\n    var c = MediaQuery.of(context).size.width ~/ 200;\n    if (c < 2) {\n      c = 2;\n    }\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"关注用户\"),\n        actions: [\n          PopupMenuButton(\n            itemBuilder: (context) {\n              return const [\n                PopupMenuItem(\n                  value: 0,\n                  child: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      Icon(Remix.trophy_line),\n                      AppStyle.hGap12,\n                      Text(\"赛事订阅\"),\n                    ],\n                  ),\n                ),\n                PopupMenuItem(\n                  value: 1,\n                  child: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      Icon(Remix.blender_line),\n                      AppStyle.hGap12,\n                      Text(\"模式切换\"),\n                    ],\n                  ),\n                ),\n                PopupMenuItem(\n                  value: 2,\n                  child: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      Icon(Remix.sort_asc),\n                      AppStyle.hGap12,\n                      Text(\"按序排列\"),\n                    ],\n                  ),\n                ),\n                PopupMenuItem(\n                  value: 4,\n                  child: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      Icon(Remix.heart_line),\n                      AppStyle.hGap12,\n                      Text(\"关注设置\"),\n                    ],\n                  ),\n                ),\n              ];\n            },\n            onSelected: (value) {\n              if (value == 4) {\n                Get.toNamed(RoutePath.kSettingsFollow);\n              } else if (value == 0) {\n                SmartDialog.showToast(\"此功能暂未开放！敬请期待！\");\n              } else if (value == 1) {\n                controller.showFollowStyleDialog();\n              } else if (value == 2) {\n                controller.showSortDialog();\n              }\n            },\n          ),\n        ],\n        leading: Obx(\n          () => FollowService.instance.updating.value\n              ? const IconButton(\n                  onPressed: null,\n                  icon: SizedBox(\n                    width: 16,\n                    height: 16,\n                    child: CircularProgressIndicator(\n                      strokeWidth: 2,\n                    ),\n                  ),\n                )\n              : IconButton(\n                  onPressed: () {\n                    controller.refreshData();\n                  },\n                  icon: const Icon(Icons.refresh),\n                ),\n        ),\n      ),\n      body: Column(\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsL8,\n            child: Row(\n              children: [\n                Expanded(\n                  child: Obx(\n                        () =>\n                        SingleChildScrollView(\n                          scrollDirection: Axis.horizontal,\n                          child: Wrap(\n                            spacing: 12,\n                            children: controller.tagList.map(\n                                  (option) {\n                                return FilterButton(\n                                  text: option.tag,\n                                  selected: controller.filterMode.value ==\n                                      option,\n                                  onTap: () {\n                                    controller.setFilterMode(option);\n                                  },\n                                );\n                              },\n                            ).toList(),\n                          ),\n                        ),\n                  ),\n                ),\n              ],\n            ),\n          ),\n          Obx(\n                () =>\n                Expanded(\n                  child: AppSettingsController.instance.followStyleNotGrid.value\n                      ? PageGridView(\n                    crossAxisSpacing: 12,\n                    crossAxisCount: count,\n                    pageController: controller,\n                    firstRefresh: true,\n                    showPCRefreshButton: false,\n                    itemBuilder: (_, i) {\n                      var item = controller.list[i];\n                      var site = Sites.allSites[item.siteId]!;\n                      return FollowUserItem(\n                        item: item,\n                        onRemove: () {\n                          controller.removeFollow(item);\n                        },\n                        onTap: () {\n                          AppNavigator.toLiveRoomDetail(\n                              site: site, roomId: item.roomId);\n                        },\n                        onLongPress: () {\n                          // 长按弹出操作：设置标签或查看详情\n                          controller.showBottomMenu(item);\n                        },\n                      );\n                    },\n                  )\n                      : KeepAliveWrapper(\n                    child: PageGridView(\n                      pageController: controller,\n                      padding: AppStyle.edgeInsetsA12,\n                      firstRefresh: true,\n                      mainAxisSpacing: 12,\n                      crossAxisSpacing: 12,\n                      crossAxisCount: c,\n                      itemBuilder: (_, i) {\n                        var item = controller.list[i];\n                        // 或许直接继承字段更好，标记工作\n                        LiveRoomItem liveRoomItem = LiveRoomItem(\n                          roomId: item.roomId,\n                          title: item.title.value,\n                          cover: item.cover.value,\n                          userName: item.userName,\n                          online: item.online.value,\n                        );\n                        var site = Sites.allSites[item.siteId]!;\n                          return LiveRoomCard(\n                            site,\n                            liveRoomItem,\n                            onLongPress: () {\n                              controller.showBottomMenu(item);\n                            },\n                          );\n                      },\n                    ),\n                  ),\n                ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/home/home_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/home/home_list_controller.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\n\nclass HomeController extends GetxController\n    with GetSingleTickerProviderStateMixin {\n  late TabController tabController;\n  HomeController() {\n    tabController =\n        TabController(length: Sites.supportSites.length, vsync: this);\n  }\n\n  StreamSubscription<dynamic>? streamSubscription;\n\n  @override\n  void onInit() {\n    streamSubscription = EventBus.instance.listen(\n      EventBus.kBottomNavigationBarClicked,\n      (index) {\n        if (index == 0) {\n          refreshOrScrollTop();\n        }\n      },\n    );\n    for (var site in Sites.supportSites) {\n      Get.put(HomeListController(site), tag: site.id);\n    }\n\n    super.onInit();\n  }\n\n  void refreshOrScrollTop() {\n    var tabIndex = tabController.index;\n    BasePageController controller;\n    controller =\n        Get.find<HomeListController>(tag: Sites.supportSites[tabIndex].id);\n    controller.scrollToTopOrRefresh();\n  }\n\n  void toSearch() {\n    Get.toNamed(RoutePath.kSearch);\n  }\n\n  @override\n  void onClose() {\n    streamSubscription?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/home/home_list_controller.dart",
    "content": "import 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass HomeListController extends BasePageController<LiveRoomItem> {\n  final Site site;\n  HomeListController(this.site);\n\n  @override\n  Future<List<LiveRoomItem>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getRecommendRooms(page: page);\n\n    return result.items;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/home/home_list_view.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/home/home_list_controller.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/live_room_card.dart';\nimport 'package:simple_live_app/widgets/page_grid_view.dart';\n\nclass HomeListView extends StatelessWidget {\n  final String tag;\n  const HomeListView(this.tag, {super.key});\n  HomeListController get controller => Get.find<HomeListController>(tag: tag);\n  @override\n  Widget build(BuildContext context) {\n    var c = MediaQuery.of(context).size.width ~/ 200;\n    if (c < 2) {\n      c = 2;\n    }\n    return KeepAliveWrapper(\n      child: PageGridView(\n        pageController: controller,\n        padding: AppStyle.edgeInsetsA12,\n        firstRefresh: true,\n        mainAxisSpacing: 12,\n        crossAxisSpacing: 12,\n        crossAxisCount: c,\n        itemBuilder: (_, i) {\n          var item = controller.list[i];\n          return LiveRoomCard(controller.site, item);\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/home/home_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/home/home_controller.dart';\nimport 'package:simple_live_app/modules/home/home_list_view.dart';\n\nclass HomePage extends GetView<HomeController> {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        titleSpacing: 8,\n        title: TabBar(\n          controller: controller.tabController,\n          labelPadding: AppStyle.edgeInsetsH20,\n          isScrollable: true,\n          indicatorSize: TabBarIndicatorSize.label,\n          tabAlignment: TabAlignment.center,\n          tabs: Sites.supportSites\n              .map(\n                (e) => Tab(\n                  //text: e.name,\n\n                  child: Row(\n                    children: [\n                      Image.asset(\n                        e.logo,\n                        width: 24,\n                      ),\n                      AppStyle.hGap8,\n                      Text(e.name),\n                    ],\n                  ),\n                ),\n              )\n              .toList(),\n        ),\n        actions: [\n          IconButton(\n            onPressed: controller.toSearch,\n            icon: const Icon(Icons.search),\n          )\n        ],\n      ),\n      body: TabBarView(\n        controller: controller.tabController,\n        children: Sites.supportSites\n            .map(\n              (e) => HomeListView(\n                e.id,\n              ),\n            )\n            .toList(),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/indexed/indexed_controller.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/category/category_controller.dart';\nimport 'package:simple_live_app/modules/category/category_page.dart';\nimport 'package:simple_live_app/modules/home/home_controller.dart';\nimport 'package:simple_live_app/modules/home/home_page.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_user_controller.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_user_page.dart';\nimport 'package:simple_live_app/modules/mine/mine_page.dart';\n\nclass IndexedController extends GetxController {\n  RxList<HomePageItem> items = RxList<HomePageItem>([]);\n\n  var index = 0.obs;\n  RxList<Widget> pages = RxList<Widget>([\n    const SizedBox(),\n    const SizedBox(),\n    const SizedBox(),\n    const SizedBox(),\n  ]);\n\n  void setIndex(int i) {\n    if (pages[i] is SizedBox) {\n      switch (items[i].index) {\n        case 0:\n          Get.put(HomeController());\n          pages[i] = const HomePage();\n          break;\n        case 1:\n          Get.put(FollowUserController());\n          pages[i] = const FollowUserPage();\n          break;\n        case 2:\n          Get.put(CategoryController());\n          pages[i] = const CategoryPage();\n          break;\n        case 3:\n          pages[i] = const MinePage();\n          break;\n        default:\n      }\n    } else {\n      if (index.value == i) {\n        EventBus.instance\n            .emit<int>(EventBus.kBottomNavigationBarClicked, items[i].index);\n      }\n    }\n\n    index.value = i;\n  }\n\n  @override\n  void onInit() {\n    Future.delayed(Duration.zero, showFirstRun);\n    items.value = AppSettingsController.instance.homeSort\n        .map((key) => Constant.allHomePages[key]!)\n        .toList();\n    setIndex(0);\n    super.onInit();\n  }\n\n  void showFirstRun() async {\n    var settingsController = Get.find<AppSettingsController>();\n    if (settingsController.firstRun) {\n      settingsController.setNoFirstRun();\n      await Utils.showStatement();\n      Utils.checkUpdate();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/indexed/indexed_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nimport 'indexed_controller.dart';\n\nclass IndexedPage extends GetView<IndexedController> {\n  const IndexedPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return OrientationBuilder(\n      builder: (context, orientation) {\n        return Scaffold(\n          body: Row(\n            children: [\n              Visibility(\n                visible: orientation == Orientation.landscape,\n                child: Obx(\n                  () => NavigationRail(\n                    selectedIndex: controller.index.value,\n                    onDestinationSelected: controller.setIndex,\n                    labelType: NavigationRailLabelType.none,\n                    destinations: controller.items\n                        .map(\n                          (item) => NavigationRailDestination(\n                            icon: Icon(item.iconData),\n                            label: Text(item.title),\n                            padding: AppStyle.edgeInsetsV8,\n                          ),\n                        )\n                        .toList(),\n                  ),\n                ),\n              ),\n              Expanded(\n                child: Obx(\n                  () => Container(\n                    decoration: BoxDecoration(\n                      border: Border(\n                        left: orientation == Orientation.landscape\n                            ? BorderSide(\n                                color: Colors.grey.withAlpha(50),\n                                width: 1,\n                              )\n                            : BorderSide.none,\n                      ),\n                    ),\n                    child: IndexedStack(\n                      index: controller.index.value,\n                      children: controller.pages,\n                    ),\n                  ),\n                ),\n              ),\n            ],\n          ),\n          bottomNavigationBar: Visibility(\n            visible: orientation == Orientation.portrait,\n            child: Obx(\n              () => NavigationBar(\n                selectedIndex: controller.index.value,\n                onDestinationSelected: controller.setIndex,\n                height: 56,\n                labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,\n                destinations: controller.items\n                    .map(\n                      (item) => NavigationDestination(\n                        icon: Icon(item.iconData),\n                        label: item.title,\n                      ),\n                    )\n                    .toList(),\n              ),\n            ),\n          ),\n        );\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/live_room/danmu/danmaku_mask.dart",
    "content": "import 'dart:async';\nimport 'dart:isolate';\nimport 'dart:math';\n\n// 通过滑动窗口、分桶、哈希去重的弹幕屏蔽器\n// 原理类似于mask,单位时间内已有弹幕占据过滤矩阵，过滤重复弹幕\n// 通过滑动窗口，实现弹幕time to live策略\n// 直接使用会造成开屏时卡UI线程\nclass DanmakuMask {\n  final int baseWindowMs;\n  final int bucketCount;\n  final bool useNormalization;\n  final bool useFrequencyControl;\n  final int maxFrequency;\n  final bool adaptiveWindow;\n\n  late int _windowMs;\n  late int _bucketSizeMs;\n\n  int _currentBucket = 0;\n  int _lastShiftMs = 0;\n\n  late final List<Set<int>> _buckets;\n  final Map<int, int> _freqMap = {};\n\n  DanmakuMask({\n    this.baseWindowMs = 5000,\n    this.bucketCount = 5,\n    this.useNormalization = false,\n    this.useFrequencyControl = false,\n    this.maxFrequency = 3,\n    this.adaptiveWindow = false,\n  }) {\n    _windowMs = baseWindowMs;\n    _bucketSizeMs = _windowMs ~/ bucketCount;\n    _buckets = List.generate(bucketCount, (_) => <int>{});\n  }\n\n  String _normalize(String text) {\n    if (!useNormalization) return text;\n    return text\n        .trim()\n        .replaceAll(RegExp(r\"\\s+\"), \"\")\n        .replaceAll(RegExp(r\"[~!！?？,.，。]\"), \"\")\n        .toLowerCase();\n  }\n\n  void _shiftIfNeeded(int nowMs) {\n    while (nowMs - _lastShiftMs >= _bucketSizeMs) {\n      _lastShiftMs += _bucketSizeMs;\n\n      _currentBucket = (_currentBucket + 1) % bucketCount;\n\n      final expiredBucket = _buckets[_currentBucket];\n      for (final hash in expiredBucket) {\n        _freqMap[hash] = (_freqMap[hash] ?? 1) - 1;\n        if (_freqMap[hash]! <= 0) {\n          _freqMap.remove(hash);\n        }\n      }\n\n      expiredBucket.clear();\n    }\n  }\n\n  void _adaptWindow() {\n    if (!adaptiveWindow) return;\n\n    final totalItems = _buckets.fold<int>(0, (sum, b) => sum + b.length);\n\n    if (totalItems > 300) {\n      _windowMs = max(baseWindowMs ~/ 2, 1500);\n    } else if (totalItems < 50) {\n      _windowMs = baseWindowMs;\n    }\n\n    _bucketSizeMs = _windowMs ~/ bucketCount;\n  }\n\n  // 替换为List传递消息，减少线程间通信开销\n  List<bool> allowList(List<String> texts, int nowMs) {\n    _shiftIfNeeded(nowMs);\n    _adaptWindow();\n\n    final results = <bool>[];\n    for (String text in texts) {\n      final normalizedText = _normalize(text);\n      final hash = normalizedText.hashCode;\n      var isAllowed = true;\n\n      for (final bucket in _buckets) {\n        if (bucket.contains(hash)) {\n          isAllowed = false;\n          break;\n        }\n      }\n\n      if (isAllowed && useFrequencyControl) {\n        final freq = _freqMap[hash] ?? 0;\n        if (freq >= maxFrequency) {\n          isAllowed = false;\n        }\n      }\n\n      if (isAllowed) {\n        _buckets[_currentBucket].add(hash);\n        _freqMap[hash] = (_freqMap[hash] ?? 0) + 1;\n      }\n\n      results.add(isAllowed);\n    }\n    return results;\n  }\n\n  void reset() {\n    for (var b in _buckets) {\n      b.clear();\n    }\n    _freqMap.clear();\n    _currentBucket = 0;\n    _lastShiftMs = 0;\n    _windowMs = baseWindowMs;\n    _bucketSizeMs = _windowMs ~/ bucketCount;\n  }\n\n  // 基于动态规划的 Levenshtein 距离 计算，用于文本相似度计算，暂时搁置\n  int _editDistance(String a, String b) {\n    final m = a.length;\n    final n = b.length;\n    List<List<int>> dp = List.generate(m + 1, (_) => List.filled(n + 1, 0));\n\n    for (int i = 0; i <= m; i++) {\n      dp[i][0] = i;\n    }\n    for (int j = 0; j <= n; j++) {\n      dp[0][j] = j;\n    }\n\n    for (int i = 1; i < m + 1; i++) {\n      for (int j = 1; j < n + 1; j++) {\n        if (a[i - 1] == b[j - 1]) {\n          dp[i][j] = dp[i - 1][j - 1];\n        } else {\n          dp[i][j] = 1 +\n              min(\n                dp[i - 1][j - 1],\n                min(dp[i][j - 1], dp[i - 1][j]),\n              );\n        }\n      }\n    }\n    return dp[m][n];\n  }\n}\n\n// Isolate\nclass IsolateDanmakuMask {\n  late final SendPort _isolateSendPort;\n  final _mainReceivePort = ReceivePort();\n  late final Isolate _isolate;\n\n  final Map<int, Completer<dynamic>> _pendingRequests = {};\n  int _requestId = 0;\n\n  IsolateDanmakuMask._();\n\n  static Future<IsolateDanmakuMask> create({\n    int baseWindowMs = 15000,\n    int bucketCount = 15,\n    bool useNormalization = false,\n    bool useFrequencyControl = false,\n    int maxFrequency = 3,\n    bool adaptiveWindow = false,\n  }) async {\n    final mask = IsolateDanmakuMask._();\n    await mask._init(\n      baseWindowMs: baseWindowMs,\n      bucketCount: bucketCount,\n      useNormalization: useNormalization,\n      useFrequencyControl: useFrequencyControl,\n      maxFrequency: maxFrequency,\n      adaptiveWindow: adaptiveWindow,\n    );\n    return mask;\n  }\n\n  Future<void> _init({\n    required int baseWindowMs,\n    required int bucketCount,\n    required bool useNormalization,\n    required bool useFrequencyControl,\n    required int maxFrequency,\n    required bool adaptiveWindow,\n  }) async {\n    final initCompleter = Completer<void>();\n\n    _mainReceivePort.listen((message) {\n      if (message is SendPort) {\n        _isolateSendPort = message;\n        if (!initCompleter.isCompleted) {\n          initCompleter.complete();\n        }\n      } else if (message is List) {\n        final id = message[0] as int;\n        final result = message[1];\n        _pendingRequests.remove(id)?.complete(result);\n      }\n    });\n\n    final params = {\n      'baseWindowMs': baseWindowMs,\n      'bucketCount': bucketCount,\n      'useNormalization': useNormalization,\n      'useFrequencyControl': useFrequencyControl,\n      'maxFrequency': maxFrequency,\n      'adaptiveWindow': adaptiveWindow,\n    };\n\n    _isolate = await Isolate.spawn(\n      _danmakuIsolateEntryPoint,\n      [_mainReceivePort.sendPort, params],\n    );\n\n    return initCompleter.future;\n  }\n\n  Future<List<bool>> allowList(List<String> texts, int nowMs) {\n    final id = _requestId++;\n    final completer = Completer<List<bool>>();\n    _pendingRequests[id] = completer;\n    _isolateSendPort.send(['allowList', id, texts, nowMs]);\n    return completer.future;\n  }\n\n  void reset() {\n    _isolateSendPort.send(['reset']);\n  }\n\n  void dispose() {\n    _isolateSendPort.send(['dispose']);\n    _mainReceivePort.close();\n    _isolate.kill(priority: Isolate.immediate);\n  }\n}\n\nvoid _danmakuIsolateEntryPoint(List<dynamic> initialMessage) {\n  final mainSendPort = initialMessage[0] as SendPort;\n  final params = initialMessage[1] as Map<String, dynamic>;\n\n  final danmakuMask = DanmakuMask(\n    baseWindowMs: params['baseWindowMs'],\n    bucketCount: params['bucketCount'],\n    useNormalization: params['useNormalization'],\n    useFrequencyControl: params['useFrequencyControl'],\n    maxFrequency: params['maxFrequency'],\n    adaptiveWindow: params['adaptiveWindow'],\n  );\n\n  final isolateReceivePort = ReceivePort();\n  mainSendPort.send(isolateReceivePort.sendPort);\n\n  isolateReceivePort.listen((message) {\n    if (message is! List) return;\n\n    final command = message[0] as String;\n    switch (command) {\n      case 'allowList':\n        final id = message[1] as int;\n        final texts = (message[2] as List).cast<String>();\n        final nowMs = message[3] as int;\n        final List<bool> allowedList = danmakuMask.allowList(texts, nowMs);\n        mainSendPort.send([id, allowedList]);\n        break;\n      case 'reset':\n        danmakuMask.reset();\n        break;\n      case 'dispose':\n        isolateReceivePort.close();\n        break;\n    }\n  });\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/live_room/live_room_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:io';\n\nimport 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:connectivity_plus/connectivity_plus.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:share_plus/share_plus.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/sandbox.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/modules/live_room/player/player_controller.dart';\nimport 'package:simple_live_app/modules/settings/danmu_settings_page.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/services/history_service.dart';\nimport 'package:simple_live_app/src/rust/api/danmaku_mask.dart';\nimport 'package:simple_live_app/widgets/desktop_refresh_button.dart';\nimport 'package:simple_live_app/widgets/follow_user_item.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:url_launcher/url_launcher.dart';\nimport 'package:url_launcher/url_launcher_string.dart';\nimport 'package:wakelock_plus/wakelock_plus.dart';\n\nclass LiveRoomController extends PlayerController with WidgetsBindingObserver {\n  final Site pSite;\n  final String pRoomId;\n  late LiveDanmaku liveDanmaku;\n  late DanmakuMask rustDanmakuMask;\n\n\n  List<LiveMessage> danmakuBuffer = [];\n  Timer? danmakuTimer;\n  bool _isProcessingBuffer = false;\n\n  LiveRoomController({\n    required this.pSite,\n    required this.pRoomId,\n  }) {\n    rxSite = pSite.obs;\n    rxRoomId = pRoomId.obs;\n    liveDanmaku = site.liveSite.getDanmaku();\n    // 抖音应该默认是竖屏的\n    if (site.id == \"douyin\") {\n      isVertical.value = true;\n    }\n  }\n\n  late Rx<Site> rxSite;\n  Site get site => rxSite.value;\n  late Rx<String> rxRoomId;\n  String get roomId => rxRoomId.value;\n\n  Rx<LiveRoomDetail?> detail = Rx<LiveRoomDetail?>(null);\n  var online = 0.obs;\n  var followed = false.obs;\n  var liveStatus = false.obs;\n  RxList<LiveSuperChatMessage> superChats = RxList<LiveSuperChatMessage>();\n\n  /// 滚动控制\n  final ScrollController scrollController = ScrollController();\n\n  /// 聊天信息\n  RxList<LiveMessage> messages = RxList<LiveMessage>();\n\n  /// 清晰度数据\n  RxList<LivePlayQuality> qualites = RxList<LivePlayQuality>();\n\n  /// 当前清晰度\n  var currentQuality = -1;\n  var currentQualityInfo = \"\".obs;\n\n  /// 线路数据\n  RxList<String> playUrls = RxList<String>();\n\n  Map<String, String>? playHeaders;\n\n  /// 当前线路\n  var currentLineIndex = -1;\n  var currentLineInfo = \"\".obs;\n\n  /// 退出倒计时\n  var countdown = 60.obs;\n\n  Timer? autoExitTimer;\n\n  /// 设置的自动关闭时间（分钟）\n  var autoExitMinutes = 60.obs;\n\n  ///是否延迟自动关闭\n  var delayAutoExit = false.obs;\n\n  /// 是否启用自动关闭\n  var autoExitEnable = false.obs;\n\n  /// 是否禁用自动滚动聊天栏\n  /// - 当用户向上滚动聊天栏时，不再自动滚动\n  var disableAutoScroll = false.obs;\n\n  /// 是否处于后台\n  var isBackground = false;\n\n  /// 直播间加载失败\n  var loadError = false.obs;\n  Error? error;\n\n  @override\n  void onInit() {\n    WidgetsBinding.instance.addObserver(this);\n    if (FollowService.instance.followList.isEmpty) {\n      FollowService.instance.loadData();\n    }\n    initAutoExit();\n    showDanmakuState.value = AppSettingsController.instance.danmuEnable.value;\n    followed.value =\n        FollowService.instance.getFollowExist(\"${site.id}_$roomId\");\n    loadData();\n\n    scrollController.addListener(scrollListener);\n\n    _initDanmakuMask();\n    super.onInit();\n  }\n\n  void _initDanmakuMask() async {\n    rustDanmakuMask = DanmakuMask(\n      baseWindowMs: AppSettingsController.instance.danmuWindowMs.value * 1000,\n      bucketCount: AppSettingsController.instance.danmuWindowMs.value,\n      useNormalization:\n          AppSettingsController.instance.danmuTextNormalization.value,\n      useFrequencyControl:\n          AppSettingsController.instance.danmuFrequencyControl.value,\n      maxFrequency: AppSettingsController.instance.danmuMaxFrequency.value,\n      adaptiveWindow: false,\n    );\n    danmakuTimer = Timer.periodic(\n      const Duration(milliseconds: 500),\n      (timer) {\n        _processDanmakuBuffer();\n      },\n    );\n  }\n\n  // 缓存降低跨线程消息开销 估算弹幕延迟在800ms左右\n  void _processDanmakuBuffer() async {\n    if (_isProcessingBuffer) return;\n    if (danmakuBuffer.isEmpty) return;\n\n    _isProcessingBuffer = true;\n    try {\n      final batch = List<LiveMessage>.from(danmakuBuffer);\n      danmakuBuffer.clear();\n\n      final batchMessages = batch.map((e) => e.message).toList();\n      final nowMs = DateTime.now().millisecondsSinceEpoch;\n      final allowedResults = await rustDanmakuMask.allowListBatch(texts: batchMessages, nowMs: BigInt.from(nowMs));\n\n      final filteredBatch = <LiveMessage>[];\n      for (int i = 0; i < batch.length; i++) {\n        if (allowedResults[i] == 1) {\n          filteredBatch.add(batch[i]);\n        }\n      }\n\n      if (filteredBatch.isEmpty) return;\n\n      messages.addAll(filteredBatch);\n      if (messages.length > 200 && !disableAutoScroll.value) {\n        messages.removeRange(0, messages.length - 200);\n      }\n\n      WidgetsBinding.instance.addPostFrameCallback(\n        (_) => chatScrollToBottom(),\n      );\n      if (!liveStatus.value || isBackground) {\n        return;\n      }\n\n      addDanmaku(filteredBatch\n          .map((msg) => DanmakuContentItem(\n                msg.message,\n                color: Color.fromARGB(\n                  255,\n                  msg.color.r,\n                  msg.color.g,\n                  msg.color.b,\n                ),\n              ))\n          .toList());\n    } finally {\n      _isProcessingBuffer = false;\n    }\n  }\n\n  void scrollListener() {\n    if (scrollController.position.userScrollDirection ==\n        ScrollDirection.forward) {\n      disableAutoScroll.value = true;\n    }\n  }\n\n  /// 初始化自动关闭倒计时\n  void initAutoExit() {\n    if (AppSettingsController.instance.autoExitEnable.value) {\n      autoExitEnable.value = true;\n      autoExitMinutes.value =\n          AppSettingsController.instance.autoExitDuration.value;\n      setAutoExit();\n    } else {\n      autoExitMinutes.value =\n          AppSettingsController.instance.roomAutoExitDuration.value;\n    }\n  }\n\n  void setAutoExit() {\n    if (!autoExitEnable.value) {\n      autoExitTimer?.cancel();\n      return;\n    }\n    autoExitTimer?.cancel();\n    countdown.value = autoExitMinutes.value * 60;\n    autoExitTimer = Timer.periodic(const Duration(seconds: 1), (timer) async {\n      countdown.value -= 1;\n      if (countdown.value <= 0) {\n        timer = Timer(const Duration(seconds: 10), () async {\n          await WakelockPlus.disable();\n          exit(0);\n        });\n        autoExitTimer?.cancel();\n        var delay = await Utils.showAlertDialog(\"定时关闭已到时,是否延迟关闭?\",\n            title: \"延迟关闭\", confirm: \"延迟\", cancel: \"关闭\", selectable: true);\n        if (delay) {\n          timer.cancel();\n          delayAutoExit.value = true;\n          showAutoExitSheet();\n          setAutoExit();\n        } else {\n          delayAutoExit.value = false;\n          await WakelockPlus.disable();\n          exit(0);\n        }\n      }\n    });\n  }\n  // 弹窗逻辑\n\n  void refreshRoom() {\n    //messages.clear();\n    superChats.clear();\n    liveDanmaku.stop();\n\n    loadData();\n  }\n\n  /// 聊天栏始终滚动到底部\n  void chatScrollToBottom() {\n    if (scrollController.hasClients) {\n      // 如果手动上拉过，就不自动滚动到底部\n      if (disableAutoScroll.value) {\n        return;\n      }\n      scrollController.jumpTo(scrollController.position.maxScrollExtent);\n    }\n  }\n\n  /// 初始化弹幕接收事件\n  void initDanmau() {\n    liveDanmaku.onMessage = onWSMessage;\n    liveDanmaku.onClose = onWSClose;\n    liveDanmaku.onReady = onWSReady;\n  }\n\n  /// 接收到WebSocket信息\n  void onWSMessage(LiveMessage msg) async {\n    if (msg.type == LiveMessageType.chat) {\n      // 关键词屏蔽检查\n      for (var keyword in AppSettingsController.instance.shieldList) {\n        Pattern? pattern;\n        if (Utils.isRegexFormat(keyword)) {\n          String removedSlash = Utils.removeRegexFormat(keyword);\n          try {\n            pattern = RegExp(removedSlash);\n          } catch (e) {\n            // should avoid this during add keyword\n            Log.d(\"关键词：$keyword 正则格式错误\");\n          }\n        } else {\n          pattern = keyword;\n        }\n        if (pattern != null && msg.message.contains(pattern)) {\n          Log.d(\"关键词：$keyword\\n已屏蔽消息内容：${msg.message}\");\n          return;\n        }\n      }\n\n      //  messages.length>n 预加载部分弹幕后启用去重功能\n      if (AppSettingsController.instance.danmakuMaskEnable.value&&\n          messages.length > 50) {\n        danmakuBuffer.add(msg);\n      } else {\n        if (messages.length > 200 && !disableAutoScroll.value) {\n          messages.removeAt(0);\n        }\n        messages.add(msg);\n        WidgetsBinding.instance.addPostFrameCallback(\n          (_) => chatScrollToBottom(),\n        );\n        if (!liveStatus.value || isBackground) {\n          return;\n        }\n\n        addDanmaku([\n          DanmakuContentItem(\n            msg.message,\n            color: Color.fromARGB(\n              255,\n              msg.color.r,\n              msg.color.g,\n              msg.color.b,\n            ),\n          ),\n        ]);\n      }\n    } else if (msg.type == LiveMessageType.online) {\n      online.value = msg.data;\n    } else if (msg.type == LiveMessageType.superChat) {\n      superChats.add(msg.data);\n    }\n  }\n\n  /// 添加一条系统消息\n  void addSysMsg(String msg) {\n    messages.add(\n      LiveMessage(\n        type: LiveMessageType.chat,\n        userName: \"LiveSysMessage\",\n        message: msg,\n        color: LiveMessageColor.white,\n      ),\n    );\n  }\n\n  /// 接收到WebSocket关闭信息\n  void onWSClose(String msg) {\n    addSysMsg(msg);\n  }\n\n  /// WebSocket准备就绪\n  void onWSReady() {\n    addSysMsg(\"弹幕服务器连接正常\");\n  }\n\n  /// 加载直播间信息\n  void loadData() async {\n    try {\n      SmartDialog.showLoading(msg: \"\");\n      loadError.value = false;\n      addSysMsg(\"正在读取直播间信息\");\n      detail.value = await site.liveSite.getRoomDetail(roomId: roomId);\n\n      if (site.id == Constant.kDouyin) {\n        // 1.6.0之前收藏的WebRid\n        // 1.6.0收藏的RoomID\n        // 1.6.0之后改回WebRid\n        if (detail.value!.roomId != roomId) {\n          var oldId = roomId;\n          rxRoomId.value = detail.value!.roomId;\n          if (followed.value) {\n            // 更新关注列表\n            DBService.instance.deleteFollow(\"${site.id}_$oldId\");\n            DBService.instance.addFollow(\n              FollowUser(\n                id: \"${site.id}_$roomId\",\n                roomId: roomId,\n                siteId: site.id,\n                userName: detail.value!.userName,\n                face: detail.value!.userAvatar,\n                addTime: DateTime.now(),\n              ),\n            );\n          } else {\n            followed.value =\n                DBService.instance.getFollowExist(\"${site.id}_$roomId\");\n          }\n        }\n      }\n\n      getSuperChatMessage();\n\n      addHistory();\n      // 确认房间关注状态\n      followed.value =\n          FollowService.instance.getFollowExist(\"${site.id}_$roomId\");\n      online.value = detail.value!.online;\n      liveStatus.value = detail.value!.status || detail.value!.isRecord;\n      if (liveStatus.value) {\n        getPlayQualites();\n        addSysMsg(\"开始连接弹幕服务器\");\n        initDanmau();\n        liveDanmaku.start(detail.value?.danmakuData);\n      }\n      if (detail.value!.isRecord) {\n        addSysMsg(\"当前主播未开播，正在轮播录像\");\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      //SmartDialog.showToast(e.toString());\n      loadError.value = true;\n      if(e is Error){\n        error = e;\n      }\n    } finally {\n      SmartDialog.dismiss(status: SmartStatus.loading);\n    }\n  }\n\n  /// 初始化播放器\n  void getPlayQualites() async {\n    currentQuality = -1;\n\n    try {\n      var playQualites =\n          await site.liveSite.getPlayQualites(detail: detail.value!);\n\n      if (playQualites.isEmpty) {\n        SmartDialog.showToast(\"无法读取播放清晰度\");\n        return;\n      }\n      qualites.assignAll(playQualites);\n      var qualityLevel = await getQualityLevel();\n      if (qualityLevel == 2) {\n        //最高\n        currentQuality = 0;\n      } else if (qualityLevel == 0) {\n        //最低\n        currentQuality = playQualites.length - 1;\n      } else {\n        //中间值\n        int middle = (playQualites.length / 2).floor();\n        currentQuality = middle;\n      }\n      await getPlayUrl();\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"无法读取播放清晰度\");\n    }\n  }\n\n  Future<int> getQualityLevel() async {\n    var qualityLevel = AppSettingsController.instance.qualityLevel.value;\n    try {\n      var connectivityResult = await (Connectivity().checkConnectivity());\n      if (connectivityResult.first == ConnectivityResult.mobile) {\n        qualityLevel =\n            AppSettingsController.instance.qualityLevelCellular.value;\n      }\n    } catch (e) {\n      Log.logPrint(e);\n    }\n    return qualityLevel;\n  }\n\n  Future<void> getPlayUrl() async {\n    currentQualityInfo.value = qualites[currentQuality].quality;\n    currentLineInfo.value = \"\";\n    currentLineIndex = -1;\n    var playUrl = await site.liveSite\n        .getPlayUrls(detail: detail.value!, quality: qualites[currentQuality]);\n    if (playUrl.urls.isEmpty) {\n      SmartDialog.showToast(\"无法读取播放地址\");\n      return;\n    }\n    playUrls.assignAll(playUrl.urls); // 深拷贝\n    playHeaders = playUrl.headers;\n    currentLineIndex = 0;\n    currentLineInfo.value = \"线路${currentLineIndex + 1}\";\n    //重置错误次数\n    mediaErrorRetryCount = 0;\n    initPlaylist();\n  }\n\n  void changePlayLine(int index) {\n    currentLineIndex = index;\n    //重置错误次数\n    mediaErrorRetryCount = 0;\n    setPlayer();\n  }\n\n  void initPlaylist() async {\n    currentLineInfo.value = \"线路${currentLineIndex + 1}\";\n    errorMsg.value = \"\";\n\n    final mediaList = playUrls.map((url) {\n      var finalUrl = url;\n      if (AppSettingsController.instance.playerForceHttps.value) {\n        finalUrl = finalUrl.replaceAll(\"http://\", \"https://\");\n      }\n      return Media(finalUrl, httpHeaders: playHeaders);\n    }).toList();\n\n    // 初始化播放器并设置 ao 参数\n    await initializePlayer();\n\n    await player.open(Playlist(mediaList));\n  }\n\n  void setPlayer() async {\n    currentLineInfo.value = \"线路${currentLineIndex + 1}\";\n    errorMsg.value = \"\";\n\n    await player.jump(currentLineIndex);\n  }\n\n  @override\n  void mediaEnd() async {\n    super.mediaEnd();\n    if (mediaErrorRetryCount < 2) {\n      Log.d(\"播放结束，尝试第${mediaErrorRetryCount + 1}次刷新\");\n      if (mediaErrorRetryCount == 1) {\n        //延迟一秒再刷新\n        await Future.delayed(const Duration(seconds: 1));\n      }\n      mediaErrorRetryCount += 1;\n      //刷新一次\n      setPlayer();\n      return;\n    }\n\n    Log.d(\"播放结束\");\n    // 遍历线路，如果全部链接都断开就是直播结束了\n    if (playUrls.length - 1 == currentLineIndex) {\n      liveStatus.value = false;\n    } else {\n      changePlayLine(currentLineIndex + 1);\n\n      //setPlayer();\n    }\n  }\n\n  int mediaErrorRetryCount = 0;\n  @override\n  void mediaError(String error) async {\n    super.mediaEnd();\n    if (mediaErrorRetryCount < 2) {\n      Log.d(\"播放失败，尝试第${mediaErrorRetryCount + 1}次刷新\");\n      if (mediaErrorRetryCount == 1) {\n        //延迟一秒再刷新\n        await Future.delayed(const Duration(seconds: 1));\n      }\n      mediaErrorRetryCount += 1;\n      //刷新一次\n      setPlayer();\n      return;\n    }\n\n    if (playUrls.length - 1 == currentLineIndex) {\n      errorMsg.value = \"播放失败\";\n      SmartDialog.showToast(\"播放失败:$error\");\n    } else {\n      //currentLineIndex += 1;\n      //setPlayer();\n      changePlayLine(currentLineIndex + 1);\n    }\n  }\n\n  /// 读取SC\n  void getSuperChatMessage() async {\n    try {\n      var sc =\n          await site.liveSite.getSuperChatMessage(roomId: detail.value!.roomId);\n      superChats.addAll(sc);\n    } catch (e) {\n      Log.logPrint(e);\n      addSysMsg(\"SC读取失败\");\n    }\n  }\n\n  /// 移除掉已到期的SC\n  void removeSuperChats() async {\n    var now = DateTime.now().millisecondsSinceEpoch;\n    superChats.removeWhere((x) => x.endTime.millisecondsSinceEpoch < now);\n  }\n\n  /// 添加历史记录\n  void addHistory() {\n    if (detail.value == null) {\n      return;\n    }\n    var id = \"${site.id}_$roomId\";\n    History history = History(\n      id: id,\n      roomId: roomId,\n      siteId: site.id,\n      userName: detail.value?.userName ?? \"\",\n      face: detail.value?.userAvatar ?? \"\",\n      updateTime: DateTime.now(),\n    );\n    HistoryService.instance.start(history);\n  }\n\n  /// 关注用户\n  void followUser() {\n    if (detail.value == null) {\n      return;\n    }\n    var id = \"${site.id}_$roomId\";\n    var historyDuration =\n        HistoryService.instance.getHistoryDuration(followUserId: id);\n    FollowService.instance.addFollow(\n      FollowUser(\n        id: id,\n        roomId: roomId,\n        siteId: site.id,\n        userName: detail.value?.userName ?? \"\",\n        face: detail.value?.userAvatar ?? \"\",\n        addTime: DateTime.now(),\n        watchDuration: historyDuration,\n      ),\n    );\n    followed.value = true;\n    EventBus.instance.emit(Constant.kUpdateFollow, id);\n  }\n\n  /// 取消关注用户\n  void removeFollowUser() async {\n    if (detail.value == null) {\n      return;\n    }\n    if (!await Utils.showAlertDialog(\"确定要取消关注该用户吗？\", title: \"取消关注\")) {\n      return;\n    }\n\n    var id = \"${site.id}_$roomId\";\n    FollowService.instance.removeFollowUser(id);\n    followed.value = false;\n    EventBus.instance.emit(Constant.kUpdateFollow, id);\n  }\n\n  void share() {\n    if (detail.value == null) {\n      return;\n    }\n    SharePlus.instance.share(ShareParams(text: detail.value!.url));\n  }\n\n  void copyUrl() {\n    if (detail.value == null) {\n      return;\n    }\n    Utils.copyToClipboard(detail.value!.url);\n    SmartDialog.showToast(\"已复制直播间链接\");\n  }\n\n  Future<void> visitWebLive() async {\n    Uri uri = Uri.parse(detail.value!.url);\n    if (await canLaunchUrl(uri) || runningInSandbox()) {\n      await launchUrl(uri);\n    } else {\n      throw '无法打开网页 $uri';\n    }\n  }\n\n  /// 底部打开播放器设置\n  void showDanmuSettingsSheet() {\n    Utils.showBottomSheet(\n      title: \"弹幕设置\",\n      child: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          DanmuSettingsView(\n            danmakuController: danmakuController,\n            onTapDanmuShield: () {\n              Get.back();\n              showDanmuShield();\n            },\n          ),\n        ],\n      ),\n    );\n  }\n\n  void showVolumeSlider(BuildContext targetContext) {\n    SmartDialog.showAttach(\n      targetContext: targetContext,\n      alignment: Alignment.topCenter,\n      displayTime: const Duration(seconds: 3),\n      maskColor: const Color(0x00000000),\n      builder: (context) {\n        return Container(\n          decoration: BoxDecoration(\n            borderRadius: AppStyle.radius12,\n            color: Theme.of(context).cardColor,\n          ),\n          padding: AppStyle.edgeInsetsA4,\n          child: Obx(\n            () => SizedBox(\n              width: 200,\n              child: Slider(\n                min: 0,\n                max: 100,\n                value: AppSettingsController.instance.playerVolume.value,\n                onChanged: (newValue) {\n                  player.setVolume(newValue);\n                  AppSettingsController.instance.setPlayerVolume(newValue);\n                },\n              ),\n            ),\n          ),\n        );\n      },\n    );\n  }\n\n  void showQualitySheet() {\n    Utils.showBottomSheet(\n      title: \"切换清晰度\",\n      child: RadioGroup(\n        groupValue: currentQuality,\n        onChanged: (e) async {\n          Get.back();\n          currentQuality = e ?? 0;\n          await getPlayUrl();\n        },\n        child: ListView.builder(\n          itemCount: qualites.length,\n          itemBuilder: (_, i) {\n            var item = qualites[i];\n            return RadioListTile(\n              value: i,\n              title: Text(item.quality),\n            );\n          },\n        ),\n      ),\n    );\n  }\n\n  void showPlayUrlsSheet() {\n    Utils.showBottomSheet(\n      title: \"切换线路\",\n      child: RadioGroup(\n        groupValue: currentLineIndex,\n        onChanged: (e) {\n          Get.back();\n          //currentLineIndex = i;\n          //setPlayer();\n          changePlayLine(e ?? 0);\n        },\n        child: ListView.builder(\n          itemCount: playUrls.length,\n          itemBuilder: (_, i) {\n            return RadioListTile(\n              value: i,\n              title: Text(\"线路${i + 1}\"),\n              secondary: Text(\n                playUrls[i].contains(\".flv\") ? \"FLV\" : \"HLS\",\n              ),\n            );\n          },\n        ),\n      ),\n    );\n  }\n\n  void showPlayerSettingsSheet() {\n    Utils.showBottomSheet(\n      title: \"画面尺寸\",\n      child: Obx(\n        () => ListView(\n          padding: AppStyle.edgeInsetsV12,\n          children: [\n            RadioGroup(\n              groupValue: AppSettingsController.instance.scaleMode.value,\n              onChanged: (e) {\n                AppSettingsController.instance.setScaleMode(e ?? 0);\n                updateScaleMode();\n              },\n              child: Column(\n                children: [\n                  RadioListTile(\n                    value: 0,\n                    title: const Text(\"适应\"),\n                    visualDensity: VisualDensity.compact,\n                  ),\n                  RadioListTile(\n                    value: 1,\n                    title: const Text(\"拉伸\"),\n                    visualDensity: VisualDensity.compact,\n                  ),\n                  RadioListTile(\n                    value: 2,\n                    title: const Text(\"铺满\"),\n                    visualDensity: VisualDensity.compact,\n                  ),\n                  RadioListTile(\n                    value: 3,\n                    title: const Text(\"16:9\"),\n                    visualDensity: VisualDensity.compact,\n                  ),\n                  RadioListTile(\n                    value: 4,\n                    title: const Text(\"4:3\"),\n                    visualDensity: VisualDensity.compact,\n                  ),\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  void showDanmuShield() {\n    TextEditingController keywordController = TextEditingController();\n\n    void addKeyword() {\n      if (keywordController.text.isEmpty) {\n        SmartDialog.showToast(\"请输入关键词\");\n        return;\n      }\n\n      AppSettingsController.instance\n          .addShieldList(keywordController.text.trim());\n      keywordController.text = \"\";\n    }\n\n    Utils.showBottomSheet(\n      title: \"关键词屏蔽\",\n      child: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          TextField(\n            controller: keywordController,\n            decoration: InputDecoration(\n              contentPadding: AppStyle.edgeInsetsH12,\n              border: const OutlineInputBorder(),\n              hintText: \"请输入关键词\",\n              suffixIcon: TextButton.icon(\n                onPressed: addKeyword,\n                icon: const Icon(Icons.add),\n                label: const Text(\"添加\"),\n              ),\n            ),\n            onSubmitted: (e) {\n              addKeyword();\n            },\n          ),\n          AppStyle.vGap12,\n          Obx(\n            () => Text(\n              \"已添加${AppSettingsController.instance.shieldList.length}个关键词（点击移除）\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          AppStyle.vGap12,\n          Obx(\n            () => Wrap(\n              runSpacing: 12,\n              spacing: 12,\n              children: AppSettingsController.instance.shieldList\n                  .map(\n                    (item) => InkWell(\n                      borderRadius: AppStyle.radius24,\n                      onTap: () {\n                        AppSettingsController.instance.removeShieldList(item);\n                      },\n                      child: Container(\n                        decoration: BoxDecoration(\n                          border: Border.all(color: Colors.grey),\n                          borderRadius: AppStyle.radius24,\n                        ),\n                        padding: AppStyle.edgeInsetsH12.copyWith(\n                          top: 4,\n                          bottom: 4,\n                        ),\n                        child: Text(\n                          item,\n                          style: Get.textTheme.bodyMedium,\n                        ),\n                      ),\n                    ),\n                  )\n                  .toList(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void showFollowUserSheet() {\n    Utils.showBottomSheet(\n      title: \"关注列表\",\n      child: Obx(\n        () => Stack(\n          children: [\n            RefreshIndicator(\n              onRefresh: FollowService.instance.loadData,\n              child: ListView.builder(\n                itemCount: FollowService.instance.liveList.length,\n                itemBuilder: (_, i) {\n                  var item = FollowService.instance.liveList[i];\n                  return Obx(\n                    () => FollowUserItem(\n                      item: item,\n                      playing: rxSite.value.id == item.siteId &&\n                          rxRoomId.value == item.roomId,\n                      onTap: () {\n                        Get.back();\n                        resetRoom(\n                          Sites.allSites[item.siteId]!,\n                          item.roomId,\n                        );\n                      },\n                    ),\n                  );\n                },\n              ),\n            ),\n            if (Platform.isLinux || Platform.isWindows || Platform.isMacOS)\n              Positioned(\n                right: 12,\n                bottom: 12,\n                child: Obx(\n                  () => DesktopRefreshButton(\n                    refreshing: FollowService.instance.updating.value,\n                    onPressed: FollowService.instance.loadData,\n                  ),\n                ),\n              ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  void showAutoExitSheet() {\n    if (AppSettingsController.instance.autoExitEnable.value &&\n        !delayAutoExit.value) {\n      SmartDialog.showToast(\"已设置了全局定时关闭\");\n      return;\n    }\n    Utils.showBottomSheet(\n      title: \"定时关闭\",\n      child: ListView(\n        children: [\n          Obx(\n            () => SwitchListTile(\n              title: Text(\n                \"启用定时关闭\",\n                style: Get.textTheme.titleMedium,\n              ),\n              value: autoExitEnable.value,\n              onChanged: (e) {\n                autoExitEnable.value = e;\n\n                setAutoExit();\n                //controller.setAutoExitEnable(e);\n              },\n            ),\n          ),\n          Obx(\n            () => ListTile(\n              enabled: autoExitEnable.value,\n              title: Text(\n                \"自动关闭时间：${autoExitMinutes.value ~/ 60}小时${autoExitMinutes.value % 60}分钟\",\n                style: Get.textTheme.titleMedium,\n              ),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () async {\n                var value = await showTimePicker(\n                  context: Get.context!,\n                  initialTime: TimeOfDay(\n                    hour: autoExitMinutes.value ~/ 60,\n                    minute: autoExitMinutes.value % 60,\n                  ),\n                  initialEntryMode: TimePickerEntryMode.inputOnly,\n                  builder: (_, child) {\n                    return MediaQuery(\n                      data: Get.mediaQuery.copyWith(\n                        alwaysUse24HourFormat: true,\n                      ),\n                      child: child!,\n                    );\n                  },\n                );\n                if (value == null || (value.hour == 0 && value.minute == 0)) {\n                  return;\n                }\n                var duration =\n                    Duration(hours: value.hour, minutes: value.minute);\n                autoExitMinutes.value = duration.inMinutes;\n                AppSettingsController.instance\n                    .setRoomAutoExitDuration(autoExitMinutes.value);\n                //setAutoExitDuration(duration.inMinutes);\n                setAutoExit();\n              },\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void openNaviteAPP() async {\n    var naviteUrl = \"\";\n    var webUrl = \"\";\n    if (site.id == Constant.kBiliBili) {\n      naviteUrl = \"bilibili://live/${detail.value?.roomId}\";\n      webUrl = \"https://live.bilibili.com/${detail.value?.roomId}\";\n    } else if (site.id == Constant.kDouyin) {\n      var args = detail.value?.danmakuData as DouyinDanmakuArgs;\n      naviteUrl = \"snssdk1128://webcast_room?room_id=${args.roomId}\";\n      webUrl = \"https://live.douyin.com/${args.webRid}\";\n    } else if (site.id == Constant.kHuya) {\n      var args = detail.value?.danmakuData as HuyaDanmakuArgs;\n      naviteUrl =\n          \"yykiwi://homepage/index.html?banneraction=https%3A%2F%2Fdiy-front.cdn.huya.com%2Fzt%2Ffrontpage%2Fcc%2Fupdate.html%3Fhyaction%3Dlive%26channelid%3D${args.subSid}%26subid%3D${args.subSid}%26liveuid%3D${args.subSid}%26screentype%3D1%26sourcetype%3D0%26fromapp%3Dhuya_wap%252Fclick%252Fopen_app_guide%26&fromapp=huya_wap/click/open_app_guide\";\n      webUrl = \"https://www.huya.com/${detail.value?.roomId}\";\n    } else if (site.id == Constant.kDouyu) {\n      naviteUrl =\n          \"douyulink://?type=90001&schemeUrl=douyuapp%3A%2F%2Froom%3FliveType%3D0%26rid%3D${detail.value?.roomId}\";\n      webUrl = \"https://www.douyu.com/${detail.value?.roomId}\";\n    }\n    try {\n      await launchUrlString(naviteUrl, mode: LaunchMode.externalApplication);\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"无法打开APP，将使用浏览器打开\");\n      await launchUrlString(webUrl, mode: LaunchMode.externalApplication);\n    }\n  }\n\n  void resetRoom(Site site, String roomId) async {\n    if (this.site == site && this.roomId == roomId) {\n      return;\n    }\n\n    rxSite.value = site;\n    rxRoomId.value = roomId;\n\n    // 清除全部消息\n    liveDanmaku.stop();\n    messages.clear();\n    superChats.clear();\n    danmakuController?.clear();\n\n    // 重新设置LiveDanmaku\n    liveDanmaku = site.liveSite.getDanmaku();\n    rustDanmakuMask.reset();\n\n    // 停止播放\n    await player.stop();\n\n    // 刷新信息\n    loadData();\n    HistoryService.instance.reset(\"${site.id}_$roomId\");\n  }\n\n  void copyErrorDetail() {\n    Utils.copyToClipboard('''直播平台：${rxSite.value.name}\n房间号：${rxRoomId.value}\n错误信息：\n${error?.toString()}\n----------------\n${error?.stackTrace}''');\n    SmartDialog.showToast(\"已复制错误信息\");\n  }\n\n  @override\n  void didChangeAppLifecycleState(AppLifecycleState state) {\n    super.didChangeAppLifecycleState(state);\n\n    if (state == AppLifecycleState.paused) {\n      var height = MediaQuery.of(Get.context!).padding.top;\n      Log.d(\"当前状态栏高度$height\");\n      Log.d(\"进入后台\");\n      //进入后台，关闭弹幕\n      danmakuController?.clear();\n      isBackground = true;\n    } else\n    //返回前台\n    if (state == AppLifecycleState.resumed) {\n      // update();\n      var height = MediaQuery.of(Get.context!).padding.top;\n      Log.d(\"当前状态栏高度$height\");\n      Log.d(\"返回前台\");\n      danmakuController?.resume;\n      isBackground = false;\n    }\n  }\n\n  @override\n  void onClose() {\n    WidgetsBinding.instance.removeObserver(this);\n    scrollController.removeListener(scrollListener);\n    autoExitTimer?.cancel();\n    danmakuTimer?.cancel();\n    HistoryService.instance.stop();\n\n    liveDanmaku.stop();\n    danmakuController = null;\n    rustDanmakuMask.dispose();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/live_room/live_room_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:floating/floating.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:lottie/lottie.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_app/modules/live_room/player/player_controls.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/widgets/desktop_refresh_button.dart';\nimport 'package:simple_live_app/widgets/follow_user_item.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_app/widgets/settings/settings_action.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_number.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\nimport 'package:simple_live_app/widgets/superchat_card.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass LiveRoomPage extends GetView<LiveRoomController> {\n  const LiveRoomPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final page = Obx(\n      () {\n        if (controller.loadError.value) {\n          return Scaffold(\n            appBar: AppBar(\n              title: const Text(\"直播间加载失败\"),\n            ),\n            body: Padding(\n              padding: AppStyle.edgeInsetsA12,\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.stretch,\n                mainAxisAlignment: MainAxisAlignment.center,\n                children: [\n                  LottieBuilder.asset(\n                    'assets/lotties/error.json',\n                    height: 140,\n                    repeat: false,\n                  ),\n                  const Text(\n                    \"直播间加载失败\",\n                    textAlign: TextAlign.center,\n                  ),\n                  AppStyle.vGap4,\n                  Text(\n                    controller.error?.toString() ?? \"未知错误\",\n                    textAlign: TextAlign.center,\n                    maxLines: 1,\n                    overflow: TextOverflow.ellipsis,\n                    style: const TextStyle(fontSize: 12, color: Colors.grey),\n                  ),\n                  AppStyle.vGap4,\n                  Text(\n                    \"${controller.rxSite.value.id} - ${controller.rxRoomId.value}\",\n                    textAlign: TextAlign.center,\n                    style: const TextStyle(fontSize: 12, color: Colors.grey),\n                  ),\n                  Row(\n                    mainAxisAlignment: MainAxisAlignment.center,\n                    children: [\n                      TextButton.icon(\n                        onPressed: controller.copyErrorDetail,\n                        icon: const Icon(Remix.file_copy_line),\n                        label: const Text(\"复制信息\"),\n                      ),\n                      TextButton.icon(\n                        onPressed: controller.refreshRoom,\n                        icon: const Icon(Remix.refresh_line),\n                        label: const Text(\"刷新\"),\n                      ),\n                    ],\n                  )\n                ],\n              ),\n            ),\n          );\n        }\n        if (controller.fullScreenState.value) {\n          return PopScope(\n            canPop: false,\n            onPopInvokedWithResult: (e, r) {\n              controller.exitFull();\n            },\n            child: Scaffold(\n              body: buildMediaPlayer(),\n            ),\n          );\n        } else {\n          return buildPageUI();\n        }\n      },\n    );\n    if (!Platform.isAndroid) {\n      return page;\n    }\n    return PiPSwitcher(\n      floating: controller.pip,\n      childWhenDisabled: page,\n      childWhenEnabled: buildMediaPlayer(),\n    );\n  }\n\n  Widget buildPageUI() {\n    return OrientationBuilder(\n      builder: (context, orientation) {\n        return Scaffold(\n          appBar: AppBar(\n            title: Obx(\n              () => Text(controller.detail.value?.title ?? \"直播间\"),\n            ),\n            actions: buildAppbarActions(context),\n          ),\n          body: orientation == Orientation.portrait\n              ? buildPhoneUI(context)\n              : buildTabletUI(context),\n        );\n      },\n    );\n  }\n\n  Widget buildPhoneUI(BuildContext context) {\n    return Column(\n      children: [\n        AspectRatio(\n          aspectRatio: 16 / 9,\n          child: buildMediaPlayer(),\n        ),\n        buildUserProfile(context),\n        buildMessageArea(),\n        buildBottomActions(context),\n      ],\n    );\n  }\n\n  Widget buildTabletUI(BuildContext context) {\n    return Column(\n      children: [\n        Expanded(\n          child: Row(\n            children: [\n              Expanded(\n                child: buildMediaPlayer(),\n              ),\n              SizedBox(\n                width: 300,\n                child: Column(\n                  children: [\n                    buildUserProfile(context),\n                    buildMessageArea(),\n                  ],\n                ),\n              ),\n            ],\n          ),\n        ),\n        Container(\n          decoration: BoxDecoration(\n            color: Theme.of(context).cardColor,\n            border: Border(\n              top: BorderSide(\n                color: Colors.grey.withAlpha(25),\n              ),\n            ),\n          ),\n          padding: AppStyle.edgeInsetsV4.copyWith(\n            bottom: AppStyle.bottomBarHeight + 4,\n          ),\n          child: Row(\n            children: [\n              TextButton.icon(\n                style: TextButton.styleFrom(\n                  textStyle: const TextStyle(fontSize: 14),\n                ),\n                onPressed: controller.refreshRoom,\n                icon: const Icon(Remix.refresh_line),\n                label: const Text(\"刷新\"),\n              ),\n              Obx(\n                () => controller.followed.value\n                    ? TextButton.icon(\n                        style: TextButton.styleFrom(\n                          textStyle: const TextStyle(fontSize: 14),\n                        ),\n                        onPressed: controller.removeFollowUser,\n                        icon: const Icon(Remix.heart_fill),\n                        label: const Text(\"取消关注\"),\n                      )\n                    : TextButton.icon(\n                        style: TextButton.styleFrom(\n                          textStyle: const TextStyle(fontSize: 14),\n                        ),\n                        onPressed: controller.followUser,\n                        icon: const Icon(Remix.heart_line),\n                        label: const Text(\"关注\"),\n                      ),\n              ),\n              const Expanded(child: Center()),\n              TextButton.icon(\n                style: TextButton.styleFrom(\n                  textStyle: const TextStyle(fontSize: 14),\n                ),\n                onPressed: controller.share,\n                icon: const Icon(Remix.share_line),\n                label: const Text(\"分享\"),\n              ),\n              (Platform.isWindows || Platform.isLinux)\n                  ? TextButton.icon(\n                      style: TextButton.styleFrom(\n                        textStyle: const TextStyle(fontSize: 14),\n                      ),\n                      onPressed: controller.visitWebLive,\n                      icon: const Icon(Remix.chrome_fill),\n                      label: const Text(\"浏览器打开\"),\n                    )\n                  : TextButton.icon(\n                      style: TextButton.styleFrom(\n                        textStyle: const TextStyle(fontSize: 14),\n                      ),\n                      onPressed: controller.copyUrl,\n                      icon: const Icon(Remix.file_copy_line),\n                      label: const Text(\"复制链接\"),\n                    ),\n            ],\n          ),\n        ),\n        //buildBottomActions(context),\n      ],\n    );\n  }\n\n  Widget buildMediaPlayer() {\n    var boxFit = BoxFit.contain;\n    double? aspectRatio;\n    if (AppSettingsController.instance.scaleMode.value == 0) {\n      boxFit = BoxFit.contain;\n    } else if (AppSettingsController.instance.scaleMode.value == 1) {\n      boxFit = BoxFit.fill;\n    } else if (AppSettingsController.instance.scaleMode.value == 2) {\n      boxFit = BoxFit.cover;\n    } else if (AppSettingsController.instance.scaleMode.value == 3) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 16 / 9;\n    } else if (AppSettingsController.instance.scaleMode.value == 4) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 4 / 3;\n    }\n    return Stack(\n      children: [\n        Video(\n          key: controller.globalPlayerKey,\n          controller: controller.videoController,\n          pauseUponEnteringBackgroundMode:\n              AppSettingsController.instance.playerAutoPause.value,\n          resumeUponEnteringForegroundMode:\n              AppSettingsController.instance.playerAutoPause.value,\n          controls: (state) {\n            return playerControls(state, controller);\n          },\n          aspectRatio: aspectRatio,\n          fit: boxFit,\n          // 自己实现\n          wakelock: false,\n        ),\n        Obx(\n          () => Visibility(\n            visible: !controller.liveStatus.value,\n            child: const Center(\n              child: Text(\n                \"未开播\",\n                style: TextStyle(fontSize: 16, color: Colors.white),\n              ),\n            ),\n          ),\n        ),\n      ],\n    );\n  }\n\n  Widget buildUserProfile(BuildContext context) {\n    return Container(\n      decoration: BoxDecoration(\n        color: Theme.of(context).cardColor,\n        border: Border(\n          top: BorderSide(\n            color: Colors.grey.withAlpha(25),\n          ),\n          bottom: BorderSide(\n            color: Colors.grey.withAlpha(25),\n          ),\n        ),\n      ),\n      padding: AppStyle.edgeInsetsA8.copyWith(\n        left: 12,\n        right: 12,\n      ),\n      child: Obx(\n        () => Row(\n          mainAxisAlignment: MainAxisAlignment.start,\n          children: [\n            Container(\n              decoration: BoxDecoration(\n                border: Border.all(color: Colors.grey.withAlpha(50)),\n                borderRadius: AppStyle.radius24,\n              ),\n              child: NetImage(\n                controller.detail.value?.userAvatar ?? \"\",\n                width: 48,\n                height: 48,\n                borderRadius: 24,\n              ),\n            ),\n            AppStyle.hGap12,\n            Expanded(\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.start,\n                children: [\n                  Text(\n                    controller.detail.value?.userName ?? \"\",\n                    maxLines: 1,\n                    overflow: TextOverflow.ellipsis,\n                  ),\n                  AppStyle.vGap4,\n                  Row(\n                    children: [\n                      Image.asset(\n                        controller.site.logo,\n                        width: 20,\n                      ),\n                      AppStyle.hGap4,\n                      Text(\n                        controller.site.name,\n                        style: const TextStyle(\n                          fontSize: 12,\n                          color: Colors.grey,\n                        ),\n                      ),\n                    ],\n                  ),\n                ],\n              ),\n            ),\n            AppStyle.hGap12,\n            Row(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                const Icon(\n                  Remix.fire_fill,\n                  size: 20,\n                  color: Colors.orange,\n                ),\n                AppStyle.hGap4,\n                Text(\n                  Utils.onlineToString(\n                    controller.detail.value?.online ?? 0,\n                  ),\n                  style: const TextStyle(fontSize: 14),\n                ),\n              ],\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  Widget buildBottomActions(BuildContext context) {\n    return Container(\n      decoration: BoxDecoration(\n        color: Theme.of(context).cardColor,\n        border: Border(\n          top: BorderSide(\n            color: Colors.grey.withAlpha(25),\n          ),\n        ),\n      ),\n      padding: EdgeInsets.only(bottom: AppStyle.bottomBarHeight),\n      child: Row(\n        children: [\n          Expanded(\n            child: Obx(\n              () => controller.followed.value\n                  ? TextButton.icon(\n                      style: TextButton.styleFrom(\n                        textStyle: const TextStyle(fontSize: 14),\n                      ),\n                      onPressed: controller.removeFollowUser,\n                      icon: const Icon(Remix.heart_fill),\n                      label: const Text(\"取消关注\"),\n                    )\n                  : TextButton.icon(\n                      style: TextButton.styleFrom(\n                        textStyle: const TextStyle(fontSize: 14),\n                      ),\n                      onPressed: controller.followUser,\n                      icon: const Icon(Remix.heart_line),\n                      label: const Text(\"关注\"),\n                    ),\n            ),\n          ),\n          Expanded(\n            child: TextButton.icon(\n              style: TextButton.styleFrom(\n                textStyle: const TextStyle(fontSize: 14),\n              ),\n              onPressed: controller.refreshRoom,\n              icon: const Icon(Remix.refresh_line),\n              label: const Text(\"刷新\"),\n            ),\n          ),\n          Expanded(\n            child: TextButton.icon(\n              style: TextButton.styleFrom(\n                textStyle: const TextStyle(fontSize: 14),\n              ),\n              onPressed: controller.share,\n              icon: const Icon(Remix.share_line),\n              label: const Text(\"分享\"),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildMessageArea() {\n    return Expanded(\n      child: DefaultTabController(\n        length: 4,\n        child: Column(\n          children: [\n            TabBar(\n              indicatorSize: TabBarIndicatorSize.tab,\n              labelPadding: EdgeInsets.zero,\n              indicatorWeight: 1.0,\n              tabs: [\n                const Tab(\n                  text: \"聊天\",\n                ),\n                Tab(\n                  child: Obx(\n                    () => Text(\n                      controller.superChats.isNotEmpty\n                          ? \"SC(${controller.superChats.length})\"\n                          : \"SC\",\n                    ),\n                  ),\n                ),\n                const Tab(\n                  text: \"关注\",\n                ),\n                const Tab(\n                  text: \"设置\",\n                ),\n              ],\n            ),\n            Expanded(\n              child: TabBarView(\n                children: [\n                  Obx(\n                    () => Stack(\n                      children: [\n                        ListView.separated(\n                          controller: controller.scrollController,\n                          separatorBuilder: (_, i) => Obx(\n                            () => SizedBox(\n                              // *2与原来的EdgeInsets.symmetric(vertical: )做兼容\n                              height: AppSettingsController\n                                      .instance.chatTextGap.value *\n                                  2,\n                            ),\n                          ),\n                          padding: AppStyle.edgeInsetsA12,\n                          itemCount: controller.messages.length,\n                          itemBuilder: (_, i) {\n                            var item = controller.messages[i];\n                            return buildMessageItem(item);\n                          },\n                        ),\n                        Visibility(\n                          visible: controller.disableAutoScroll.value,\n                          child: Positioned(\n                            right: 12,\n                            bottom: 12,\n                            child: ElevatedButton.icon(\n                              onPressed: () {\n                                controller.disableAutoScroll.value = false;\n                                controller.chatScrollToBottom();\n                              },\n                              icon: const Icon(Icons.expand_more),\n                              label: const Text(\"最新\"),\n                            ),\n                          ),\n                        ),\n                      ],\n                    ),\n                  ),\n                  buildSuperChats(),\n                  buildFollowList(),\n                  buildSettings(),\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  Widget buildMessageItem(LiveMessage message) {\n    if (message.userName == \"LiveSysMessage\") {\n      return Obx(\n        () => SelectableText(\n          message.message,\n          style: TextStyle(\n            color: Colors.grey,\n            fontSize: AppSettingsController.instance.chatTextSize.value,\n          ),\n        ),\n      );\n    }\n\n    return Obx(\n      () => AppSettingsController.instance.chatBubbleStyle.value\n          ? Row(\n              mainAxisAlignment: MainAxisAlignment.start,\n              crossAxisAlignment: CrossAxisAlignment.start,\n              children: [\n                Flexible(\n                  child: Container(\n                    decoration: BoxDecoration(\n                      color: Colors.blueGrey.withAlpha(25),\n                      //borderRadius: AppStyle.radius8,\n                      borderRadius: const BorderRadius.only(\n                        topRight: Radius.circular(12),\n                        bottomLeft: Radius.circular(12),\n                        bottomRight: Radius.circular(12),\n                      ),\n                    ),\n                    padding:\n                        AppStyle.edgeInsetsA4.copyWith(left: 12, right: 12),\n                    child: SelectableText.rich(\n                      TextSpan(\n                        text: \"${message.userName}：\",\n                        style: TextStyle(\n                          color: Colors.grey,\n                          fontSize:\n                              AppSettingsController.instance.chatTextSize.value,\n                        ),\n                        children: [\n                          TextSpan(\n                            text: message.message,\n                            style: TextStyle(\n                              color: Get.isDarkMode\n                                  ? Colors.white\n                                  : AppColors.black333,\n                            ),\n                          )\n                        ],\n                      ),\n                    ),\n                  ),\n                ),\n              ],\n            )\n          : SelectableText.rich(\n              TextSpan(\n                text: \"${message.userName}：\",\n                style: TextStyle(\n                  color: Colors.grey,\n                  fontSize: AppSettingsController.instance.chatTextSize.value,\n                ),\n                children: [\n                  TextSpan(\n                    text: message.message,\n                    style: TextStyle(\n                      color: Get.isDarkMode ? Colors.white : AppColors.black333,\n                    ),\n                  )\n                ],\n              ),\n            ),\n    );\n  }\n\n  Widget buildSuperChats() {\n    return KeepAliveWrapper(\n      child: Obx(\n        () => ListView.separated(\n          padding: AppStyle.edgeInsetsA12,\n          itemCount: controller.superChats.length,\n          separatorBuilder: (_, i) => AppStyle.vGap12,\n          itemBuilder: (_, i) {\n            var item = controller.superChats[i];\n            return SuperChatCard(\n              item,\n              onExpire: () {\n                controller.removeSuperChats();\n              },\n            );\n          },\n        ),\n      ),\n    );\n  }\n\n  Widget buildSettings() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA12,\n      children: [\n        Obx(\n          () => Visibility(\n            visible: controller.autoExitEnable.value,\n            child: ListTile(\n              leading: const Icon(Icons.timer_outlined),\n              visualDensity: VisualDensity.compact,\n              title: Text(\"${parseDuration(controller.countdown.value)}后自动关闭\"),\n            ),\n          ),\n        ),\n        Padding(\n          padding: AppStyle.edgeInsetsA12,\n          child: Text(\n            \"聊天区\",\n            style: Get.textTheme.titleSmall,\n          ),\n        ),\n        SettingsCard(\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              Obx(\n                () => SettingsNumber(\n                  title: \"文字大小\",\n                  value:\n                      AppSettingsController.instance.chatTextSize.value.toInt(),\n                  min: 8,\n                  max: 36,\n                  onChanged: (e) {\n                    AppSettingsController.instance\n                        .setChatTextSize(e.toDouble());\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"上下间隔\",\n                  value:\n                      AppSettingsController.instance.chatTextGap.value.toInt(),\n                  min: 0,\n                  max: 12,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setChatTextGap(e.toDouble());\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsSwitch(\n                  title: \"气泡样式\",\n                  value: AppSettingsController.instance.chatBubbleStyle.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setChatBubbleStyle(e);\n                  },\n                ),\n              ),\n            ],\n          ),\n        ),\n        Padding(\n          padding: AppStyle.edgeInsetsA12,\n          child: Text(\n            \"更多设置\",\n            style: Get.textTheme.titleSmall,\n          ),\n        ),\n        SettingsCard(\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              SettingsAction(\n                title: \"关键词屏蔽\",\n                onTap: controller.showDanmuShield,\n              ),\n              AppStyle.divider,\n              SettingsAction(\n                title: \"弹幕设置\",\n                onTap: controller.showDanmuSettingsSheet,\n              ),\n              AppStyle.divider,\n              SettingsAction(\n                title: \"定时关闭\",\n                onTap: controller.showAutoExitSheet,\n              ),\n              AppStyle.divider,\n              SettingsAction(\n                title: \"画面尺寸\",\n                onTap: controller.showPlayerSettingsSheet,\n              ),\n            ],\n          ),\n        ),\n      ],\n    );\n  }\n\n  Widget buildFollowList() {\n    return Obx(\n      () => Stack(\n        children: [\n          RefreshIndicator(\n            onRefresh: FollowService.instance.loadData,\n            child: ListView.builder(\n              itemCount: FollowService.instance.liveList.length,\n              itemBuilder: (_, i) {\n                var item = FollowService.instance.liveList[i];\n                return Obx(\n                  () => FollowUserItem(\n                    item: item,\n                    playing: controller.rxSite.value.id == item.siteId &&\n                        controller.rxRoomId.value == item.roomId,\n                    onTap: () {\n                      controller.resetRoom(\n                        Sites.allSites[item.siteId]!,\n                        item.roomId,\n                      );\n                    },\n                  ),\n                );\n              },\n            ),\n          ),\n          if (Platform.isLinux || Platform.isWindows || Platform.isMacOS)\n            Positioned(\n              right: 12,\n              bottom: 12,\n              child: Obx(\n                () => DesktopRefreshButton(\n                  refreshing: FollowService.instance.updating.value,\n                  onPressed: FollowService.instance.loadData,\n                ),\n              ),\n            ),\n        ],\n      ),\n    );\n  }\n\n  List<Widget> buildAppbarActions(BuildContext context) {\n    return [\n      IconButton(\n        onPressed: () {\n          showMore();\n        },\n        icon: const Icon(Icons.more_horiz),\n      ),\n    ];\n  }\n\n  void showMore() {\n    showModalBottomSheet(\n      context: Get.context!,\n      constraints: const BoxConstraints(\n        maxWidth: 600,\n      ),\n      isScrollControlled: true,\n      builder: (_) => Container(\n        padding: EdgeInsets.only(\n          bottom: AppStyle.bottomBarHeight,\n        ),\n        child: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            ListTile(\n              leading: const Icon(Icons.refresh),\n              title: const Text(\"刷新\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                controller.refreshRoom();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.play_circle_outline),\n              trailing: const Icon(Icons.chevron_right),\n              title: const Text(\"切换清晰度\"),\n              onTap: () {\n                Get.back();\n                controller.showQualitySheet();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.switch_video_outlined),\n              title: const Text(\"切换线路\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.showPlayUrlsSheet();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.aspect_ratio_outlined),\n              title: const Text(\"画面尺寸\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.showPlayerSettingsSheet();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.camera_alt_outlined),\n              title: const Text(\"截图\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                controller.saveScreenshot();\n              },\n            ),\n            Visibility(\n              visible: Platform.isAndroid,\n              child: ListTile(\n                leading: const Icon(Icons.picture_in_picture),\n                title: const Text(\"小窗播放\"),\n                trailing: const Icon(Icons.chevron_right),\n                onTap: () {\n                  Get.back();\n                  controller.enablePIP();\n                },\n              ),\n            ),\n            ListTile(\n              leading: const Icon(Icons.timer_outlined),\n              title: const Text(\"定时关闭\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.showAutoExitSheet();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.share_sharp),\n              title: const Text(\"分享直播间\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.share();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.copy),\n              title: const Text(\"复制链接\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.copyUrl();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.open_in_new),\n              title: const Text(\"APP 中打开\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.openNaviteAPP();\n              },\n            ),\n            ListTile(\n              leading: const Icon(Icons.info_outline_rounded),\n              title: const Text(\"播放信息\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                controller.showDebugInfo();\n              },\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  String parseDuration(int sec) {\n    // 转为时分秒\n    var h = sec ~/ 3600;\n    var m = (sec % 3600) ~/ 60;\n    var s = sec % 60;\n    if (h > 0) {\n      return \"${h.toString().padLeft(2, '0')}小时${m.toString().padLeft(2, '0')}分钟${s.toString().padLeft(2, '0')}秒\";\n    }\n    if (m > 0) {\n      return \"${m.toString().padLeft(2, '0')}分钟${s.toString().padLeft(2, '0')}秒\";\n    }\n    return \"${s.toString().padLeft(2, '0')}秒\";\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/live_room/player/player_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:io';\nimport 'package:auto_orientation_v2/auto_orientation_v2.dart';\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:file_picker/file_picker.dart';\nimport 'package:floating/floating.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:flutter_image_gallery_saver/flutter_image_gallery_saver.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/services/window_service.dart';\nimport 'package:volume_controller/volume_controller.dart';\nimport 'package:screen_brightness/screen_brightness.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/custom_throttle.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:wakelock_plus/wakelock_plus.dart';\nimport 'package:window_manager/window_manager.dart';\n\nmixin PlayerMixin {\n  GlobalKey<VideoState> globalPlayerKey = GlobalKey<VideoState>();\n  GlobalKey globalDanmuKey = GlobalKey();\n\n  /// 播放器实例\n  late final player = Player(\n    configuration: PlayerConfiguration(\n      title: \"Slive Player\",\n      logLevel: AppSettingsController.instance.logEnable.value\n          ? MPVLogLevel.debug\n          : MPVLogLevel.error,\n    ),\n  );\n\n  /// 初始化播放器并设置 ao 参数\n  Future<void> initializePlayer() async {\n    var pp = player.platform as NativePlayer;\n    // 设置音频输出驱动\n    if (AppSettingsController.instance.customPlayerOutput.value) {\n      await pp.setProperty(\n        'ao',\n        AppSettingsController.instance.audioOutputDriver.value,\n      );\n    } else if (Platform.isLinux) {\n      await pp.setProperty('ao', 'alsa');\n    }\n    // media_kit 仓库更新导致的问题，临时解决办法\n    if (Platform.isAndroid) {\n      // 通过错误参数强制media_kit不seek, 解决了加载-pause-seek 在直播流上的开屏问题\n      await pp.setProperty('force-seekable', 'yes');\n    }\n    // 低内存管理\n    //\n    // 根据：https://mpv.io/manual/stable/#cache\n    // --cache=<yes|no|auto>// --cache-secs=<seconds>\n    // --demuxer-seekable-cache=<yes|no|auto>\n    // --demuxer-max-back-bytes=<bytesize>\n    // --demuxer-donate-buffer==<yes|no>\n    //\n    // 内存换空间, 同时通过调整参数禁用mpv回放缓存（直播暂时不需要）\n    // hls流/令牌流/.. 根据mdk-sdk作者回复, rtsp 在 ffmpeg存在内存泄露, 这意味着我们只能等待修复\n    await pp.setProperty(\"cache\", \"no\");\n    await pp.setProperty(\"cache-secs\", \"0\");\n    await pp.setProperty('demuxer-seekable-cache', 'no');\n    await pp.setProperty('demuxer-donate-buffer', 'no');\n    await pp.setProperty(\"demuxer-max-back-bytes\", \"0\");\n    // 在所有平台上正确启用双重缓存,覆写mpv设置\n    if (AppSettingsController.instance.videoDoubleBuffering.value) {\n      final directory = await getTemporaryDirectory();\n      await pp.setProperty(\"cache\", \"yes\");\n      await pp.setProperty(\"cache-secs\", \"3\");\n      await pp.setProperty('demuxer-seekable-cache', 'yes');\n      await pp.setProperty('demuxer-donate-buffer', 'yes');\n      await pp.setProperty(\"demuxer-cache-dir\", directory.path);\n    }\n    // bili/douyin流存在时间戳跳变问题\n    // 真机建议-空间换内存-暂时不需要\n    // windows:\n    //  icc-cache-dir = \"~~/cache/icc\";\n    //  gpu-shader-cache-dir = \"~~/cache/shader\"\n    //  watch-later-dir = \"~~/cache/watch_later\"\n  }\n\n  /// 视频控制器\n  late final videoController = VideoController(\n    player,\n    configuration: AppSettingsController.instance.customPlayerOutput.value\n        ? VideoControllerConfiguration(\n            vo: AppSettingsController.instance.videoOutputDriver.value,\n            hwdec: AppSettingsController.instance.videoHardwareDecoder.value,\n          )\n        : AppSettingsController.instance.playerCompatMode.value\n            ? const VideoControllerConfiguration(\n                vo: 'mediacodec_embed',\n                hwdec: 'mediacodec',\n              )\n            : VideoControllerConfiguration(\n                enableHardwareAcceleration:\n                    AppSettingsController.instance.hardwareDecode.value,\n                androidAttachSurfaceAfterVideoParameters: false,\n              ),\n  );\n}\nmixin PlayerStateMixin on PlayerMixin {\n  ///音量控制条计时器\n  Timer? hidevolumeTimer;\n\n  /// 是否进入桌面端小窗\n  RxBool smallWindowState = false.obs;\n\n  /// 是否显示弹幕\n  RxBool showDanmakuState = false.obs;\n\n  /// 是否显示控制器\n  RxBool showControlsState = false.obs;\n\n  /// 是否显示设置窗口\n  RxBool showSettingState = false.obs;\n\n  /// 是否显示弹幕设置窗口\n  RxBool showDanmakuSettingState = false.obs;\n\n  /// 是否处于锁定控制器状态\n  RxBool lockControlsState = false.obs;\n\n  /// 是否处于全屏状态\n  RxBool fullScreenState = false.obs;\n\n  /// 显示手势Tip\n  RxBool showGestureTip = false.obs;\n\n  /// 手势Tip文本\n  RxString gestureTipText = \"\".obs;\n\n  /// 显示提示底部Tip\n  RxBool showBottomTip = false.obs;\n\n  /// 是否显示OSD统计信息\n  RxBool showOSDStats = false.obs;\n\n  /// 提示底部Tip文本\n  RxString bottomTipText = \"\".obs;\n\n  /// 自动隐藏控制器计时器\n  Timer? hideControlsTimer;\n\n  /// 自动隐藏提示计时器\n  Timer? hideSeekTipTimer;\n\n  /// 是否为竖屏直播间\n  var isVertical = false.obs;\n\n  Widget? danmakuView;\n\n  var showQualites = false.obs;\n  var showLines = false.obs;\n\n  /// 隐藏控制器\n  void hideControls() {\n    showControlsState.value = false;\n    hideControlsTimer?.cancel();\n  }\n\n  void setLockState() {\n    lockControlsState.value = !lockControlsState.value;\n    if (lockControlsState.value) {\n      showControlsState.value = false;\n    } else {\n      showControlsState.value = true;\n    }\n  }\n\n  /// 显示控制器\n  void showControls() {\n    showControlsState.value = true;\n    resetHideControlsTimer();\n  }\n\n  /// 开始隐藏控制器计时\n  /// - 当点击控制器上时功能时需要重新计时\n  void resetHideControlsTimer() {\n    hideControlsTimer?.cancel();\n\n    hideControlsTimer = Timer(\n      const Duration(\n        seconds: 5,\n      ),\n      hideControls,\n    );\n  }\n\n  void updateScaleMode() {\n    var boxFit = BoxFit.contain;\n    double? aspectRatio;\n    if (player.state.width != null && player.state.height != null) {\n      aspectRatio = player.state.width! / player.state.height!;\n    }\n\n    if (AppSettingsController.instance.scaleMode.value == 0) {\n      boxFit = BoxFit.contain;\n    } else if (AppSettingsController.instance.scaleMode.value == 1) {\n      boxFit = BoxFit.fill;\n    } else if (AppSettingsController.instance.scaleMode.value == 2) {\n      boxFit = BoxFit.cover;\n    } else if (AppSettingsController.instance.scaleMode.value == 3) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 16 / 9;\n    } else if (AppSettingsController.instance.scaleMode.value == 4) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 4 / 3;\n    }\n    globalPlayerKey.currentState?.update(\n      aspectRatio: aspectRatio,\n      fit: boxFit,\n    );\n  }\n}\nmixin PlayerDanmakuMixin on PlayerStateMixin {\n  /// 弹幕控制器\n  late DanmakuController? danmakuController;\n\n  void initDanmakuController(DanmakuController e) {\n    danmakuController = e;\n  }\n\n  void updateDanmuOption(DanmakuOption? option) {\n    if (option == null) return;\n    danmakuController?.updateOption(option);\n  }\n\n  void disposeDanmakuController() {\n    danmakuController?.clear();\n  }\n\n  void addDanmaku(List<DanmakuContentItem> items) {\n    if (!showDanmakuState.value) {\n      return;\n    }\n    for (var item in items) {\n      danmakuController?.addDanmaku(item);\n    }\n  }\n}\nmixin PlayerSystemMixin on PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin {\n  final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n  final screenBrightness = ScreenBrightness();\n  final VolumeController volumeController = VolumeController.instance;\n  final pip = Floating();\n  StreamSubscription<PiPStatus>? _pipSubscription;\n\n  /// 初始化一些系统状态\n  void initSystem() async {\n    if (Platform.isAndroid || Platform.isIOS) {\n      volumeController.showSystemUI = false;\n    }\n\n    // 屏幕常亮\n    //WakelockPlus.enable();\n\n    // 开始隐藏计时\n    resetHideControlsTimer();\n  }\n\n  /// 释放一些系统状态\n  Future resetSystem() async {\n    _pipSubscription?.cancel();\n    //pip.dispose();\n    await SystemChrome.setEnabledSystemUIMode(\n      SystemUiMode.edgeToEdge,\n      overlays: SystemUiOverlay.values,\n    );\n\n    await setPortraitOrientation();\n    if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {\n      // 亮度重置,桌面平台可能会报错,暂时不处理桌面平台的亮度\n      try {\n        await screenBrightness.resetApplicationScreenBrightness();\n      } catch (e) {\n        Log.logPrint(e);\n      }\n    }\n\n    await WakelockPlus.disable();\n  }\n\n  /// 进入全屏\n  void enterFullScreen() async {\n    fullScreenState.value = true;\n    if (Platform.isAndroid || Platform.isIOS) {\n      //全屏\n      SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);\n      if (!isVertical.value) {\n        //横屏\n        setLandscapeOrientation();\n      }\n    } else {\n      bool isMaximized = await windowManager.isMaximized();\n      if (isMaximized) {\n        await windowManager.setFullScreen(true);\n        await windowManager.setTitleBarStyle(TitleBarStyle.hidden);\n      }\n      await windowManager.setFullScreen(true);\n    }\n    //danmakuController?.clear();\n  }\n\n  /// 退出全屏\n  void exitFull() async {\n    if (Platform.isAndroid || Platform.isIOS) {\n      SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge,\n          overlays: SystemUiOverlay.values);\n      setPortraitOrientation();\n    } else {\n      bool isMaximized = await windowManager.isMaximized();\n      if (isMaximized) {\n        await windowManager.setFullScreen(false);\n        await windowManager.setTitleBarStyle(TitleBarStyle.normal);\n      }\n      windowManager.setFullScreen(false);\n    }\n    fullScreenState.value = false;\n\n    //danmakuController?.clear();\n  }\n\n  Size? _lastWindowSize;\n  Offset? _lastWindowPosition;\n\n  ///小窗模式()\n  void enterSmallWindow() async {\n    if (!(Platform.isAndroid || Platform.isIOS)) {\n      fullScreenState.value = true;\n      smallWindowState.value = true;\n      WindowService.instance.isPIP = smallWindowState.value;\n\n      // 读取窗口大小\n      _lastWindowSize = await windowManager.getSize();\n      _lastWindowPosition = await windowManager.getPosition();\n\n      windowManager.setTitleBarStyle(TitleBarStyle.hidden);\n      // 获取视频窗口大小\n      var width = player.state.width ?? 16;\n      var height = player.state.height ?? 9;\n\n      // 横屏还是竖屏\n      if (height > width) {\n        var aspectRatio = width / height;\n        windowManager.setSize(Size(400, 400 / aspectRatio));\n      } else {\n        var aspectRatio = height / width;\n        windowManager.setSize(Size(280 / aspectRatio, 280));\n      }\n\n      windowManager.setAlwaysOnTop(true);\n    }\n  }\n\n  ///退出小窗模式()\n  void exitSmallWindow() {\n    if (!(Platform.isAndroid || Platform.isIOS)) {\n      fullScreenState.value = false;\n      smallWindowState.value = false;\n      WindowService.instance.isPIP = smallWindowState.value;\n      windowManager.setTitleBarStyle(TitleBarStyle.normal);\n      windowManager.setSize(_lastWindowSize!);\n      windowManager.setPosition(_lastWindowPosition!);\n      windowManager.setAlwaysOnTop(false);\n      //windowManager.setAlignment(Alignment.center);\n    }\n  }\n\n  /// 设置横屏\n  Future setLandscapeOrientation() async {\n    if (await beforeIOS16()) {\n      AutoOrientation.landscapeAutoMode();\n    } else {\n      SystemChrome.setPreferredOrientations([\n        DeviceOrientation.landscapeLeft,\n        DeviceOrientation.landscapeRight,\n      ]);\n    }\n  }\n\n  /// 设置竖屏\n  Future setPortraitOrientation() async {\n    if (await beforeIOS16()) {\n      AutoOrientation.portraitAutoMode();\n    } else {\n      await SystemChrome.setPreferredOrientations(DeviceOrientation.values);\n    }\n  }\n\n  /// 是否是IOS16以下\n  Future<bool> beforeIOS16() async {\n    if (Platform.isIOS) {\n      var info = await deviceInfo.iosInfo;\n      var version = info.systemVersion;\n      var versionInt = int.tryParse(version.split('.').first) ?? 0;\n      return versionInt < 16;\n    } else {\n      return false;\n    }\n  }\n\n  Future saveScreenshot() async {\n    final imageSaver = ImageGallerySaver();\n    try {\n      SmartDialog.showLoading(msg: \"正在保存截图\");\n      //检查相册权限,仅iOS需要\n      var permission = await Utils.checkPhotoPermission();\n      if (!permission) {\n        SmartDialog.showToast(\"没有相册权限\");\n        SmartDialog.dismiss(status: SmartStatus.loading);\n        return;\n      }\n\n      var imageData = await player.screenshot();\n      if (imageData == null) {\n        SmartDialog.showToast(\"截图失败,数据为空\");\n        SmartDialog.dismiss(status: SmartStatus.loading);\n        return;\n      }\n\n      if (Platform.isIOS || Platform.isAndroid) {\n        await imageSaver.saveImage(\n          imageData,\n        );\n        SmartDialog.showToast(\"已保存截图至相册\");\n      } else {\n        //选择保存文件夹\n        var path = await FilePicker.platform.saveFile(\n          allowedExtensions: [\"jpg\"],\n          type: FileType.image,\n          fileName: \"${DateTime.now().millisecondsSinceEpoch}.jpg\",\n        );\n        if (path == null) {\n          SmartDialog.showToast(\"取消保存\");\n          SmartDialog.dismiss(status: SmartStatus.loading);\n          return;\n        }\n        var file = File(path);\n        await file.writeAsBytes(imageData);\n        SmartDialog.showToast(\"已保存截图至${file.path}\");\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"截图失败\");\n    } finally {\n      SmartDialog.dismiss(status: SmartStatus.loading);\n    }\n  }\n\n  /// 开启小窗播放前弹幕状态\n  bool danmakuStateBeforePIP = false;\n\n  Future enablePIP() async {\n    if (!Platform.isAndroid) {\n      return;\n    }\n    if (await pip.isPipAvailable == false) {\n      SmartDialog.showToast(\"设备不支持小窗播放\");\n      return;\n    }\n    danmakuStateBeforePIP = showDanmakuState.value;\n    //关闭并清除弹幕\n    if (AppSettingsController.instance.pipHideDanmu.value &&\n        danmakuStateBeforePIP) {\n      showDanmakuState.value = false;\n    }\n    danmakuController?.clear();\n    //关闭控制器\n    showControlsState.value = false;\n\n    //监听事件\n    var width = player.state.width ?? 0;\n    var height = player.state.height ?? 0;\n    Rational ratio = const Rational.landscape();\n    if (height > width) {\n      ratio = const Rational.vertical();\n    } else {\n      ratio = const Rational.landscape();\n    }\n    await pip.enable(\n      ImmediatePiP(\n        aspectRatio: ratio,\n      ),\n    );\n\n    _pipSubscription ??= pip.pipStatusStream.listen((event) {\n      if (event == PiPStatus.disabled) {\n        // 返回前台时恢复弹幕\n        danmakuController?.resume();\n        showDanmakuState.value = danmakuStateBeforePIP;\n      }\n      Log.w(event.toString());\n    });\n  }\n}\nmixin PlayerGestureControlMixin\n    on PlayerStateMixin, PlayerMixin, PlayerSystemMixin {\n  /// 单击显示/隐藏控制器\n  void onTap() {\n    if (showControlsState.value) {\n      hideControls();\n    } else {\n      showControls();\n    }\n  }\n\n  //桌面端操控\n  void onEnter(PointerEnterEvent event) {\n    if (!showControlsState.value) {\n      showControls();\n    }\n  }\n\n  void onExit(PointerExitEvent event) {\n    if (showControlsState.value) {\n      hideControls();\n    }\n  }\n\n  void onHover(PointerHoverEvent event, BuildContext context) {\n    final screenHeight = MediaQuery.of(context).size.height;\n    final targetPosition = screenHeight * 0.25; // 计算屏幕顶部25%的位置\n    if (event.position.dy <= targetPosition ||\n        event.position.dy >= targetPosition * 3) {\n      if (!showControlsState.value) {\n        showControls();\n      }\n    }\n  }\n\n  /// 双击全屏/退出全屏\n  void onDoubleTap(TapDownDetails details) {\n    if (lockControlsState.value) {\n      return;\n    }\n    if (fullScreenState.value) {\n      exitFull();\n    } else {\n      enterFullScreen();\n    }\n  }\n\n  bool verticalDragging = false;\n  bool leftVerticalDrag = false;\n  var _currentVolume = 0.0;\n  var _currentBrightness = 1.0;\n  var verStartPosition = 0.0;\n\n  DelayedThrottle? throttle;\n\n  /// 竖向手势开始\n  void onVerticalDragStart(DragStartDetails details) async {\n    if (lockControlsState.value && fullScreenState.value) {\n      return;\n    }\n\n    final dy = details.globalPosition.dy;\n    // 开始位置必须是中间2/4的位置\n    if (dy < Get.height * 0.25 || dy > Get.height * 0.75) {\n      return;\n    }\n\n    verStartPosition = dy;\n    leftVerticalDrag = details.globalPosition.dx < Get.width / 2;\n\n    throttle = DelayedThrottle(200);\n\n    verticalDragging = true;\n    if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {\n      showGestureTip.value = true;\n    }\n    if (Platform.isAndroid || Platform.isIOS) {\n      _currentVolume = await volumeController.getVolume();\n    }\n    if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {\n      _currentBrightness = await screenBrightness.application;\n    }\n  }\n\n  /// 竖向手势更新\n  void onVerticalDragUpdate(DragUpdateDetails e) async {\n    if (lockControlsState.value && fullScreenState.value) {\n      return;\n    }\n    if (verticalDragging == false) return;\n    if (!Platform.isAndroid && !Platform.isIOS) {\n      return;\n    }\n    //String text = \"\";\n    //double value = 0.0;\n\n    Log.logPrint(\"$verStartPosition/${e.globalPosition.dy}\");\n\n    if (leftVerticalDrag) {\n      setGestureBrightness(e.globalPosition.dy);\n    } else {\n      setGestureVolume(e.globalPosition.dy);\n    }\n  }\n\n  int lastVolume = -1; // it's ok to be -1\n\n  void setGestureVolume(double dy) {\n    double value = 0.0;\n    double seek;\n    if (dy > verStartPosition) {\n      value = ((dy - verStartPosition) / (Get.height * 0.5));\n\n      seek = _currentVolume - value;\n      if (seek < 0) {\n        seek = 0;\n      }\n    } else {\n      value = ((dy - verStartPosition) / (Get.height * 0.5));\n      seek = value.abs() + _currentVolume;\n      if (seek > 1) {\n        seek = 1;\n      }\n    }\n    int volume = _convertVolume((seek * 100).round());\n    if (volume == lastVolume) {\n      return;\n    }\n    lastVolume = volume;\n    // update UI outside throttle to make it more fluent\n    gestureTipText.value = \"音量 $volume%\";\n    throttle?.invoke(() async => await _realSetVolume(volume));\n  }\n\n  // 0 to 100, 5 step each\n  int _convertVolume(int volume) {\n    return (volume / 5).round() * 5;\n  }\n\n  Future _realSetVolume(int volume) async {\n    Log.logPrint(volume);\n    volumeController.setVolume(volume / 100);\n  }\n\n  void setGestureBrightness(double dy) {\n    double value = 0.0;\n    if (dy > verStartPosition) {\n      value = ((dy - verStartPosition) / (Get.height * 0.5));\n\n      var seek = _currentBrightness - value;\n      if (seek < 0) {\n        seek = 0;\n      }\n      screenBrightness.setApplicationScreenBrightness(seek);\n\n      gestureTipText.value = \"亮度 ${(seek * 100).toInt()}%\";\n      Log.logPrint(value);\n    } else {\n      value = ((dy - verStartPosition) / (Get.height * 0.5));\n      var seek = value.abs() + _currentBrightness;\n      if (seek > 1) {\n        seek = 1;\n      }\n\n      screenBrightness.setApplicationScreenBrightness(seek);\n      gestureTipText.value = \"亮度 ${(seek * 100).toInt()}%\";\n      Log.logPrint(value);\n    }\n  }\n\n  /// 竖向手势完成\n  void onVerticalDragEnd(DragEndDetails details) async {\n    if (lockControlsState.value && fullScreenState.value) {\n      return;\n    }\n    throttle = null;\n    verticalDragging = false;\n    leftVerticalDrag = false;\n    showGestureTip.value = false;\n  }\n}\n\nclass PlayerController extends BaseController\n    with\n        PlayerMixin,\n        PlayerStateMixin,\n        PlayerDanmakuMixin,\n        PlayerSystemMixin,\n        PlayerGestureControlMixin {\n  @override\n  void onInit() {\n    initSystem();\n    initStream();\n    //设置音量\n    player.setVolume(AppSettingsController.instance.playerVolume.value);\n    super.onInit();\n  }\n\n  StreamSubscription<String>? _errorSubscription;\n  StreamSubscription? _completedSubscription;\n  StreamSubscription? _widthSubscription;\n  StreamSubscription? _heightSubscription;\n  StreamSubscription? _logSubscription;\n  StreamSubscription? _playingSubscription;\n  StreamSubscription? _escSubscription;\n\n  void initStream() {\n    _errorSubscription = player.stream.error.listen((event) {\n      Log.d(\"播放器错误：$event\");\n      // 跳过无音频输出的错误\n      // Could not open/initialize audio device -> no sound.\n      if (event.contains('no sound.')) {\n        return;\n      }\n      //SmartDialog.showToast(event);\n      mediaError(event);\n    });\n\n    _playingSubscription = player.stream.playing.listen((event) {\n      if (event) {\n        WakelockPlus.enable();\n        Log.d(\"Playing\");\n      }\n    });\n\n    _completedSubscription = player.stream.completed.listen((event) {\n      if (event) {\n        mediaEnd();\n      }\n    });\n    _logSubscription = player.stream.log.listen((event) {\n      Log.d(\"播放器日志：$event\");\n    });\n    _widthSubscription = player.stream.width.listen((event) {\n      Log.d(\n          'width:$event  W:${(player.state.width)}  H:${(player.state.height)}');\n      if (player.state.width == null) {\n        return;\n      } else {\n        // 可获取直播流size时且不为全屏模式时判断是否进入全屏模式\n        isVertical.value = player.state.height! > player.state.width!;\n        if (AppSettingsController.instance.autoFullScreen.value &&\n            !fullScreenState.value) {\n          enterFullScreen();\n        }\n      }\n    });\n    _heightSubscription = player.stream.height.listen((event) {\n      Log.d(\n          'height:$event  W:${(player.state.width)}  H:${(player.state.height)}');\n      isVertical.value =\n          (player.state.height ?? 9) > (player.state.width ?? 16);\n    });\n    _escSubscription =\n        EventBus.instance.listen(EventBus.kEscapePressed, (event) {\n      exitFull();\n    });\n  }\n\n  void disposeStream() {\n    _errorSubscription?.cancel();\n    _completedSubscription?.cancel();\n    _widthSubscription?.cancel();\n    _heightSubscription?.cancel();\n    _logSubscription?.cancel();\n    _pipSubscription?.cancel();\n    _playingSubscription?.cancel();\n    _escSubscription?.cancel();\n  }\n\n  void mediaEnd() {\n    WakelockPlus.disable();\n  }\n\n  void mediaError(String error) {\n   // 弱网调整：用户自责\n   // WakelockPlus.disable();\n  }\n\n  Future<void> toggleOSDStats() async {\n    showOSDStats.value = !showOSDStats.value;\n    if (player.platform is NativePlayer) {\n      await (player.platform as NativePlayer).command([\n        'script-binding',\n        'stats/display-page-1-toggle',\n      ]);\n    }\n  }\n\n  void showDebugInfo() {\n    Utils.showBottomSheet(\n      title: \"播放信息\",\n      child: ListView(\n        children: [\n          Obx(() => SwitchListTile(\n              title: const Text(\"OSD 显示\"),\n              value: showOSDStats.value,\n              onChanged: (value) => toggleOSDStats())),\n          ListTile(\n            title: const Text(\"Resolution\"),\n            subtitle: Text('${player.state.width}x${player.state.height}'),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text:\n                      \"Resolution\\n${player.state.width}x${player.state.height}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"VideoParams\"),\n            subtitle: Text(player.state.videoParams.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"VideoParams\\n${player.state.videoParams}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"AudioParams\"),\n            subtitle: Text(player.state.audioParams.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"AudioParams\\n${player.state.audioParams}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"Media\"),\n            subtitle: Text(player.state.playlist.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"Media\\n${player.state.playlist}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"AudioTrack\"),\n            subtitle: Text(player.state.track.audio.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"AudioTrack\\n${player.state.track.audio}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"VideoTrack\"),\n            subtitle: Text(player.state.track.video.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"VideoTrack\\n${player.state.track.audio}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"AudioBitrate\"),\n            subtitle: Text(player.state.audioBitrate.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"AudioBitrate\\n${player.state.audioBitrate}\",\n                ),\n              );\n            },\n          ),\n          ListTile(\n            title: const Text(\"Volume\"),\n            subtitle: Text(player.state.volume.toString()),\n            onTap: () {\n              Clipboard.setData(\n                ClipboardData(\n                  text: \"Volume\\n${player.state.volume}\",\n                ),\n              );\n            },\n          ),\n        ],\n      ),\n    );\n  }\n\n  @override\n  void onClose() async {\n    Log.w(\"播放器关闭\");\n    if (smallWindowState.value) {\n      exitSmallWindow();\n    }\n    disposeStream();\n    disposeDanmakuController();\n    await resetSystem();\n    await player.dispose();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/live_room/player/player_controls.dart",
    "content": "import 'dart:io';\nimport 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:flutter/gestures.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_app/modules/settings/appstyle_settings/appstyle_setting_contorller.dart';\nimport 'package:simple_live_app/modules/settings/danmu_settings_page.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/widgets/desktop_refresh_button.dart';\nimport 'package:simple_live_app/widgets/follow_user_item.dart';\nimport 'package:window_manager/window_manager.dart';\n\nWidget playerControls(\n  VideoState videoState,\n  LiveRoomController controller,\n) {\n  return Obx(() {\n    if (controller.fullScreenState.value) {\n      return buildFullControls(\n        videoState,\n        controller,\n      );\n    }\n    return buildControls(\n      videoState.context.orientation == Orientation.portrait,\n      videoState,\n      controller,\n    );\n  });\n}\n\nWidget buildFullControls(\n  VideoState videoState,\n  LiveRoomController controller,\n) {\n  var padding = MediaQuery.of(videoState.context).padding;\n  GlobalKey volumeButtonkey = GlobalKey();\n  return DragToMoveArea(\n    child: Stack(\n      children: [\n        Container(),\n        buildDanmuView(videoState, controller),\n\n        Center(\n          child: // 中间\n              StreamBuilder(\n            stream: videoState.widget.controller.player.stream.buffering,\n            initialData: videoState.widget.controller.player.state.buffering,\n            builder: (_, s) => Visibility(\n              visible: s.data ?? false,\n              child: const Center(\n                child: CircularProgressIndicator(),\n              ),\n            ),\n          ),\n        ),\n        Positioned.fill(\n          child: GestureDetector(\n            onTap: controller.onTap,\n            onDoubleTapDown: controller.onDoubleTap,\n            onLongPress: () {\n              if (controller.lockControlsState.value) {\n                return;\n              }\n              showFollowUser(controller);\n            },\n            onVerticalDragStart: controller.onVerticalDragStart,\n            onVerticalDragUpdate: controller.onVerticalDragUpdate,\n            onVerticalDragEnd: controller.onVerticalDragEnd,\n            child: MouseRegion(\n              onHover: (PointerHoverEvent event) {\n                controller.onHover(event, videoState.context);\n              },\n              child: Container(\n                width: double.infinity,\n                height: double.infinity,\n                color: Colors.transparent,\n                // child: Visibility(\n                //   //拖拽区域\n                //   visible: controller.smallWindowState.value,\n                //   child: DragToMoveArea(\n                //       child: Container(\n                //     width: double.infinity,\n                //     height: double.infinity,\n                //     color: Colors.transparent,\n                //   )),\n                // ),\n              ),\n            ),\n          ),\n        ),\n\n        // 顶部\n        Obx(\n          () => AnimatedPositioned(\n            left: 0,\n            right: 0,\n            top: (controller.showControlsState.value &&\n                    !controller.lockControlsState.value)\n                ? 0\n                : -(48 + padding.top),\n            duration: const Duration(milliseconds: 200),\n            child: Container(\n              height: 48 + padding.top,\n              padding: EdgeInsets.only(\n                left: padding.left + 12,\n                right: padding.right + 12,\n                top: padding.top,\n              ),\n              decoration: const BoxDecoration(\n                gradient: LinearGradient(\n                  begin: Alignment.bottomCenter,\n                  end: Alignment.topCenter,\n                  colors: [\n                    Colors.transparent,\n                    Colors.black87,\n                  ],\n                ),\n              ),\n              child: Row(\n                children: [\n                  IconButton(\n                    onPressed: () {\n                      if (controller.smallWindowState.value) {\n                        controller.exitSmallWindow();\n                      } else {\n                        controller.exitFull();\n                      }\n                    },\n                    icon: const Icon(\n                      Icons.arrow_back,\n                      color: Colors.white,\n                      size: 24,\n                    ),\n                  ),\n                  AppStyle.hGap12,\n                  Expanded(\n                    child: Text(\n                      \"${controller.detail.value?.title} - ${controller.detail.value?.userName}\",\n                      maxLines: 1,\n                      overflow: TextOverflow.ellipsis,\n                      style: const TextStyle(color: Colors.white, fontSize: 16),\n                    ),\n                  ),\n                  AppStyle.hGap12,\n                  IconButton(\n                    onPressed: () {\n                      controller.saveScreenshot();\n                    },\n                    icon: const Icon(\n                      Icons.camera_alt_outlined,\n                      color: Colors.white,\n                      size: 24,\n                    ),\n                  ),\n                  IconButton(\n                    onPressed: () {\n                      showFollowUser(controller);\n                    },\n                    icon: const Icon(\n                      Remix.play_list_2_line,\n                      color: Colors.white,\n                      size: 24,\n                    ),\n                  ),\n                  Visibility(\n                    visible: Platform.isAndroid,\n                    child: IconButton(\n                      onPressed: () {\n                        controller.enablePIP();\n                      },\n                      icon: const Icon(\n                        Icons.picture_in_picture,\n                        color: Colors.white,\n                        size: 24,\n                      ),\n                    ),\n                  ),\n                  IconButton(\n                    onPressed: () {\n                      showPlayerSettings(controller);\n                    },\n                    icon: const Icon(\n                      Icons.more_horiz,\n                      color: Colors.white,\n                      size: 24,\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n        ),\n        // 底部\n        Obx(\n          () => AnimatedPositioned(\n            left: 0,\n            right: 0,\n            bottom: (controller.showControlsState.value &&\n                    !controller.lockControlsState.value)\n                ? 0\n                : -(80 + padding.bottom),\n            duration: const Duration(milliseconds: 200),\n            child: Container(\n              decoration: const BoxDecoration(\n                gradient: LinearGradient(\n                  begin: Alignment.topCenter,\n                  end: Alignment.bottomCenter,\n                  colors: [\n                    Colors.transparent,\n                    Colors.black87,\n                  ],\n                ),\n              ),\n              padding: EdgeInsets.only(\n                left: padding.left + 12,\n                right: padding.right + 12,\n                bottom: padding.bottom,\n              ),\n              child: Row(\n                children: [\n                  IconButton(\n                    onPressed: () {\n                      controller.refreshRoom();\n                    },\n                    icon: const Icon(\n                      Remix.refresh_line,\n                      color: Colors.white,\n                    ),\n                  ),\n                  Offstage(\n                    offstage: controller.showDanmakuState.value,\n                    child: IconButton(\n                      onPressed: () => controller.showDanmakuState.value =\n                          !controller.showDanmakuState.value,\n                      icon: const ImageIcon(\n                        AssetImage('assets/icons/icon_danmaku_open.png'),\n                        size: 24,\n                        color: Colors.white,\n                      ),\n                    ),\n                  ),\n                  Offstage(\n                    offstage: !controller.showDanmakuState.value,\n                    child: IconButton(\n                      onPressed: () => controller.showDanmakuState.value =\n                          !controller.showDanmakuState.value,\n                      icon: const ImageIcon(\n                        AssetImage('assets/icons/icon_danmaku_close.png'),\n                        size: 24,\n                        color: Colors.white,\n                      ),\n                    ),\n                  ),\n                  IconButton(\n                    onPressed: () {\n                      showDanmakuSettings(controller);\n                    },\n                    icon: const ImageIcon(\n                      AssetImage('assets/icons/icon_danmaku_setting.png'),\n                      size: 24,\n                      color: Colors.white,\n                    ),\n                  ),\n                  const Expanded(child: Center()),\n                  Visibility(\n                    visible: !Platform.isAndroid && !Platform.isIOS,\n                    child: IconButton(\n                      key: volumeButtonkey,\n                      onPressed: () {\n                        controller\n                            .showVolumeSlider(volumeButtonkey.currentContext!);\n                      },\n                      icon: const Icon(\n                        Icons.volume_down,\n                        size: 24,\n                        color: Colors.white,\n                      ),\n                    ),\n                  ),\n                  TextButton(\n                    onPressed: () {\n                      showQualitesInfo(controller);\n                    },\n                    child: Obx(\n                      () => Text(\n                        controller.currentQualityInfo.value,\n                        style:\n                            const TextStyle(color: Colors.white, fontSize: 15),\n                      ),\n                    ),\n                  ),\n                  TextButton(\n                    onPressed: () {\n                      showLinesInfo(controller);\n                    },\n                    child: Text(\n                      controller.currentLineInfo.value,\n                      style: const TextStyle(color: Colors.white, fontSize: 15),\n                    ),\n                  ),\n                  IconButton(\n                    onPressed: () {\n                      if (controller.smallWindowState.value) {\n                        controller.exitSmallWindow();\n                      } else {\n                        controller.exitFull();\n                      }\n                    },\n                    icon: const Icon(\n                      Remix.fullscreen_exit_fill,\n                      color: Colors.white,\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n        ),\n\n        // 右侧锁定\n        Obx(\n          () => AnimatedPositioned(\n            top: 0,\n            bottom: 0,\n            right: controller.showControlsState.value\n                ? padding.right + 12\n                : -(64 + padding.right),\n            duration: const Duration(milliseconds: 200),\n            child: buildLockButton(controller),\n          ),\n        ),\n        // 左侧锁定\n        Obx(\n          () => AnimatedPositioned(\n            top: 0,\n            bottom: 0,\n            left: controller.showControlsState.value\n                ? padding.left + 12\n                : -(64 + padding.right),\n            duration: const Duration(milliseconds: 200),\n            child: buildLockButton(controller),\n          ),\n        ),\n        Obx(\n          () => Offstage(\n            offstage: !controller.showGestureTip.value,\n            child: Center(\n              child: Container(\n                padding: const EdgeInsets.all(12),\n                decoration: BoxDecoration(\n                  color: Colors.grey.shade900,\n                  borderRadius: BorderRadius.circular(12),\n                ),\n                child: Text(\n                  controller.gestureTipText.value,\n                  style: const TextStyle(fontSize: 18, color: Colors.white),\n                ),\n              ),\n            ),\n          ),\n        ),\n      ],\n    ),\n  );\n}\n\nWidget buildLockButton(LiveRoomController controller) {\n  return Center(\n    child: InkWell(\n      onTap: () {\n        controller.setLockState();\n      },\n      child: Container(\n        decoration: BoxDecoration(\n          color: Colors.black45,\n          borderRadius: AppStyle.radius8,\n        ),\n        width: 40,\n        height: 40,\n        child: Center(\n          child: Icon(\n            controller.lockControlsState.value\n                ? Icons.lock_outline_rounded\n                : Icons.lock_open_outlined,\n            color: Colors.white,\n            size: 20,\n          ),\n        ),\n      ),\n    ),\n  );\n}\n\nWidget buildControls(\n  bool isPortrait,\n  VideoState videoState,\n  LiveRoomController controller,\n) {\n  GlobalKey volumeButtonkey = GlobalKey();\n  return Stack(\n    children: [\n      Container(),\n      buildDanmuView(videoState, controller),\n      // 中间\n      Center(\n        child: StreamBuilder(\n          stream: videoState.widget.controller.player.stream.buffering,\n          initialData: videoState.widget.controller.player.state.buffering,\n          builder: (_, s) => Visibility(\n            visible: s.data ?? false,\n            child: const Center(\n              child: CircularProgressIndicator(),\n            ),\n          ),\n        ),\n      ),\n      Positioned.fill(\n        child: GestureDetector(\n          onTap: controller.onTap,\n          onDoubleTapDown: controller.onDoubleTap,\n          onVerticalDragStart: controller.onVerticalDragStart,\n          onVerticalDragUpdate: controller.onVerticalDragUpdate,\n          onVerticalDragEnd: controller.onVerticalDragEnd,\n          //onLongPress: controller.showDebugInfo,\n          child: MouseRegion(\n            onEnter: controller.onEnter,\n            child: Container(\n              width: double.infinity,\n              height: double.infinity,\n              color: Colors.transparent,\n            ),\n          ),\n        ),\n      ),\n      Obx(\n        () => AnimatedPositioned(\n          left: 0,\n          right: 0,\n          bottom: controller.showControlsState.value ? 0 : -48,\n          duration: const Duration(milliseconds: 200),\n          child: Container(\n            decoration: const BoxDecoration(\n              gradient: LinearGradient(\n                begin: Alignment.topCenter,\n                end: Alignment.bottomCenter,\n                colors: [\n                  Colors.transparent,\n                  Colors.black87,\n                ],\n              ),\n            ),\n            child: Row(\n              children: [\n                IconButton(\n                  onPressed: () {\n                    controller.refreshRoom();\n                  },\n                  icon: const Icon(\n                    Remix.refresh_line,\n                    color: Colors.white,\n                  ),\n                ),\n                Offstage(\n                  offstage: controller.showDanmakuState.value,\n                  child: IconButton(\n                    onPressed: () => controller.showDanmakuState.value =\n                        !controller.showDanmakuState.value,\n                    icon: const ImageIcon(\n                      AssetImage('assets/icons/icon_danmaku_open.png'),\n                      size: 24,\n                      color: Colors.white,\n                    ),\n                  ),\n                ),\n                Offstage(\n                  offstage: !controller.showDanmakuState.value,\n                  child: IconButton(\n                    onPressed: () => controller.showDanmakuState.value =\n                        !controller.showDanmakuState.value,\n                    icon: const ImageIcon(\n                      AssetImage('assets/icons/icon_danmaku_close.png'),\n                      size: 24,\n                      color: Colors.white,\n                    ),\n                  ),\n                ),\n                IconButton(\n                  onPressed: () {\n                    controller.showDanmuSettingsSheet();\n                  },\n                  icon: const ImageIcon(\n                    AssetImage('assets/icons/icon_danmaku_setting.png'),\n                    size: 24,\n                    color: Colors.white,\n                  ),\n                ),\n                const Expanded(child: Center()),\n                Visibility(\n                  visible: !Platform.isAndroid && !Platform.isIOS,\n                  child: IconButton(\n                    key: volumeButtonkey,\n                    onPressed: () {\n                      controller.showVolumeSlider(\n                        volumeButtonkey.currentContext!,\n                      );\n                    },\n                    icon: const Icon(\n                      Icons.volume_down,\n                      size: 24,\n                      color: Colors.white,\n                    ),\n                  ),\n                ),\n                Offstage(\n                  offstage: isPortrait,\n                  child: TextButton(\n                    onPressed: () {\n                      controller.showQualitySheet();\n                    },\n                    child: Obx(\n                      () => Text(\n                        controller.currentQualityInfo.value,\n                        style:\n                            const TextStyle(color: Colors.white, fontSize: 15),\n                      ),\n                    ),\n                  ),\n                ),\n                Offstage(\n                  offstage: isPortrait,\n                  child: TextButton(\n                    onPressed: () {\n                      controller.showPlayUrlsSheet();\n                    },\n                    child: Text(\n                      controller.currentLineInfo.value,\n                      style: const TextStyle(color: Colors.white, fontSize: 15),\n                    ),\n                  ),\n                ),\n                Visibility(\n                  visible: !Platform.isAndroid && !Platform.isIOS,\n                  child: IconButton(\n                    onPressed: () {\n                      controller.enterSmallWindow();\n                    },\n                    icon: const Icon(\n                      Icons.picture_in_picture,\n                      color: Colors.white,\n                      size: 24,\n                    ),\n                  ),\n                ),\n                IconButton(\n                  onPressed: () {\n                    controller.enterFullScreen();\n                  },\n                  icon: const Icon(\n                    Remix.fullscreen_line,\n                    color: Colors.white,\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ),\n      ),\n      Obx(\n        () => Offstage(\n          offstage: !controller.showGestureTip.value,\n          child: Center(\n            child: Container(\n              padding: const EdgeInsets.all(12),\n              decoration: BoxDecoration(\n                color: Colors.grey.shade900,\n                borderRadius: BorderRadius.circular(12),\n              ),\n              child: Text(\n                controller.gestureTipText.value,\n                style: const TextStyle(fontSize: 18, color: Colors.white),\n              ),\n            ),\n          ),\n        ),\n      ),\n    ],\n  );\n}\n\nWidget buildDanmuView(VideoState videoState, LiveRoomController controller) {\n  var padding = MediaQuery.of(videoState.context).padding;\n  controller.danmakuView ??= DanmakuScreen(\n    createdController: controller.initDanmakuController,\n    option: DanmakuOption(\n      fontSize: AppSettingsController.instance.danmuSize.value,\n      area: AppSettingsController.instance.danmuArea.value,\n      duration: AppSettingsController.instance.danmuSpeed.value,\n      opacity: AppSettingsController.instance.danmuOpacity.value,\n      strokeWidth: AppSettingsController.instance.danmuStrokeWidth.value,\n      fontWeight: AppSettingsController.instance.danmuFontWeight.value,\n      fontFamily: AppStyleSettingController.instance.curFontName.value,\n    ),\n  );\n  return Positioned.fill(\n    top: padding.top,\n    bottom: padding.bottom,\n    child: Obx(\n      () => Offstage(\n        offstage: !controller.showDanmakuState.value,\n        child: Padding(\n          padding: controller.fullScreenState.value\n              ? EdgeInsets.only(\n                  top: AppSettingsController.instance.danmuTopMargin.value,\n                  bottom:\n                      AppSettingsController.instance.danmuBottomMargin.value,\n                )\n              : EdgeInsets.zero,\n          child: controller.danmakuView!,\n        ),\n      ),\n    ),\n  );\n}\n\nvoid showLinesInfo(LiveRoomController controller) {\n  if (controller.isVertical.value) {\n    controller.showPlayUrlsSheet();\n    return;\n  }\n  Utils.showRightDialog(\n    title: \"线路\",\n    useSystem: true,\n    child: ListView.builder(\n      padding: EdgeInsets.zero,\n      itemCount: controller.playUrls.length,\n      itemBuilder: (_, i) {\n        return ListTile(\n          selected: controller.currentLineIndex == i,\n          title: Text.rich(\n            TextSpan(\n              text: \"线路${i + 1}\",\n              children: [\n                WidgetSpan(\n                    child: Container(\n                  decoration: BoxDecoration(\n                    borderRadius: AppStyle.radius4,\n                    border: Border.all(\n                      color: Colors.grey,\n                    ),\n                  ),\n                  padding: AppStyle.edgeInsetsH4,\n                  margin: AppStyle.edgeInsetsL8,\n                  child: Text(\n                    controller.playUrls[i].contains(\".flv\") ? \"FLV\" : \"HLS\",\n                    style: const TextStyle(\n                      fontSize: 12,\n                    ),\n                  ),\n                )),\n              ],\n            ),\n            style: const TextStyle(fontSize: 14),\n          ),\n          minLeadingWidth: 16,\n          onTap: () {\n            Utils.hideRightDialog();\n            //controller.currentLineIndex = i;\n            //controller.setPlayer();\n            controller.changePlayLine(i);\n          },\n        );\n      },\n    ),\n  );\n}\n\nvoid showQualitesInfo(LiveRoomController controller) {\n  if (controller.isVertical.value) {\n    controller.showQualitySheet();\n    return;\n  }\n  Utils.showRightDialog(\n    title: \"清晰度\",\n    useSystem: true,\n    child: ListView.builder(\n      padding: EdgeInsets.zero,\n      itemCount: controller.qualites.length,\n      itemBuilder: (_, i) {\n        var item = controller.qualites[i];\n        return ListTile(\n          selected: controller.currentQuality == i,\n          title: Text(\n            item.quality,\n            style: const TextStyle(fontSize: 14),\n          ),\n          minLeadingWidth: 16,\n          onTap: () {\n            Utils.hideRightDialog();\n            controller.currentQuality = i;\n            controller.getPlayUrl();\n          },\n        );\n      },\n    ),\n  );\n}\n\nvoid showDanmakuSettings(LiveRoomController controller) {\n  if (controller.isVertical.value) {\n    controller.showDanmuSettingsSheet();\n    return;\n  }\n  Utils.showRightDialog(\n    title: \"弹幕设置\",\n    width: 400,\n    useSystem: true,\n    child: ListView(\n      padding: AppStyle.edgeInsetsA12,\n      children: [\n        DanmuSettingsView(\n          danmakuController: controller.danmakuController,\n        ),\n      ],\n    ),\n  );\n}\n\nvoid showPlayerSettings(LiveRoomController controller) {\n  if (controller.isVertical.value) {\n    controller.showPlayerSettingsSheet();\n    return;\n  }\n  Utils.showRightDialog(\n    title: \"设置\",\n    width: 320,\n    useSystem: true,\n    child: Obx(\n      () => ListView(\n        padding: AppStyle.edgeInsetsV12,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsH16,\n            child: Text(\n              \"画面尺寸\",\n              style: Get.textTheme.titleMedium,\n            ),\n          ),\n          RadioGroup(\n            groupValue: AppSettingsController.instance.scaleMode.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setScaleMode(e ?? 0);\n              controller.updateScaleMode();\n            },\n            child: Column(\n              children: [\n                RadioListTile(\n                  value: 0,\n                  contentPadding: AppStyle.edgeInsetsH4,\n                  title: const Text(\"适应\"),\n                  visualDensity: VisualDensity.compact,\n                ),\n                RadioListTile(\n                  value: 1,\n                  contentPadding: AppStyle.edgeInsetsH4,\n                  title: const Text(\"拉伸\"),\n                  visualDensity: VisualDensity.compact,\n                ),\n                RadioListTile(\n                  value: 2,\n                  contentPadding: AppStyle.edgeInsetsH4,\n                  title: const Text(\"铺满\"),\n                  visualDensity: VisualDensity.compact,\n                ),\n                RadioListTile(\n                  value: 3,\n                  contentPadding: AppStyle.edgeInsetsH4,\n                  title: const Text(\"16:9\"),\n                  visualDensity: VisualDensity.compact,\n                ),\n                RadioListTile(\n                  value: 4,\n                  contentPadding: AppStyle.edgeInsetsH4,\n                  title: const Text(\"4:3\"),\n                  visualDensity: VisualDensity.compact,\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    ),\n  );\n}\n\nvoid showFollowUser(LiveRoomController controller) {\n  if (controller.isVertical.value) {\n    controller.showFollowUserSheet();\n    return;\n  }\n\n  Utils.showRightDialog(\n    title: \"关注列表\",\n    width: 400,\n    useSystem: true,\n    child: Obx(\n      () => Stack(\n        children: [\n          RefreshIndicator(\n            onRefresh: FollowService.instance.loadData,\n            child: ListView.builder(\n              itemCount: FollowService.instance.liveList.length,\n              itemBuilder: (_, i) {\n                var item = FollowService.instance.liveList[i];\n                return Obx(\n                  () => FollowUserItem(\n                    item: item,\n                    playing: controller.rxSite.value.id == item.siteId &&\n                        controller.rxRoomId.value == item.roomId,\n                    onTap: () {\n                      Utils.hideRightDialog();\n                      controller.resetRoom(\n                        Sites.allSites[item.siteId]!,\n                        item.roomId,\n                      );\n                    },\n                  ),\n                );\n              },\n            ),\n          ),\n          if (Platform.isLinux || Platform.isWindows || Platform.isMacOS)\n            Positioned(\n              right: 12,\n              bottom: 12,\n              child: Obx(\n                () => DesktopRefreshButton(\n                  refreshing: FollowService.instance.updating.value,\n                  onPressed: FollowService.instance.loadData,\n                ),\n              ),\n            ),\n        ],\n      ),\n    ),\n  );\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/account_controller.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/douyin_account_service.dart';\n\nclass AccountController extends GetxController {\n  void bilibiliTap() async {\n    if (BiliBiliAccountService.instance.logined.value) {\n      var result = await Utils.showAlertDialog(\"确定要退出哔哩哔哩账号吗？\", title: \"退出登录\");\n      if (result) {\n        BiliBiliAccountService.instance.logout();\n      }\n    } else {\n      //AppNavigator.toBiliBiliLogin();\n      bilibiliLogin();\n    }\n  }\n\n  void bilibiliLogin() {\n    Utils.showBottomSheet(\n      title: \"登录哔哩哔哩\",\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          Visibility(\n            visible: Platform.isAndroid || Platform.isIOS,\n            child: ListTile(\n              leading: const Icon(Icons.account_circle_outlined),\n              title: const Text(\"Web登录\"),\n              subtitle: const Text(\"填写用户名密码登录\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.back();\n                Get.toNamed(RoutePath.kBiliBiliWebLogin);\n              },\n            ),\n          ),\n          ListTile(\n            leading: const Icon(Icons.qr_code),\n            title: const Text(\"扫码登录\"),\n            subtitle: const Text(\"使用哔哩哔哩APP扫描二维码登录\"),\n            trailing: const Icon(Icons.chevron_right),\n            onTap: () {\n              Get.back();\n              Get.toNamed(RoutePath.kBiliBiliQRLogin);\n            },\n          ),\n          ListTile(\n            leading: const Icon(Icons.edit_outlined),\n            title: const Text(\"Cookie登录\"),\n            subtitle: const Text(\"手动输入Cookie登录\"),\n            trailing: const Icon(Icons.chevron_right),\n            onTap: () {\n              Get.back();\n              doCookieLogin();\n            },\n          ),\n        ],\n      ),\n    );\n  }\n\n  void doCookieLogin() async {\n    var cookie = await Utils.showEditTextDialog(\n      \"\",\n      title: \"请输入Cookie\",\n      hintText: \"请输入Cookie\",\n    );\n    if (cookie == null || cookie.isEmpty) {\n      return;\n    }\n    BiliBiliAccountService.instance.setCookie(cookie);\n    await BiliBiliAccountService.instance.loadUserInfo();\n  }\n\n  // 需要用户手动复制抖音的Cookie\n  void douyinTap() async {\n    if (DouyinAccountService.instance.logined.value) {\n      var result =\n          await Utils.showAlertDialog(\"确定要清除抖音Cookie吗？\", title: \"清除Cookie\");\n      if (result) {\n        DouyinAccountService.instance.logout();\n      }\n    } else {\n      final cookie = await Utils.showEditTextDialog(\n        \"\",\n        title: \"请输入抖音Cookie\",\n        hintText: \"__ac_nonce=...;__ac_signature=...;sessionid=...;\",\n      );\n      if (cookie == null || cookie.isEmpty) return;\n      DouyinAccountService.instance.setCookie(cookie);\n      // 检查输入的cookie是否有效\n      await DouyinAccountService.instance.loadUserInfo();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/account_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/mine/account/account_controller.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/douyin_account_service.dart';\n\nclass AccountPage extends GetView<AccountController> {\n  const AccountPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"账号管理\"),\n      ),\n      body: ListView(\n        children: [\n          const Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Text(\n              \"哔哩哔哩账号需要登录才能看高清晰度的直播，其他平台暂无此限制。\",\n              textAlign: TextAlign.center,\n            ),\n          ),\n          Obx(\n            () => ListTile(\n              leading: Image.asset(\n                'assets/images/bilibili_2.png',\n                width: 36,\n                height: 36,\n              ),\n              title: const Text(\"哔哩哔哩\"),\n              subtitle: Text(BiliBiliAccountService.instance.name.value),\n              trailing: BiliBiliAccountService.instance.logined.value\n                  ? const Icon(Icons.logout)\n                  : const Icon(Icons.chevron_right),\n              onTap: controller.bilibiliTap,\n            ),\n          ),\n          ListTile(\n            leading: Image.asset(\n              'assets/images/douyu.png',\n              width: 36,\n              height: 36,\n            ),\n            title: const Text(\"斗鱼直播\"),\n            subtitle: const Text(\"无需登录\"),\n            enabled: false,\n            trailing: const Icon(Icons.chevron_right),\n          ),\n          ListTile(\n            leading: Image.asset(\n              'assets/images/huya.png',\n              width: 36,\n              height: 36,\n            ),\n            title: const Text(\"虎牙直播\"),\n            subtitle: const Text(\"无需登录\"),\n            enabled: false,\n            trailing: const Icon(Icons.chevron_right),\n          ),\n          Obx(\n            () => ListTile(\n              leading: Image.asset(\n                'assets/images/douyin.png',\n                width: 36,\n                height: 36,\n              ),\n              title: const Text(\"抖音直播\"),\n              subtitle: Text(DouyinAccountService.instance.name.value),\n              trailing: DouyinAccountService.instance.logined.value\n                  ? const Icon(Icons.logout)\n                  : const Icon(Icons.chevron_right),\n              onTap: controller.douyinTap,\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/bilibili/qr_login_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/requests/http_client.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\n\nenum QRStatus {\n  loading,\n  unscanned,\n  scanned,\n  expired,\n  failed,\n}\n\nclass BiliBiliQRLoginController extends GetxController {\n  @override\n  void onInit() {\n    loadQRCode();\n    super.onInit();\n  }\n\n  Timer? timer;\n\n  var qrcodeUrl = \"\".obs;\n  var qrcodeKey = \"\";\n\n  /// 二维码状态\n  /// - [0] 加载中\n  /// - [1] 未扫描\n  /// - [2] 已扫描，待确认\n  /// - [3] 二维码已经失效\n  /// - [4] 登录失败\n  Rx<QRStatus> qrStatus = QRStatus.loading.obs;\n\n  void loadQRCode() async {\n    try {\n      qrStatus.value = QRStatus.loading;\n\n      var result = await HttpClient.instance.getJson(\n        \"https://passport.bilibili.com/x/passport-login/web/qrcode/generate\",\n      );\n      if (result[\"code\"] != 0) {\n        throw result[\"message\"];\n      }\n      qrcodeKey = result[\"data\"][\"qrcode_key\"];\n      qrcodeUrl.value = result[\"data\"][\"url\"];\n      qrStatus.value = QRStatus.unscanned;\n      startPoll();\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(e.toString());\n      qrStatus.value = QRStatus.failed;\n    }\n  }\n\n  void startPoll() {\n    timer = Timer.periodic(\n      const Duration(seconds: 3),\n      (timer) {\n        pollQRStatus();\n      },\n    );\n  }\n\n  void pollQRStatus() async {\n    try {\n      var response = await HttpClient.instance.get(\n        \"https://passport.bilibili.com/x/passport-login/web/qrcode/poll\",\n        queryParameters: {\n          \"qrcode_key\": qrcodeKey,\n        },\n      );\n      if (response.data[\"code\"] != 0) {\n        throw response.data[\"message\"];\n      }\n      var data = response.data[\"data\"];\n      var code = data[\"code\"];\n      if (code == 0) {\n        var cookies = <String>[];\n        response.headers[\"set-cookie\"]?.forEach((element) {\n          var cookie = element.split(\";\")[0];\n          cookies.add(cookie);\n        });\n        if (cookies.isNotEmpty) {\n          var cookieStr = cookies.join(\";\");\n          Log.i(cookieStr);\n          BiliBiliAccountService.instance.setCookie(cookieStr);\n          await BiliBiliAccountService.instance.loadUserInfo();\n          Get.back();\n        }\n      } else if (code == 86038) {\n        qrStatus.value = QRStatus.expired;\n        qrcodeKey = \"\";\n        timer?.cancel();\n      } else if (code == 86090) {\n        qrStatus.value = QRStatus.scanned;\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(e.toString());\n    }\n  }\n\n  @override\n  void onClose() {\n    timer?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/bilibili/qr_login_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_flutter/qr_flutter.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/qr_login_controller.dart';\n\nclass BiliBiliQRLoginPage extends GetView<BiliBiliQRLoginController> {\n  const BiliBiliQRLoginPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text(\"哔哩哔哩账号登录\")),\n      body: Column(\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        mainAxisAlignment: MainAxisAlignment.center,\n        children: [\n          Center(\n            child: Obx(\n              () {\n                if (controller.qrStatus.value == QRStatus.loading) {\n                  return const CircularProgressIndicator();\n                }\n                if (controller.qrStatus.value == QRStatus.failed) {\n                  return Column(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      const Text(\"二维码加载失败\"),\n                      TextButton(\n                        onPressed: controller.loadQRCode,\n                        child: const Text(\"重试\"),\n                      ),\n                    ],\n                  );\n                }\n                if (controller.qrStatus.value == QRStatus.failed) {\n                  return Column(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      const Text(\"二维码已失效\"),\n                      TextButton(\n                        onPressed: controller.loadQRCode,\n                        child: const Text(\"刷新二维码\"),\n                      ),\n                    ],\n                  );\n                }\n                return Column(\n                  children: [\n                    ClipRRect(\n                      borderRadius: AppStyle.radius12,\n                      child: QrImageView(\n                        data: controller.qrcodeUrl.value,\n                        version: QrVersions.auto,\n                        backgroundColor: Colors.white,\n                        size: 200.0,\n                        padding: AppStyle.edgeInsetsA12,\n                      ),\n                    ),\n                    AppStyle.vGap8,\n                    Visibility(\n                      visible: controller.qrStatus.value == QRStatus.scanned,\n                      child: const Text(\"已扫描，请在手机上确认登录\"),\n                    ),\n                  ],\n                );\n              },\n            ),\n          ),\n          const Padding(\n            padding: AppStyle.edgeInsetsA24,\n            child: Text(\n              \"请使用哔哩哔哩手机客户端扫描二维码登录\",\n              textAlign: TextAlign.center,\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/bilibili/web_login_controller.dart",
    "content": "import 'package:flutter_inappwebview/flutter_inappwebview.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\n\nclass BiliBiliWebLoginController extends BaseController {\n  InAppWebViewController? webViewController;\n  final CookieManager cookieManager = CookieManager.instance();\n  void onWebViewCreated(InAppWebViewController controller) {\n    webViewController = controller;\n    webViewController!.loadUrl(\n      urlRequest: URLRequest(\n        url: WebUri(\"https://passport.bilibili.com/login\"),\n      ),\n    );\n  }\n\n  void toQRLogin() async {\n    await Get.toNamed(RoutePath.kBiliBiliQRLogin);\n    Get.back();\n  }\n\n  void onLoadStop(InAppWebViewController controller, Uri? uri) async {\n    if (uri == null) {\n      return;\n    }\n    if (uri.host == \"m.bilibili.com\") {\n      logined();\n    }\n  }\n\n  Future<bool> logined() async {\n    try {\n      var cookies =\n          await cookieManager.getCookies(url: WebUri(\"https://bilibili.com\"));\n      if (cookies.isEmpty) {\n        return false;\n      }\n      var cookieStr = cookies.map((e) => \"${e.name}=${e.value}\").join(\";\");\n      Log.i(cookieStr);\n      BiliBiliAccountService.instance.setCookie(cookieStr);\n      await BiliBiliAccountService.instance.loadUserInfo();\n      Get.back();\n      return true;\n    } catch (e) {\n      return false;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/account/bilibili/web_login_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_inappwebview/flutter_inappwebview.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/web_login_controller.dart';\n\nclass BiliBiliWebLoginPage extends GetView<BiliBiliWebLoginController> {\n  const BiliBiliWebLoginPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"哔哩哔哩账号登录\"),\n        actions: [\n          TextButton.icon(\n            onPressed: controller.toQRLogin,\n            icon: const Icon(Icons.qr_code),\n            label: const Text(\"二维码登录\"),\n          ),\n        ],\n      ),\n      body: InAppWebView(\n        onWebViewCreated: controller.onWebViewCreated,\n        onLoadStop: controller.onLoadStop,\n        initialSettings: InAppWebViewSettings(\n          userAgent:\n              \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/118.0.0.0\",\n          useShouldOverrideUrlLoading: true,\n        ),\n        shouldOverrideUrlLoading: (webController, navigationAction) async {\n          var uri = navigationAction.request.url;\n          if (uri == null) {\n            return NavigationActionPolicy.ALLOW;\n          }\n          if (uri.host == \"m.bilibili.com\" || uri.host == \"www.bilibili.com\") {\n            await controller.logined();\n            return NavigationActionPolicy.CANCEL;\n          }\n          return NavigationActionPolicy.ALLOW;\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/history/history_controller.dart",
    "content": "import 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/services/db_service.dart';\n\nclass HistoryController extends BasePageController<History> {\n  @override\n  Future<List<History>> getData(int page, int pageSize) {\n    if (page > 1) {\n      return Future.value([]);\n    }\n    return Future.value(DBService.instance.getHistories());\n  }\n\n  void clean() async {\n    var result = await Utils.showAlertDialog(\"确定要清空观看记录吗?\", title: \"清空观看记录\");\n    if (!result) {\n      return;\n    }\n    await DBService.instance.historyBox.clear();\n    refreshData();\n  }\n\n  void removeItem(History item) async {\n    await DBService.instance.historyBox.delete(item.id);\n    refreshData();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/history/history_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/mine/history/history_controller.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_app/widgets/page_grid_view.dart';\n\nclass HistoryPage extends GetView<HistoryController> {\n  const HistoryPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    var rowCount = MediaQuery.of(context).size.width ~/ 500;\n    if (rowCount < 1) rowCount = 1;\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"观看记录\"),\n        actions: [\n          TextButton.icon(\n            onPressed: controller.clean,\n            icon: const Icon(Icons.delete_outline),\n            label: const Text(\"清空\"),\n          ),\n        ],\n      ),\n      body: PageGridView(\n        crossAxisSpacing: 12,\n        crossAxisCount: rowCount,\n        pageController: controller,\n        firstRefresh: true,\n        itemBuilder: (_, i) {\n          var item = controller.list[i];\n          var site = Sites.allSites[item.siteId]!;\n          return Dismissible(\n            key: ValueKey(item.id),\n            direction: DismissDirection.endToStart,\n            background: Container(\n              color: Colors.red,\n              padding: AppStyle.edgeInsetsA12,\n              alignment: Alignment.centerRight,\n              child: const Icon(\n                Icons.delete,\n                color: Colors.white,\n              ),\n            ),\n            confirmDismiss: (direction) async {\n              return await Utils.showAlertDialog(\"确定要删除此记录吗?\", title: \"删除记录\");\n            },\n            onDismissed: (_) {\n              controller.removeItem(item);\n            },\n            child: ListTile(\n              leading: NetImage(\n                item.face,\n                width: 48,\n                height: 48,\n                borderRadius: 24,\n              ),\n              title: Text(item.userName),\n              subtitle: Row(\n                children: [\n                  Expanded(\n                    child: Row(\n                      children: [\n                        Image.asset(\n                          site.logo,\n                          width: 20,\n                        ),\n                        AppStyle.hGap4,\n                        Text(\n                          site.name,\n                          style: const TextStyle(\n                            fontSize: 12,\n                            color: Colors.grey,\n                          ),\n                        ),\n                      ],\n                    ),\n                  ),\n                  Text(\n                    Utils.parseTime(item.updateTime),\n                    style: const TextStyle(fontSize: 12, color: Colors.grey),\n                  ),\n                ],\n              ),\n              onTap: () {\n                AppNavigator.toLiveRoomDetail(site: site, roomId: item.roomId);\n              },\n              onLongPress: () async {\n                var result =\n                    await Utils.showAlertDialog(\"确定要删除此记录吗?\", title: \"删除记录\");\n                if (!result) {\n                  return;\n                }\n                controller.removeItem(item);\n              },\n            ),\n          );\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/mine_page.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/signalr_service.dart';\nimport 'package:url_launcher/url_launcher_string.dart';\n\nclass MinePage extends StatelessWidget {\n  const MinePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AnnotatedRegion<SystemUiOverlayStyle>(\n      value: Get.isDarkMode\n          ? SystemUiOverlayStyle.light.copyWith(\n              systemNavigationBarColor: Colors.transparent,\n            )\n          : SystemUiOverlayStyle.dark.copyWith(\n              systemNavigationBarColor: Colors.transparent,\n            ),\n      child: SafeArea(\n        child: ListView(\n          padding: AppStyle.edgeInsetsA4,\n          children: [\n            AppStyle.vGap12,\n            ListTile(\n              leading: Image.asset(\n                'assets/images/logo.png',\n                width: 56,\n                height: 56,\n              ),\n              title: const Text(\n                \"Slive\",\n                style: TextStyle(height: 1.0),\n              ),\n              subtitle: const Text(\"我就默默看你表演\"),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: () {\n                Get.dialog(AboutDialog(\n                  applicationIcon: Image.asset(\n                    'assets/images/logo.png',\n                    width: 48,\n                    height: 48,\n                  ),\n                  applicationName: \"Slive\",\n                  applicationVersion: \"我就默默看你表演\",\n                  applicationLegalese: \"Ver ${Utils.packageInfo.version}\",\n                ));\n              },\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            _buildCard(\n              context,\n              children: [\n                ListTile(\n                  leading: const Icon(Remix.history_line),\n                  title: const Text(\"观看记录\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kHistory);\n                  },\n                ),\n              ],\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            ListTile(\n              leading: const Icon(Remix.account_circle_line),\n              title: const Text(\"账号管理\"),\n              trailing: const Icon(\n                Icons.chevron_right,\n                color: Colors.grey,\n              ),\n              onTap: () {\n                Get.toNamed(RoutePath.kSettingsAccount);\n              },\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            ListTile(\n              leading: const Icon(Icons.devices),\n              title: const Text(\"数据同步\"),\n              trailing: const Icon(\n                Icons.chevron_right,\n                color: Colors.grey,\n              ),\n              onTap: () {\n                Get.toNamed(RoutePath.kSync);\n              },\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            ListTile(\n              leading: const Icon(Remix.link),\n              title: const Text(\"链接解析\"),\n              trailing: const Icon(\n                Icons.chevron_right,\n                color: Colors.grey,\n              ),\n              onTap: () {\n                Get.toNamed(RoutePath.kTools);\n              },\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            _buildCard(\n              context,\n              children: [\n                ListTile(\n                  leading: const Icon(Remix.moon_line),\n                  title: const Text(\"外观设置\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kAppstyleSetting);\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.home_2_line),\n                  title: const Text(\"主页设置\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kSettingsIndexed);\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.play_circle_line),\n                  title: const Text(\"直播设置\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kSettingsPlay);\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.text),\n                  title: const Text(\"弹幕设置\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kSettingsDanmu);\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.timer_2_line),\n                  title: const Text(\"定时关闭\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kSettingsAutoExit);\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.apps_line),\n                  title: const Text(\"其他设置\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kSettingsOther);\n                  },\n                ),\n                if (kDebugMode)\n                  ListTile(\n                    leading: const Icon(Remix.apps_line),\n                    title: const Text(\"测试\"),\n                    trailing: const Icon(\n                      Icons.chevron_right,\n                      color: Colors.grey,\n                    ),\n                    onTap: () async {\n                      SignalRService signalRService = SignalRService();\n                      await signalRService.connect();\n                      //Get.toNamed(RoutePath.kTest);\n                      var room = await signalRService.createRoom();\n                      Log.logPrint(room);\n                    },\n                  ),\n              ],\n            ),\n            Divider(\n              indent: 12,\n              endIndent: 12,\n              color: Colors.grey.withAlpha(25),\n            ),\n            _buildCard(\n              context,\n              children: [\n                const ListTile(\n                  leading: Icon(Remix.error_warning_line),\n                  title: Text(\"免责声明\"),\n                  trailing: Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: Utils.showStatement,\n                ),\n                ListTile(\n                  leading: const Icon(Remix.github_line),\n                  title: const Text(\"开源主页\"),\n                  trailing: const Icon(\n                    Icons.chevron_right,\n                    color: Colors.grey,\n                  ),\n                  onTap: () {\n                    launchUrlString(\n                      \"https://github.com/slotsun/dart_simple_live\",\n                      mode: LaunchMode.externalApplication,\n                    );\n                  },\n                ),\n                ListTile(\n                  leading: const Icon(Remix.upload_2_line),\n                  title: const Text(\"检查更新\"),\n                  trailing: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      Text(\"Ver ${Utils.packageInfo.version}\"),\n                      AppStyle.hGap4,\n                      const Icon(\n                        Icons.chevron_right,\n                        color: Colors.grey,\n                      ),\n                    ],\n                  ),\n                  onTap: () {\n                    Utils.checkUpdate(showMsg: true);\n                  },\n                ),\n              ],\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  Widget _buildCard(BuildContext context, {required List<Widget> children}) {\n    return Theme(\n      data: Theme.of(context).copyWith(\n        listTileTheme: ListTileThemeData(\n          shape: RoundedRectangleBorder(borderRadius: AppStyle.radius8),\n        ),\n      ),\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: children,\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/parse/parse_controller.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils/url_parse.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\n\nclass ParseController extends GetxController {\n  final TextEditingController roomJumpToController = TextEditingController();\n  final TextEditingController getUrlController = TextEditingController();\n\n  void jumpToRoom(String e) async {\n    if (e.isEmpty) {\n      SmartDialog.showToast(\"链接不能为空\");\n      return;\n    }\n    // 隐藏键盘\n    FocusManager.instance.primaryFocus?.unfocus();\n\n    var parseResult = await UrlParse.instance.parse(e);\n    if (parseResult.isEmpty || parseResult.first == \"\") {\n      SmartDialog.showToast(\"无法解析此链接\");\n      return;\n    }\n\n    // 延迟200ms跳转，等待键盘隐藏\n    Future.delayed(const Duration(milliseconds: 200), () {\n      Site site = parseResult[1];\n      AppNavigator.toLiveRoomDetail(site: site, roomId: parseResult.first);\n    });\n  }\n\n  void getPlayUrl(String e) async {\n    if (e.isEmpty) {\n      SmartDialog.showToast(\"链接不能为空\");\n      return;\n    }\n    var parseResult = await UrlParse.instance.parse(e);\n    if (parseResult.isEmpty && parseResult.first == \"\") {\n      SmartDialog.showToast(\"无法解析此链接\");\n      return;\n    }\n    Site site = parseResult[1];\n    try {\n      SmartDialog.showLoading(msg: \"\");\n      var detail = await site.liveSite.getRoomDetail(roomId: parseResult.first);\n      var qualites = await site.liveSite.getPlayQualites(detail: detail);\n      SmartDialog.dismiss(status: SmartStatus.loading);\n      if (qualites.isEmpty) {\n        SmartDialog.showToast(\"读取直链失败,无法读取清晰度\");\n\n        return;\n      }\n      var result = await Get.dialog(SimpleDialog(\n        title: const Text(\"选择清晰度\"),\n        children: qualites\n            .map(\n              (e) => ListTile(\n                title: Text(\n                  e.quality,\n                  textAlign: TextAlign.center,\n                ),\n                onTap: () {\n                  Get.back(result: e);\n                },\n              ),\n            )\n            .toList(),\n      ));\n      if (result == null) {\n        return;\n      }\n      SmartDialog.showLoading(msg: \"\");\n      var playUrl =\n          await site.liveSite.getPlayUrls(detail: detail, quality: result);\n      SmartDialog.dismiss(status: SmartStatus.loading);\n      await Get.dialog(SimpleDialog(\n        title: const Text(\"选择线路\"),\n        children: playUrl.urls\n            .map(\n              (e) => ListTile(\n                title: Text(\n                  \"线路${playUrl.urls.indexOf(e) + 1}\",\n                ),\n                subtitle: Text(\n                  e,\n                  maxLines: 1,\n                  overflow: TextOverflow.ellipsis,\n                ),\n                onTap: () {\n                  Clipboard.setData(ClipboardData(text: e));\n                  Get.back();\n                  SmartDialog.showToast(\"已复制直链\");\n                },\n              ),\n            )\n            .toList(),\n      ));\n    } catch (e) {\n      SmartDialog.showToast(\"读取直链失败\");\n    } finally {\n      SmartDialog.dismiss(status: SmartStatus.loading);\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/mine/parse/parse_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/mine/parse/parse_controller.dart';\n\nclass ParsePage extends GetView<ParseController> {\n  const ParsePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"链接解析\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          buildCard(\n            context: context,\n            child: ExpansionTile(\n              title: const Text(\"直播间跳转\"),\n              childrenPadding: AppStyle.edgeInsetsH12,\n              initiallyExpanded: true,\n              children: [\n                TextField(\n                  minLines: 3,\n                  maxLines: 3,\n                  controller: controller.roomJumpToController,\n                  textInputAction: TextInputAction.go,\n                  decoration: InputDecoration(\n                    border: const OutlineInputBorder(),\n                    hintText: \"输入或粘贴哔哩哔哩直播/虎牙直播/斗鱼直播/抖音直播的链接\",\n                    contentPadding: AppStyle.edgeInsetsA12,\n                    enabledBorder: OutlineInputBorder(\n                      borderSide: BorderSide(\n                        color: Colors.grey.withAlpha(50),\n                      ),\n                    ),\n                  ),\n                  onSubmitted: controller.jumpToRoom,\n                ),\n                Container(\n                  margin: AppStyle.edgeInsetsB4,\n                  width: double.infinity,\n                  child: TextButton.icon(\n                    onPressed: () {\n                      controller\n                          .jumpToRoom(controller.roomJumpToController.text);\n                    },\n                    icon: const Icon(Remix.play_circle_line),\n                    label: const Text(\"链接跳转\"),\n                  ),\n                ),\n              ],\n            ),\n          ),\n          buildCard(\n            context: context,\n            child: ExpansionTile(\n              title: const Text(\"获取直链\"),\n              childrenPadding: AppStyle.edgeInsetsH12,\n              initiallyExpanded: true,\n              children: [\n                TextField(\n                  minLines: 3,\n                  maxLines: 3,\n                  controller: controller.getUrlController,\n                  textInputAction: TextInputAction.go,\n                  decoration: InputDecoration(\n                    border: const OutlineInputBorder(),\n                    hintText: \"输入或粘贴哔哩哔哩直播/虎牙直播/斗鱼直播/抖音直播的链接\",\n                    contentPadding: AppStyle.edgeInsetsA12,\n                    enabledBorder: OutlineInputBorder(\n                      borderSide: BorderSide(\n                        color: Colors.grey.withAlpha(50),\n                      ),\n                    ),\n                  ),\n                  onSubmitted: controller.getPlayUrl,\n                ),\n                Container(\n                  margin: AppStyle.edgeInsetsB4,\n                  width: double.infinity,\n                  child: TextButton.icon(\n                    onPressed: () {\n                      controller.getPlayUrl(controller.getUrlController.text);\n                    },\n                    icon: const Icon(Remix.link),\n                    label: const Text(\"获取直链\"),\n                  ),\n                ),\n              ],\n            ),\n          ),\n          const Padding(\n            padding: AppStyle.edgeInsetsV12,\n            child: SelectableText('''支持以下类型的链接解析：\n哔哩哔哩：\nhttps://live.bilibili.com/xxxxx\nhttps://b23.tv/xxxxx\n虎牙直播：\nhttps://www.huya.com/xxxxx\n斗鱼直播：\nhttps://www.douyu.com/xxxxx\nhttps://www.douyu.com/topic/xxxx\n抖音直播：\nhttps://live.douyin.com/xxxxx\nhttps://webcast.amemv.com/douyin/webcast/reflow/xxxxx\n''', style: TextStyle(color: Colors.grey)),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildCard({required BuildContext context, required Widget child}) {\n    return Container(\n      decoration: BoxDecoration(\n        color: Theme.of(context).cardColor,\n        borderRadius: AppStyle.radius8,\n        boxShadow: Get.isDarkMode\n            ? []\n            : [\n                BoxShadow(\n                  blurRadius: 8,\n                  color: Colors.grey.withAlpha(50),\n                )\n              ],\n      ),\n      margin: AppStyle.edgeInsetsB12,\n      child: Theme(\n        data: Theme.of(context).copyWith(\n          dividerColor: Colors.transparent,\n        ),\n        child: child,\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/other/debug_log_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:share_plus/share_plus.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/log.dart';\n\nclass DebugLogPage extends StatelessWidget {\n  const DebugLogPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"Log\"),\n        actions: [\n          IconButton(\n            onPressed: () async {\n              var msg = Log.debugLogs\n                  .map((x) => \"${x.datetime}\\r\\n${x.content}\")\n                  .join('\\r\\n\\r\\n');\n              var dir = await getApplicationDocumentsDirectory();\n              var logFile = File(\n                  '${dir.path}/${DateTime.now().millisecondsSinceEpoch}.log');\n              await logFile.writeAsString(msg);\n              SharePlus.instance\n                  .share(ShareParams(files: [XFile(logFile.path)]));\n            },\n            icon: const Icon(Icons.save),\n          ),\n          IconButton(\n            onPressed: () {\n              Log.debugLogs.clear();\n            },\n            icon: const Icon(Icons.clear_all),\n          ),\n        ],\n      ),\n      body: Obx(\n        () => ListView.separated(\n          itemCount: Log.debugLogs.length,\n          separatorBuilder: (_, i) => const Divider(),\n          padding: AppStyle.edgeInsetsA12,\n          itemBuilder: (_, i) {\n            var item = Log.debugLogs[i];\n            return SelectableText(\n              \"${item.datetime.toString()}\\r\\n${item.content}\",\n              style: TextStyle(\n                color: item.color,\n                fontSize: 12,\n              ),\n            );\n          },\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/douyin/douyin_search_controller.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter_inappwebview/flutter_inappwebview.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:url_launcher/url_launcher_string.dart';\n\nclass DouyinSearchController extends BaseController {\n  InAppWebViewController? webViewController;\n\n  void onWebViewCreated(InAppWebViewController controller) {\n    webViewController = controller;\n  }\n\n  RxList<LiveRoomItem> list = <LiveRoomItem>[].obs;\n\n  String keyword = \"\";\n\n  /// 搜索模式，0=直播间，1=主播\n  var searchMode = 0.obs;\n  final Site site;\n  DouyinSearchController(\n    this.site,\n  );\n\n  var searchUrl = \"https://www.douyin.com/search/dnf?type=live\";\n\n  void reloadWebView() {\n    if (keyword.isEmpty) {\n      return;\n    }\n    searchUrl =\n        \"https://www.douyin.com/search/${Uri.encodeComponent(keyword)}?type=live\";\n    if (Platform.isAndroid || Platform.isIOS) {\n      webViewController!.loadUrl(\n        urlRequest: URLRequest(\n          url: WebUri(searchUrl),\n        ),\n      );\n    }\n  }\n\n  void onLoadStop(InAppWebViewController controller, Uri? uri) async {\n    pageLoadding.value = false;\n  }\n\n  void onLoadStart(InAppWebViewController controller, Uri? uri) async {\n    pageLoadding.value = true;\n  }\n\n  Future<bool?> onCreateWindow(InAppWebViewController controller,\n      CreateWindowAction createWindowAction) async {\n    if (createWindowAction.request.url?.host == \"live.douyin.com\") {\n      {\n        var regExp = RegExp(r\"live\\.douyin\\.com/([\\d|\\w]+)\");\n        var id = regExp\n                .firstMatch(createWindowAction.request.url.toString())\n                ?.group(1) ??\n            \"\";\n\n        AppNavigator.toLiveRoomDetail(site: site, roomId: id);\n        return false;\n      }\n    }\n\n    return false;\n  }\n\n  void openBrowser() {\n    launchUrlString(searchUrl);\n    Get.offAndToNamed(RoutePath.kTools);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/douyin/douyin_search_view.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_inappwebview/flutter_inappwebview.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/search/douyin/douyin_search_controller.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/status/app_loadding_widget.dart';\n\nclass DouyinSearchView extends StatelessWidget {\n  const DouyinSearchView({super.key});\n  DouyinSearchController get controller => Get.find<DouyinSearchController>();\n\n  @override\n  Widget build(BuildContext context) {\n    var roomRowCount = MediaQuery.of(context).size.width ~/ 200;\n    if (roomRowCount < 2) roomRowCount = 2;\n\n    var userRowCount = MediaQuery.of(context).size.width ~/ 500;\n    if (userRowCount < 1) userRowCount = 1;\n    return KeepAliveWrapper(\n      child: Stack(\n        children: [\n          SizedBox(\n            width: double.infinity,\n            height: double.infinity,\n            child: Center(\n              child: Padding(\n                padding: AppStyle.edgeInsetsA12,\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  crossAxisAlignment: CrossAxisAlignment.center,\n                  children: [\n                    const Text(\n                      \"暂不支持抖音搜索，请打开浏览器搜索，然后复制直播间链接进行解析\",\n                      textAlign: TextAlign.center,\n                    ),\n                    TextButton.icon(\n                      onPressed: controller.openBrowser,\n                      icon: const Icon(Icons.open_in_browser),\n                      label: const Text(\"打开浏览器\"),\n                    ),\n                  ],\n                ),\n              ),\n            ),\n          ),\n          if (Platform.isAndroid || Platform.isIOS)\n            InAppWebView(\n              onWebViewCreated: controller.onWebViewCreated,\n              onLoadStop: controller.onLoadStop,\n              onLoadStart: controller.onLoadStart,\n              initialSettings: InAppWebViewSettings(\n                useOnLoadResource: true,\n                userAgent:\n                    \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/118.0.0.0\",\n                useShouldOverrideUrlLoading: true,\n              ),\n              onCreateWindow: controller.onCreateWindow,\n              shouldOverrideUrlLoading:\n                  (webController, navigationAction) async {\n                var uri = navigationAction.request.url;\n                if (uri == null) {\n                  return NavigationActionPolicy.ALLOW;\n                }\n                if (uri.host == \"live.douyin.com\") {\n                  var regExp = RegExp(r\"live\\.douyin\\.com/([\\d|\\w]+)\");\n                  var id = regExp.firstMatch(uri.toString())?.group(1) ?? \"\";\n\n                  AppNavigator.toLiveRoomDetail(\n                      site: controller.site, roomId: id);\n                  return NavigationActionPolicy.CANCEL;\n                }\n                return NavigationActionPolicy.ALLOW;\n              },\n            ),\n          Obx(\n            () => Visibility(\n              visible: controller.pageLoadding.value,\n              child: const AppLoaddingWidget(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/search_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/search/search_list_controller.dart';\n\nclass AppSearchController extends GetxController\n    with GetSingleTickerProviderStateMixin {\n  late TabController tabController;\n  int index = 0;\n\n  var searchMode = 0.obs;\n\n  AppSearchController() {\n    tabController =\n        TabController(length: Sites.supportSites.length, vsync: this);\n    tabController.animation?.addListener(() {\n      var currentIndex = (tabController.animation?.value ?? 0).round();\n      if (index == currentIndex) {\n        return;\n      }\n\n      index = currentIndex;\n      // if (Sites.supportSites[index].id == Constant.kDouyin) {\n      //   return;\n      // }\n\n      var controller =\n          Get.find<SearchListController>(tag: Sites.supportSites[index].id);\n\n      if (controller.list.isEmpty &&\n          !controller.pageEmpty.value &&\n          controller.keyword.isNotEmpty) {\n        controller.refreshData();\n      }\n    });\n  }\n\n  StreamSubscription<dynamic>? streamSubscription;\n\n  TextEditingController searchController = TextEditingController();\n\n  @override\n  void onInit() {\n    for (var site in Sites.supportSites) {\n      // if (site.id == Constant.kDouyin) {\n      //   Get.put(DouyinSearchController(site));\n      // } else {\n      Get.put(\n        SearchListController(site),\n        tag: site.id,\n      );\n      //}\n    }\n\n    super.onInit();\n  }\n\n  void doSearch() {\n    if (searchController.text.isEmpty) {\n      return;\n    }\n    for (var site in Sites.supportSites) {\n      // if (site.id == Constant.kDouyin) {\n      //   var controller = Get.find<DouyinSearchController>();\n      //   controller.keyword = searchController.text;\n      //   controller.searchMode.value = searchMode.value;\n      //   controller.reloadWebView();\n      // } else {\n      var controller = Get.find<SearchListController>(tag: site.id);\n      controller.clear();\n      controller.keyword = searchController.text;\n      controller.searchMode.value = searchMode.value;\n      //}\n    }\n    // if (Sites.supportSites[index].id != Constant.kDouyin) {\n    var controller =\n        Get.find<SearchListController>(tag: Sites.supportSites[index].id);\n    controller.refreshData();\n    //}\n  }\n\n  @override\n  void onClose() {\n    streamSubscription?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/search_list_controller.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\n\nclass SearchListController extends BasePageController {\n  String keyword = \"\";\n\n  /// 搜索模式，0=直播间，1=主播\n  var searchMode = 0.obs;\n  final Site site;\n  SearchListController(\n    this.site,\n  );\n\n  @override\n  Future refreshData() async {\n    if (keyword.isEmpty) {\n      return;\n    }\n    return await super.refreshData();\n  }\n\n  @override\n  Future<List> getData(int page, int pageSize) async {\n    if (keyword.isEmpty) {\n      return [];\n    }\n    if (searchMode.value == 1) {\n      // 搜索主播\n      var result = await site.liveSite.searchAnchors(keyword, page: page);\n      return result.items;\n    }\n    var result = await site.liveSite.searchRooms(keyword, page: page);\n\n    return result.items;\n  }\n\n  void clear() {\n    pageEmpty.value = false;\n    list.clear();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/search_list_view.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/search/search_list_controller.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/widgets/keep_alive_wrapper.dart';\nimport 'package:simple_live_app/widgets/live_room_card.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_app/widgets/page_grid_view.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass SearchListView extends StatelessWidget {\n  final String tag;\n  const SearchListView(this.tag, {super.key});\n  SearchListController get controller =>\n      Get.find<SearchListController>(tag: tag);\n  @override\n  Widget build(BuildContext context) {\n    var roomRowCount = MediaQuery.of(context).size.width ~/ 200;\n    if (roomRowCount < 2) roomRowCount = 2;\n\n    var userRowCount = MediaQuery.of(context).size.width ~/ 500;\n    if (userRowCount < 1) userRowCount = 1;\n    return KeepAliveWrapper(\n      child: Obx(\n        () => controller.searchMode.value == 0\n            ? PageGridView(\n                pageController: controller,\n                padding: AppStyle.edgeInsetsA12,\n                firstRefresh: false,\n                mainAxisSpacing: 12,\n                crossAxisSpacing: 12,\n                crossAxisCount: roomRowCount,\n                showPageLoadding: true,\n                itemBuilder: (_, i) {\n                  var item = controller.list[i] as LiveRoomItem;\n                  return LiveRoomCard(controller.site, item);\n                },\n              )\n            : PageGridView(\n                crossAxisSpacing: 12,\n                crossAxisCount: userRowCount,\n                pageController: controller,\n                firstRefresh: true,\n                itemBuilder: (_, i) {\n                  var item = controller.list[i] as LiveAnchorItem;\n\n                  return ListTile(\n                    leading: NetImage(\n                      item.avatar,\n                      width: 48,\n                      height: 48,\n                      borderRadius: 24,\n                    ),\n                    title: Text(item.userName),\n                    subtitle: Row(\n                      mainAxisSize: MainAxisSize.min,\n                      children: [\n                        Container(\n                          width: 8,\n                          height: 8,\n                          decoration: BoxDecoration(\n                            color: item.liveStatus ? Colors.green : Colors.grey,\n                            borderRadius: AppStyle.radius12,\n                          ),\n                        ),\n                        AppStyle.hGap4,\n                        Text(\n                          item.liveStatus ? \"直播中\" : \"未开播\",\n                          style: TextStyle(\n                            fontSize: 12,\n                            fontWeight: FontWeight.normal,\n                            color: item.liveStatus ? null : Colors.grey,\n                          ),\n                        ),\n                      ],\n                    ),\n                    onTap: () {\n                      AppNavigator.toLiveRoomDetail(\n                          site: controller.site, roomId: item.roomId);\n                    },\n                  );\n                },\n              ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/search/search_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/search/search_controller.dart';\nimport 'package:simple_live_app/modules/search/search_list_view.dart';\n\nclass SearchPage extends GetView<AppSearchController> {\n  const SearchPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        automaticallyImplyLeading: false,\n        title: TextField(\n          controller: controller.searchController,\n          autofocus: true,\n          decoration: InputDecoration(\n            hintText: \"搜点什么吧\",\n            border: OutlineInputBorder(\n              borderRadius: AppStyle.radius24,\n            ),\n            contentPadding: AppStyle.edgeInsetsH12,\n            prefixIcon: Row(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                IconButton(\n                  onPressed: Get.back,\n                  icon: const Icon(Icons.arrow_back),\n                ),\n                Obx(\n                  () => DropdownButton<int>(\n                    underline: const SizedBox(),\n                    items: const [\n                      DropdownMenuItem(\n                        value: 0,\n                        child: Text(\"房间\"),\n                      ),\n                      DropdownMenuItem(\n                        value: 1,\n                        child: Text(\"主播\"),\n                      ),\n                    ],\n                    value: controller.searchMode.value,\n                    onChanged: (e) {\n                      controller.searchMode.value = e ?? 0;\n                      controller.doSearch();\n                    },\n                  ),\n                ),\n                AppStyle.hGap8,\n              ],\n            ),\n            suffixIcon: IconButton(\n              onPressed: controller.doSearch,\n              icon: const Icon(Icons.search),\n            ),\n          ),\n          onSubmitted: (e) {\n            controller.doSearch();\n          },\n        ),\n        bottom: TabBar(\n          controller: controller.tabController,\n          padding: EdgeInsets.zero,\n          tabAlignment: TabAlignment.center,\n          tabs: Sites.supportSites\n              .map(\n                (e) => Tab(\n                  //text: e.name,\n                  child: Row(\n                    children: [\n                      Image.asset(\n                        e.logo,\n                        width: 24,\n                      ),\n                      AppStyle.hGap8,\n                      Text(e.name),\n                    ],\n                  ),\n                ),\n              )\n              .toList(),\n          labelPadding: AppStyle.edgeInsetsH20,\n          isScrollable: true,\n          indicatorSize: TabBarIndicatorSize.label,\n        ),\n      ),\n      body: TabBarView(\n        physics: const NeverScrollableScrollPhysics(),\n        controller: controller.tabController,\n        children: Sites.supportSites\n            .map((e) => SearchListView(\n                      e.id,\n                    )\n                // (e) => e.id == Constant.kDouyin\n                //     ? const DouyinSearchView()\n                //     : SearchListView(\n                //         e.id,\n                //       ),\n                )\n            .toList(),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/appstyle_settings/appstyle_setting_contorller.dart",
    "content": "﻿import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get_core/src/get_main.dart';\nimport 'package:get/get_instance/src/extension_instance.dart';\nimport 'package:get/get_navigation/src/extension_navigation.dart';\nimport 'package:get/get_rx/src/rx_types/rx_types.dart';\nimport 'package:get/get_state_manager/src/simple/get_controllers.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/models/font_model.dart';\nimport 'package:simple_live_app/requests/http_client.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\n\nclass AppStyleSettingController extends GetxController {\n  static AppStyleSettingController get instance =>\n      Get.find<AppStyleSettingController>();\n\n  var themeMode = 0.obs;\n  var isDynamic = false.obs;\n  var styleColor = 0xff3498db.obs;\n  Rx<String?> curFontName = Rx<String?>(null);\n  Rx<FontModel?> curFontModel = Rx<FontModel?>(null);\n  final RxList<FontModel> fontList = <FontModel>[].obs;\n  final RxMap<FontModel, String> fontMap = <FontModel, String>{}.obs;\n  Rx<DownloadState> fontState = DownloadState.notDownloaded.obs;\n\n\n  Future<void> init() async {\n    styleColor.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kStyleColor, 0xff3498db);\n\n    isDynamic.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kIsDynamic, false);\n    await fetchFonts();\n    await userFontInit();\n  }\n\n  Future<void> fontDelete() async{\n    var dir = await getApplicationSupportDirectory();\n    final fontDir = Directory(\"${dir.path}/fonts/${curFontModel.value!.id}\");\n    try {\n      // 删除整个目录（包括目录本身和所有内容）\n      await fontDir.delete(recursive: true);\n      await fontDir.create(recursive: true);\n      var download =  await fontDownloadCheck(curFontModel.value!.id);\n      if(download == false){\n        fontState.value = DownloadState.notDownloaded;\n      }\n      SmartDialog.showToast(\"已删除${curFontModel.value!.name}字体\");\n      Log.d('目录${fontDir.path}已清空并重新创建');\n    } catch (e,s) {\n      Log.e('操作失败: $e', s);\n    }\n  }\n\n  void fontReset(){\n    if(Platform.isWindows){\n      curFontName.value = \"Microsoft YaHei\";\n      LocalStorageService.instance.setValue(LocalStorageService.kCustomFont, curFontName.value);\n    }else{\n      curFontName.value = null;\n      LocalStorageService.instance.removeValue(LocalStorageService.kCustomFont);\n    }\n  }\n\n  void changeFontFamily() {\n    curFontName.value = curFontModel.value?.id;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kCustomFont, curFontName.value);\n    SmartDialog.showToast(\"已设置全局字体为${curFontModel.value?.name}\");\n  }\n\n  Future<void> onFontSelected(FontModel fontModel) async {\n    var fontName = fontModel.id;\n    curFontModel.value = fontModel;\n    if (await fontDownloadCheck(fontName)) {\n      fontState.value = DownloadState.downloaded;\n      // 存在则加载并应用\n      await loadFont(fontName);\n    } else {\n      fontState.value = DownloadState.notDownloaded;\n    }\n  }\n\n  Future<void> downloadFont() async {\n    var dir = await getApplicationSupportDirectory();\n    var fontName = curFontModel.value!.id;\n    final fontDir = Directory(\"${dir.path}/fonts/$fontName\");\n    if (!await fontDir.exists()) {\n      await fontDir.create(recursive: true);\n    }\n    Log.d(\"开始下载----$fontName\");\n    const baseUrl = \"https://gcore.jsdelivr.net/gh/SlotSun/fonts@master/\";\n    fontState.value = DownloadState.downloading;\n    for (var filePath in curFontModel.value!.files) {\n      final fileName = filePath.split('/').last;\n      final file = File(\"${fontDir.path}/$fileName\");\n\n      if (!await file.exists()) {\n        int retryCount = 0;\n        const maxRetries = 3;\n        while (retryCount < maxRetries) {\n          try {\n            // Download if not exists\n            await HttpClient.instance.download(\n              \"$baseUrl$filePath\",\n              file.path,\n            );\n            break; // Success\n          } catch (e, s) {\n            retryCount++;\n            if (retryCount >= maxRetries) {\n              Log.e(\"Failed to download font file after $maxRetries attempts: $filePath\\n$e\", s);\n              fontState.value = DownloadState.notDownloaded;\n              SmartDialog.showToast(\"下载失败，请检查网络后重试\");\n              throw Exception(\"Failed to download $fileName: $e\");\n            }\n            Log.w(\"Download failed, retrying ($retryCount/$maxRetries): $fileName\");\n            await Future.delayed(const Duration(seconds: 1));\n          }\n        }\n      }\n    }\n    fontState.value = DownloadState.downloaded;\n    await loadFont(fontName);\n  }\n\n  Future<void> userFontInit() async {\n    var fontName = LocalStorageService.instance\n        .getNullValue<String?>(LocalStorageService.kCustomFont, null);\n    Log.d('获取当前字体$fontName');\n    if (fontName != null && fontName != \"Microsoft YaHei\") {\n      // 确认本地是否存在此字体\n      if (await fontDownloadCheck(fontName)) {\n        // 存在则加载并应用\n        await loadFont(fontName);\n      } else {\n        // 不存在则使用默认字体\n        fontName = null;\n      }\n    }\n    curFontName.value = fontName;\n    if (curFontName.value != null) {\n      curFontModel.value = fontMap.keys.firstWhere(\n          (element) => element.id == curFontName.value,\n          orElse: () => fontMap.keys.first);\n    } else {\n      curFontModel.value = fontMap.keys.first;\n    }\n    // maybe curFontName = null\n    fontState.value = await fontDownloadCheck(curFontModel.value!.id)\n        ? DownloadState.downloaded\n        : DownloadState.notDownloaded;\n\n    Log.d(\"当前字体模型：${curFontModel.value!.id}\");\n  }\n\n  Future<void> loadFont(String fontName) async {\n    var dir = await getApplicationSupportDirectory();\n    final fontDir = Directory(\"${dir.path}/fonts/$fontName\");\n    final loader = FontLoader(fontName);\n\n    await for (final entity in fontDir.list()) {\n      if (entity is File && entity.path.endsWith('.ttf')) {\n        loader.addFont(entity.readAsBytes().then(ByteData.sublistView));\n      }\n    }\n    await loader.load();\n    Log.d('已加载$fontName 词库');\n  }\n\n  Future<bool> fontDownloadCheck(String fontName) async {\n    final dir = await getApplicationSupportDirectory();\n    final fontDir = Directory(\"${dir.path}/fonts/$fontName\");\n    bool fontDownload =\n        await fontDir.exists() && await fontDir.list().length >= 1;\n    return fontDownload;\n  }\n\n  Future<void> fetchFonts() async {\n    try {\n      final jsonStr =\n          await rootBundle.loadString('assets/fonts/fonts-manifest.json');\n      final List<dynamic> list = json.decode(jsonStr);\n      // 集合推导构造fontMap\n      fontMap.assignAll(\n        {\n          for (final e in list)\n            FontModel.fromJson(e): (e['name'] as String? ?? ''),\n        },\n      );\n    } catch (e, s) {\n      Log.e(\"Failed to fetch fonts manifest: $e\", s);\n    }\n  }\n\n  void setIsDynamic(bool e) {\n    isDynamic.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kIsDynamic, e);\n  }\n\n  void changeTheme() {\n    Get.dialog(\n      SimpleDialog(\n        title: const Text(\"设置主题\"),\n        children: [\n          RadioGroup<int>(\n            groupValue: themeMode.value,\n            onChanged: (e) {\n              Get.back();\n              setTheme(e ?? 0);\n            },\n            child: Column(\n              children: [\n                RadioListTile<int>(\n                  title: const Text(\"跟随系统\"),\n                  value: 0,\n                ),\n                RadioListTile<int>(\n                  title: const Text(\"浅色模式\"),\n                  value: 1,\n                ),\n                RadioListTile<int>(\n                  title: const Text(\"深色模式\"),\n                  value: 2,\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void setTheme(int i) {\n    themeMode.value = i;\n    var mode = ThemeMode.values[i];\n\n    LocalStorageService.instance.setValue(LocalStorageService.kThemeMode, i);\n    Get.changeThemeMode(mode);\n  }\n\n  void setStyleColor(int e) {\n    styleColor.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kStyleColor, e);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/appstyle_settings/appstyle_setting_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/modules/settings/appstyle_settings/appstyle_setting_contorller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_menu.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\n\nclass AppStyleSettingPage extends GetView<AppStyleSettingController> {\n  const AppStyleSettingPage({super.key});\n\n  Widget trailingBuild({required Widget widget}) {\n    return Row(\n      mainAxisSize: MainAxisSize.min,\n      children: [\n        Tooltip(\n          message: \"重置为默认字体\",\n          child: IconButton(\n            onPressed: controller.fontReset,\n            icon: Icon(Icons.settings_backup_restore_outlined),\n          ),\n        ),\n        AppStyle.hGap4,\n        Visibility(\n          visible: controller.fontState.value == DownloadState.downloaded,\n          child:\n        Tooltip(\n          message: \"删除字体\",\n          child: IconButton(\n            onPressed: controller.fontDelete,\n            icon: Icon(Icons.delete_outline_outlined),\n          ),\n        ),\n        ),\n        Visibility(\n          visible: controller.fontState.value == DownloadState.downloaded,\n          child: AppStyle.hGap4,\n        ),\n        widget,\n      ],\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"外观设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n            child: Text(\n              \"显示主题\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => RadioGroup<int>(\n                groupValue: controller.themeMode.value,\n                onChanged: (e) {\n                  controller.setTheme(e ?? 0);\n                },\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    RadioListTile<int>(\n                      title: const Text(\n                        \"跟随系统\",\n                      ),\n                      visualDensity: VisualDensity.compact,\n                      value: 0,\n                      contentPadding: AppStyle.edgeInsetsH12,\n                    ),\n                    RadioListTile<int>(\n                      title: const Text(\n                        \"浅色模式\",\n                      ),\n                      visualDensity: VisualDensity.compact,\n                      value: 1,\n                      contentPadding: AppStyle.edgeInsetsH12,\n                    ),\n                    RadioListTile<int>(\n                      title: const Text(\n                        \"深色模式\",\n                      ),\n                      visualDensity: VisualDensity.compact,\n                      value: 2,\n                      contentPadding: AppStyle.edgeInsetsH12,\n                    ),\n                  ],\n                ),\n              ),\n            ),\n          ),\n          AppStyle.vGap12,\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Text(\n              \"主题颜色\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => Column(\n                mainAxisSize: MainAxisSize.min,\n                children: [\n                  SettingsSwitch(\n                    value: controller.isDynamic.value,\n                    title: \"动态取色\",\n                    onChanged: (e) {\n                      controller.setIsDynamic(e);\n                      Get.forceAppUpdate();\n                    },\n                  ),\n                  if (!controller.isDynamic.value) AppStyle.divider,\n                  if (!controller.isDynamic.value)\n                    Padding(\n                      padding: AppStyle.edgeInsetsA12,\n                      child: Wrap(\n                        spacing: 8,\n                        runSpacing: 8,\n                        children: <Color>[\n                          const Color(0xffEF5350),\n                          const Color(0xff3498db),\n                          const Color(0xffF06292),\n                          const Color(0xff9575CD),\n                          const Color(0xff26C6DA),\n                          const Color(0xff26A69A),\n                          const Color(0xffFFF176),\n                          const Color(0xffFF9800),\n                        ]\n                            .map(\n                              (e) => GestureDetector(\n                                onTap: () {\n                                  controller.setStyleColor(e.v);\n                                  Get.forceAppUpdate();\n                                },\n                                child: Container(\n                                  width: 36,\n                                  height: 36,\n                                  decoration: BoxDecoration(\n                                    color: e,\n                                    borderRadius: AppStyle.radius4,\n                                    border: Border.all(\n                                      color: Colors.grey.withAlpha(50),\n                                      width: 1,\n                                    ),\n                                  ),\n                                  child: Obx(\n                                    () => Center(\n                                      child: Icon(\n                                        Icons.check,\n                                        color:\n                                            controller.styleColor.value == e.v\n                                                ? Colors.white\n                                                : Colors.transparent,\n                                      ),\n                                    ),\n                                  ),\n                                ),\n                              ),\n                            )\n                            .toList(),\n                      ),\n                    ),\n                ],\n              ),\n            ),\n          ),\n          AppStyle.vGap12,\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Text(\n              \"字体设置\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => SettingsMenu(\n                title: controller.curFontModel.value!.name,\n                value: controller.curFontModel.value!,\n                valueMap: controller.fontMap,\n                onChanged: (e) {\n                  controller.onFontSelected(e);\n                },\n                trailing: Obx(() {\n                  switch (controller.fontState.value) {\n                    case DownloadState.notDownloaded:\n                      return trailingBuild(\n                        widget: Tooltip(\n                          message: \"下载字体\",\n                          child: IconButton(\n                            icon: const Icon(Icons.download_outlined),\n                            onPressed: () => controller.downloadFont(),\n                          ),\n                        ),\n                      );\n\n                    case DownloadState.downloading:\n                      return trailingBuild(\n                        widget: SizedBox(\n                          width: 20,\n                          height: 20,\n                          child: CircularProgressIndicator(strokeWidth: 2),\n                        ),\n                      );\n                    case DownloadState.downloaded:\n                      return trailingBuild(\n                        widget: Tooltip(\n                          message: \"应用字体\",\n                          child: IconButton(\n                            icon: const Icon(Icons.check_circle_outline_outlined),\n                            onPressed: () => controller.changeFontFamily(),\n                          ),\n                        ),\n                      );\n                  }\n                }),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n\nextension ColorExt on Color {\n  static int _floatToInt8(double x) {\n    return (x * 255.0).round() & 0xff;\n  }\n\n  int get v =>\n      _floatToInt8(a) << 24 |\n      _floatToInt8(r) << 16 |\n      _floatToInt8(g) << 8 |\n      _floatToInt8(b) << 0;\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/auto_exit_settings_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_action.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\n\nclass AutoExitSettingsPage extends GetView<AppSettingsController> {\n  const AutoExitSettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"定时关闭设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          SettingsCard(\n            child: Column(\n              children: [\n                Obx(\n                  () => SettingsSwitch(\n                    value: controller.autoExitEnable.value,\n                    title: \"启用定时关闭\",\n                    onChanged: (e) {\n                      controller.setAutoExitEnable(e);\n                    },\n                  ),\n                ),\n                Obx(\n                  () => Visibility(\n                    visible: controller.autoExitEnable.value,\n                    child: AppStyle.divider,\n                  ),\n                ),\n                Obx(\n                  () => Visibility(\n                    visible: controller.autoExitEnable.value,\n                    child: SettingsAction(\n                      title: \"自动关闭时间\",\n                      value:\n                          \"${controller.autoExitDuration.value ~/ 60}小时${controller.autoExitDuration.value % 60}分钟\",\n                      subtitle: \"从进入直播间开始倒计时\",\n                      onTap: () {\n                        setTimer(context);\n                      },\n                    ),\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void setTimer(BuildContext context) async {\n    var value = await showTimePicker(\n      context: context,\n      initialTime: TimeOfDay(\n        hour: controller.autoExitDuration.value ~/ 60,\n        minute: controller.autoExitDuration.value % 60,\n      ),\n      initialEntryMode: TimePickerEntryMode.inputOnly,\n      builder: (_, child) {\n        return MediaQuery(\n          data: MediaQuery.of(context).copyWith(\n            alwaysUse24HourFormat: true,\n          ),\n          child: child!,\n        );\n      },\n    );\n    if (value == null || (value.hour == 0 && value.minute == 0)) {\n      return;\n    }\n    var duration = Duration(hours: value.hour, minutes: value.minute);\n    controller.setAutoExitDuration(duration.inMinutes);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/danmu_settings_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/widgets/settings/settings_action.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_number.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\n\nclass DanmuSettingsPage extends StatelessWidget {\n  const DanmuSettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"弹幕设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: const [\n          DanmuSettingsView(),\n        ],\n      ),\n    );\n  }\n}\n\nclass DanmuSettingsView extends GetView<AppSettingsController> {\n  final Function()? onTapDanmuShield;\n  final DanmakuController? danmakuController;\n\n  const DanmuSettingsView({\n    this.onTapDanmuShield,\n    this.danmakuController,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisSize: MainAxisSize.min,\n      crossAxisAlignment: CrossAxisAlignment.stretch,\n      children: [\n        Padding(\n          padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n          child: Text(\n            \"弹幕筛选\",\n            style: Get.textTheme.titleSmall,\n          ),\n        ),\n        SettingsCard(\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              SettingsAction(\n                title: \"关键词屏蔽\",\n                onTap: onTapDanmuShield ??\n                    () => Get.toNamed(RoutePath.kSettingsDanmuShield),\n              ),\n              Obx(\n                () => SettingsSwitch(\n                  title: \"弹幕去重\",\n                  subtitle: \"测试性功能\",\n                  value: controller.danmakuMaskEnable.value,\n                  onChanged: (e) {\n                    controller.setDanmakuMaskEnable(e);\n                  },\n                ),\n              ),\n            ],\n          ),\n        ),\n        Padding(\n          padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n          child: Text(\n            \"弹幕设置\",\n            style: Get.textTheme.titleSmall,\n          ),\n        ),\n        SettingsCard(\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              Obx(\n                () => SettingsSwitch(\n                  title: \"默认开关\",\n                  value: controller.danmuEnable.value,\n                  onChanged: (e) {\n                    controller.setDanmuEnable(e);\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"显示区域\",\n                  value: (controller.danmuArea.value * 100).toInt(),\n                  min: 10,\n                  max: 100,\n                  step: 10,\n                  unit: \"%\",\n                  onChanged: (e) {\n                    controller.setDanmuArea(e / 100.0);\n                    updateDanmuOption(\n                      danmakuController?.option.copyWith(area: e / 100.0),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"不透明度\",\n                  value: (controller.danmuOpacity.value * 100).toInt(),\n                  min: 10,\n                  max: 100,\n                  step: 10,\n                  unit: \"%\",\n                  onChanged: (e) {\n                    controller.setDanmuOpacity(e / 100.0);\n                    updateDanmuOption(\n                      danmakuController?.option.copyWith(opacity: e / 100.0),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"字体大小\",\n                  value: controller.danmuSize.toInt(),\n                  min: 8,\n                  max: 48,\n                  onChanged: (e) {\n                    controller.setDanmuSize(e.toDouble());\n                    updateDanmuOption(\n                      danmakuController?.option\n                          .copyWith(fontSize: e.toDouble()),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"字体粗细\",\n                  value: controller.danmuFontWeight.value,\n                  min: 0,\n                  max: 8,\n                  step: 1,\n                  displayValue: [\n                    \"极细\",\n                    \"很细\",\n                    \"细\",\n                    \"正常\",\n                    \"小粗\",\n                    \"偏粗\",\n                    \"粗\",\n                    \"很粗\",\n                    \"极粗\"\n                  ][controller.danmuFontWeight.value]\n                      .toString(),\n                  onChanged: (e) {\n                    controller.setDanmuFontWeight(e);\n                    updateDanmuOption(\n                      danmakuController?.option.copyWith(\n                        fontWeight: e,\n                      ),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"滚动速度\",\n                  subtitle: \"弹幕持续时间(秒)，越小速度越快\",\n                  value: controller.danmuSpeed.toInt(),\n                  min: 4,\n                  max: 20,\n                  onChanged: (e) {\n                    controller.setDanmuSpeed(e.toDouble());\n                    updateDanmuOption(\n                      danmakuController?.option.copyWith(duration: e.toDouble()),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"字体描边\",\n                  value: controller.danmuStrokeWidth.toInt(),\n                  min: 0,\n                  max: 10,\n                  onChanged: (e) {\n                    controller.setDanmuStrokeWidth(e.toDouble());\n                    updateDanmuOption(\n                      danmakuController?.option.copyWith(strokeWidth: e.toDouble()),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"顶部边距\",\n                  subtitle: \"曲面屏显示不全可设置此选项\",\n                  value: controller.danmuTopMargin.toInt(),\n                  min: 0,\n                  max: 48,\n                  step: 4,\n                  onChanged: (e) {\n                    controller.setDanmuTopMargin(e.toDouble());\n                  },\n                ),\n              ),\n              AppStyle.divider,\n              Obx(\n                () => SettingsNumber(\n                  title: \"底部边距\",\n                  subtitle: \"曲面屏显示不全可设置此选项\",\n                  value: controller.danmuBottomMargin.toInt(),\n                  min: 0,\n                  max: 48,\n                  step: 4,\n                  onChanged: (e) {\n                    controller.setDanmuBottomMargin(e.toDouble());\n                  },\n                ),\n              ),\n            ],\n          ),\n        ),\n        Padding(\n          padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n          child: Text(\n            \"弹幕去重参数设置\",\n            style: Get.textTheme.titleSmall,\n          ),\n        ),\n        SettingsCard(\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              Obx(\n                () => SettingsNumber(\n                  title: \"去重窗口大小(秒)\",\n                  value: AppSettingsController.instance.danmuWindowMs.value,\n                  step: 1,\n                  max: 45,\n                  min: 10,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuWindowMs(e);\n                  },\n                ),\n              ),\n              Obx(\n                () => SettingsSwitch(\n                  value: AppSettingsController\n                      .instance.danmuTextNormalization.value,\n                  title: \"文本归一化\",\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuTextNormalization(e);\n                  },\n                ),\n              ),\n              Obx(\n                () => SettingsSwitch(\n                  value: AppSettingsController\n                      .instance.danmuFrequencyControl.value,\n                  title: \"弹幕显示频率\",\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuFrequencyControl(e);\n                  },\n                ),\n              ),\n              Obx(\n                () => Visibility(\n                  visible: AppSettingsController\n                      .instance.danmuFrequencyControl.value,\n                  child: SettingsNumber(\n                    title: \"显示频率(次)\",\n                    value: AppSettingsController\n                        .instance.danmuMaxFrequency.value,\n                    step: 1,\n                    max: 10,\n                    min: 1,\n                    onChanged: (e) {\n                      AppSettingsController.instance.setDanmuMaxFrequency(e);\n                    },\n                  ),\n                ),\n              ),\n            ],\n          ),\n        ),\n      ],\n    );\n  }\n\n  void updateDanmuOption(DanmakuOption? option) {\n    if (danmakuController == null || option == null) return;\n    danmakuController!.updateOption(option);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/danmu_shield/danmu_shield_controller.dart",
    "content": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\n\nclass DanmuShieldController extends BaseController {\n  final TextEditingController textEditingController = TextEditingController();\n  final AppSettingsController settingsController =\n      Get.find<AppSettingsController>();\n  void add() {\n    if (textEditingController.text.isEmpty) {\n      SmartDialog.showToast(\"请输入关键词\");\n      return;\n    }\n\n    settingsController.addShieldList(textEditingController.text.trim());\n    textEditingController.text = \"\";\n  }\n\n  void remove(String item) {\n    settingsController.removeShieldList(item);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/danmu_shield/danmu_shield_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_controller.dart';\n\nclass DanmuShieldPage extends GetView<DanmuShieldController> {\n  const DanmuShieldPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"弹幕屏蔽\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          TextField(\n            controller: controller.textEditingController,\n            decoration: InputDecoration(\n              contentPadding: AppStyle.edgeInsetsH12,\n              border: const OutlineInputBorder(),\n              hintText: \"请输入关键词或正则表达式\",\n              suffixIcon: TextButton.icon(\n                onPressed: controller.add,\n                icon: const Icon(Icons.add),\n                label: const Text(\"添加\"),\n              ),\n            ),\n            onSubmitted: (e) {\n              controller.add();\n            },\n          ),\n          AppStyle.vGap4,\n          Text(\n            '以\"/\"开头和结尾将视作正则表达式, 如\"/\\\\d+/\"表示屏蔽所有数字',\n            style: Get.textTheme.bodySmall,\n          ),\n          AppStyle.vGap12,\n          Obx(\n            () => Text(\n              \"已添加${controller.settingsController.shieldList.length}个关键词（点击移除）\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          AppStyle.vGap12,\n          Obx(\n            () => Wrap(\n              runSpacing: 12,\n              spacing: 12,\n              children: controller.settingsController.shieldList\n                  .map(\n                    (item) => InkWell(\n                      borderRadius: AppStyle.radius24,\n                      onTap: () {\n                        controller.remove(item);\n                      },\n                      child: Container(\n                        decoration: BoxDecoration(\n                          border: Border.all(color: Colors.grey),\n                          borderRadius: AppStyle.radius24,\n                        ),\n                        padding: AppStyle.edgeInsetsH12.copyWith(\n                          top: 4,\n                          bottom: 4,\n                        ),\n                        child: Text(\n                          item,\n                          style: Get.textTheme.bodyMedium,\n                        ),\n                      ),\n                    ),\n                  )\n                  .toList(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/indexed_settings/indexed_settings_controller.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\n\nclass IndexedSettingsController extends GetxController {\n  RxList<String> siteSort = RxList<String>();\n  RxList<String> homeSort = RxList<String>();\n  @override\n  void onInit() {\n    siteSort = AppSettingsController.instance.siteSort;\n    homeSort = AppSettingsController.instance.homeSort;\n    super.onInit();\n  }\n\n  void updateSiteSort(int oldIndex, int newIndex) {\n    if (oldIndex < newIndex) {\n      newIndex -= 1;\n    }\n    final String item = siteSort.removeAt(oldIndex);\n    siteSort.insert(newIndex, item);\n    // ignore: invalid_use_of_protected_member\n    AppSettingsController.instance.setSiteSort(siteSort.value);\n  }\n\n  void updateHomeSort(int oldIndex, int newIndex) {\n    if (oldIndex < newIndex) {\n      newIndex -= 1;\n    }\n    final String item = homeSort.removeAt(oldIndex);\n    homeSort.insert(newIndex, item);\n    // ignore: invalid_use_of_protected_member\n    AppSettingsController.instance.setHomeSort(homeSort.value);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/indexed_settings/indexed_settings_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass IndexedSettingsPage extends GetView<IndexedSettingsController> {\n  const IndexedSettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"主页设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n            child: Text(\n              \"主页排序 (长按拖动排序，重启后生效)\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => ReorderableListView(\n                shrinkWrap: true,\n                physics: const NeverScrollableScrollPhysics(),\n                onReorder: controller.updateHomeSort,\n                children: controller.homeSort.map(\n                  (key) {\n                    var e = Constant.allHomePages[key]!;\n                    return ListTile(\n                      key: ValueKey(e.title),\n                      title: Text(e.title),\n                      visualDensity: VisualDensity.compact,\n                      leading: Icon(e.iconData),\n                      trailing: const Icon(Icons.drag_handle),\n                    );\n                  },\n                ).toList(),\n              ),\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"平台排序 (长按拖动排序，重启后生效)\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => ReorderableListView(\n                shrinkWrap: true,\n                physics: const NeverScrollableScrollPhysics(),\n                onReorder: controller.updateSiteSort,\n                children: controller.siteSort\n                    .where((key) => Sites.allSites[key]?.name != 'Twitch')\n                    .map(\n                  (key) {\n                    var e = Sites.allSites[key]!;\n                    return ListTile(\n                      key: ValueKey(e.id),\n                      visualDensity: VisualDensity.compact,\n                      title: Text(e.name),\n                      leading: Image.asset(\n                        e.logo,\n                        width: 24,\n                        height: 24,\n                      ),\n                      trailing: const Icon(Icons.drag_handle),\n                    );\n                  },\n                ).toList(),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/other/other_settings_controller.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:file_picker/file_picker.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:share_plus/share_plus.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:path/path.dart' as p;\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/services/firebase_service.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\n\nclass OtherSettingsController extends BaseController {\n  RxList<LogFileModel> logFiles = <LogFileModel>[].obs;\n\n  var videoOutputDrivers = {\n    \"gpu\": \"gpu\",\n    \"gpu-next\": \"gpu-next\",\n    \"xv\": \"xv (X11 only)\",\n    \"x11\": \"x11 (X11 only)\",\n    \"vdpau\": \"vdpau (X11 only)\",\n    \"direct3d\": \"direct3d (Windows only)\",\n    \"sdl\": \"sdl\",\n    \"dmabuf-wayland\": \"dmabuf-wayland\",\n    \"vaapi\": \"vaapi\",\n    \"null\": \"null\",\n    \"libmpv\": \"libmpv\",\n    \"mediacodec_embed\": \"mediacodec_embed (Android only)\",\n  };\n\n  var audioOutputDrivers = {\n    \"null\": \"null (No audio output)\",\n    \"pulse\": \"pulse (Linux, uses PulseAudio)\",\n    \"pipewire\": \"pipewire (Linux, via Pulse compatibility or native)\",\n    \"alsa\": \"alsa (Linux only)\",\n    \"oss\": \"oss (Linux only)\",\n    \"jack\": \"jack (Linux/macOS, low-latency audio)\",\n    \"directsound\": \"directsound (Windows only)\",\n    \"wasapi\": \"wasapi (Windows only)\",\n    \"winmm\": \"winmm (Windows only, legacy API)\",\n    \"audiounit\": \"audiounit (iOS only)\",\n    \"coreaudio\": \"coreaudio (macOS only)\",\n    \"opensles\": \"opensles (Android only)\",\n    \"audiotrack\": \"audiotrack (Android only)\",\n    \"aaudio\": \"aaudio (Android only)\",\n    \"pcm\": \"pcm (Cross-platform)\",\n    \"sdl\": \"sdl (Cross-platform, via SDL library)\",\n    \"openal\": \"openal (Cross-platform, OpenAL backend)\",\n    \"libao\": \"libao (Cross-platform, uses libao library)\",\n    \"auto\": \"auto (Not available)\"\n  };\n\n  var hardwareDecoder = {\n    \"no\": \"no\",\n    \"auto\": \"auto\",\n    \"auto-safe\": \"auto-safe\",\n    \"yes\": \"yes\",\n    \"auto-copy\": \"auto-copy\",\n    \"d3d11va\": \"d3d11va\",\n    \"d3d11va-copy\": \"d3d11va-copy\",\n    \"videotoolbox\": \"videotoolbox\",\n    \"videotoolbox-copy\": \"videotoolbox-copy\",\n    \"vaapi\": \"vaapi\",\n    \"vaapi-copy\": \"vaapi-copy\",\n    \"nvdec\": \"nvdec\",\n    \"nvdec-copy\": \"nvdec-copy\",\n    \"drm\": \"drm\",\n    \"drm-copy\": \"drm-copy\",\n    \"vulkan\": \"vulkan\",\n    \"vulkan-copy\": \"vulkan-copy\",\n    \"dxva2\": \"dxva2\",\n    \"dxva2-copy\": \"dxva2-copy\",\n    \"vdpau\": \"vdpau\",\n    \"vdpau-copy\": \"vdpau-copy\",\n    \"mediacodec\": \"mediacodec\",\n    \"mediacodec-copy\": \"mediacodec-copy\",\n    \"cuda\": \"cuda\",\n    \"cuda-copy\": \"cuda-copy\",\n    \"crystalhd\": \"crystalhd\",\n    \"rkmpp\": \"rkmpp\"\n  };\n\n  @override\n  void onInit() {\n    loadLogFiles();\n    super.onInit();\n  }\n\n  void setFirebaseEnable(bool e){\n    AppSettingsController.instance.setFirebaseEnable(e);\n    FirebaseService.setCrashlytics(e);\n  }\n\n  void setLogEnable(bool e) {\n    AppSettingsController.instance.setLogEnable(e);\n    if (e) {\n      Log.initWriter();\n      Future.delayed(const Duration(milliseconds: 100), () {\n        loadLogFiles();\n      });\n    } else {\n      Log.disposeWriter();\n    }\n  }\n\n  void loadLogFiles() async {\n    var supportDir = await getApplicationSupportDirectory();\n    var logDir = Directory(\"${supportDir.path}/log\");\n    if (!await logDir.exists()) {\n      await logDir.create();\n    }\n    logFiles.clear();\n    await logDir.list().forEach((element) {\n      var file = element as File;\n      var name = p.basename(file.path);\n      var time = file.lastModifiedSync();\n      var size = file.lengthSync();\n      logFiles.add(LogFileModel(name, file.path, time, size));\n    });\n    //logFiles 名称倒序\n    logFiles.sort((a, b) => b.time.compareTo(a.time));\n  }\n\n  void cleanLog() async {\n    if (AppSettingsController.instance.logEnable.value) {\n      SmartDialog.showToast(\"请先关闭日志记录\");\n      return;\n    }\n\n    var supportDir = await getApplicationSupportDirectory();\n    var logDir = Directory(\"${supportDir.path}/log\");\n    if (await logDir.exists()) {\n      await logDir.delete(recursive: true);\n    }\n    loadLogFiles();\n  }\n\n  void shareLogFile(LogFileModel item) {\n    SharePlus.instance.share(ShareParams(files: [XFile(item.path)]));\n  }\n\n  void saveLogFile(LogFileModel item) async {\n    var filePath = await FilePicker.platform.saveFile(\n      allowedExtensions: ['log'],\n      type: FileType.custom,\n      fileName: item.name,\n    );\n    if (filePath != null) {\n      var file = File(item.path);\n      await file.copy(filePath);\n      SmartDialog.showToast(\"保存成功\");\n    }\n  }\n\n  void exportConfig() async {\n    try {\n      // 组装数据\n      var data = {\n        \"type\": \"simple_live\",\n        \"platform\": Platform.operatingSystem,\n        \"version\": 1,\n        \"time\": DateTime.now().millisecondsSinceEpoch,\n        \"config\": LocalStorageService.instance.settingsBox.toMap(),\n        \"shield\": LocalStorageService.instance.shieldBox.toMap(),\n      };\n\n      var bytes = Uint8List.fromList(utf8.encode(jsonEncode(data)));\n\n      // FilePicker 直接写入\n      var inlineSave = Platform.isAndroid || Platform.isIOS || kIsWeb;\n\n      var path = await FilePicker.platform.saveFile(\n        allowedExtensions: ['json'],\n        type: FileType.custom,\n        fileName: \"simple_live_config.json\",\n        bytes: inlineSave ? bytes : null,\n      );\n\n      if (path == null && !kIsWeb) {\n        SmartDialog.showToast(\"保存取消\");\n        return;\n      }\n\n      // 桌面平台需要手动写入\n      if (!inlineSave && path != null) {\n        await File(path).writeAsBytes(bytes);\n      }\n\n      SmartDialog.showToast(\"保存成功\");\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"导出失败:$e\");\n    }\n  }\n\n  void importConfig() async {\n    try {\n      var file = await FilePicker.platform.pickFiles(\n        allowedExtensions: ['json'],\n        type: FileType.custom,\n      );\n      if (file == null) {\n        return;\n      }\n      var filePath = file.files.single.path!;\n      var data = jsonDecode(await File(filePath).readAsString());\n      if (data[\"type\"] != \"simple_live\") {\n        SmartDialog.showToast(\"不支持的配置文件\");\n        return;\n      }\n      // 检查platform\n      if (data[\"platform\"] != Platform.operatingSystem &&\n          !await Utils.showAlertDialog(\"导入配置文件平台不匹配,是否继续导入?\", title: \"平台不匹配\")) {\n        return;\n      }\n      LocalStorageService.instance.settingsBox.clear();\n      LocalStorageService.instance.shieldBox.clear();\n      LocalStorageService.instance.settingsBox.putAll(data[\"config\"]);\n      LocalStorageService.instance.shieldBox\n          .putAll(data[\"shield\"].cast<String, String>());\n      SmartDialog.showToast(\"导入成功,重启生效\");\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"导入失败:$e\");\n    }\n  }\n\n  void resetDefaultConfig() {\n    Utils.showAlertDialog(\"是否重置所有配置为默认值?\").then((value) {\n      if (value) {\n        LocalStorageService.instance.settingsBox.clear();\n        LocalStorageService.instance.shieldBox.clear();\n        SmartDialog.showToast(\"重置成功,重启生效\");\n      }\n    });\n  }\n}\n\nclass LogFileModel {\n  late String name;\n  late String path;\n  late DateTime time;\n  late int size;\n  LogFileModel(this.name, this.path, this.time, this.size);\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/other/other_settings_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/settings/other/other_settings_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_menu.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\nimport 'package:url_launcher/url_launcher_string.dart';\n\nclass OtherSettingsPage extends GetView<OtherSettingsController> {\n  const OtherSettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"其他设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          SettingsCard(\n            child: Padding(\n              padding: AppStyle.edgeInsetsA4,\n              child: Row(\n                children: [\n                  Expanded(\n                    child: TextButton.icon(\n                      onPressed: controller.exportConfig,\n                      label: const Text(\"导出配置\"),\n                      icon: const Icon(Remix.export_line),\n                    ),\n                  ),\n                  Expanded(\n                    child: TextButton.icon(\n                      onPressed: controller.importConfig,\n                      label: const Text(\"导入配置\"),\n                      icon: const Icon(Remix.import_line),\n                    ),\n                  ),\n                  Expanded(\n                    child: TextButton.icon(\n                      onPressed: controller.resetDefaultConfig,\n                      label: const Text(\"重置配置\"),\n                      icon: const Icon(Remix.restart_line),\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"播放器高级设置\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n            child: Text.rich(\n              TextSpan(\n                text: \"请勿随意修改以下设置，除非你知道自己在做什么。\\n在修改以下设置前，你应该先查阅\",\n                children: [\n                  WidgetSpan(\n                    child: GestureDetector(\n                      onTap: () {\n                        launchUrlString(\n                            \"https://mpv.io/manual/stable/#video-output-drivers\");\n                      },\n                      child: const Text(\n                        \"MPV的文档\",\n                        style: TextStyle(\n                          color: Colors.blue,\n                          fontSize: 12,\n                          decoration: TextDecoration.underline,\n                        ),\n                      ),\n                    ),\n                  ),\n                ],\n              ),\n              style: const TextStyle(fontSize: 12, color: Colors.grey),\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              children: [\n                Obx(\n                  () => SettingsSwitch(\n                    value:\n                        AppSettingsController.instance.customPlayerOutput.value,\n                    title: \"自定义输出驱动与硬件加速\",\n                    onChanged: (e) {\n                      AppSettingsController.instance.setCustomPlayerOutput(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsMenu(\n                    title: \"视频输出驱动(--vo)\",\n                    value:\n                        AppSettingsController.instance.videoOutputDriver.value,\n                    valueMap: controller.videoOutputDrivers,\n                    onChanged: (e) {\n                      AppSettingsController.instance.setVideoOutputDriver(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsMenu(\n                    title: \"音频输出驱动(--ao)\",\n                    value:\n                        AppSettingsController.instance.audioOutputDriver.value,\n                    valueMap: controller.audioOutputDrivers,\n                    onChanged: (e) {\n                      AppSettingsController.instance.setAudioOutputDriver(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsMenu(\n                    title: \"硬件解码器(--hwdec)\",\n                    value: AppSettingsController\n                        .instance.videoHardwareDecoder.value,\n                    valueMap: controller.hardwareDecoder,\n                    onChanged: (e) {\n                      AppSettingsController.instance.setVideoHardwareDecoder(e);\n                    },\n                  ),\n                ),\n                Obx(\n                  () => SettingsSwitch(\n                    value: AppSettingsController\n                        .instance.videoDoubleBuffering.value,\n                    title: \"自定义开启双重缓存\",\n                    onChanged: (e) {\n                      AppSettingsController.instance.setVideoDoubleBuffering(e);\n                    },\n                  ),\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"日志记录\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              children: [\n                Obx(\n                  () => SettingsSwitch(\n                    value: AppSettingsController.instance.logEnable.value,\n                    title: \"开启日志记录\",\n                    subtitle: \"开启后将记录调试日志，可以将日志文件提供给开发者用于排查问题\",\n                    onChanged: controller.setLogEnable,\n                  ),\n                ),\n                Visibility(\n                  visible: Platform.isAndroid,\n                  child: Obx(\n                    () => SettingsSwitch(\n                      value: AppSettingsController.instance.firebaseEnable.value,\n                      title: \"开启崩溃分析\",\n                      subtitle: \"开启后应用崩溃时自动上传脱敏崩溃日志给开发者用于排查问题\",\n                      onChanged: controller.setFirebaseEnable,\n                    ),\n                  ),\n                ),\n              ],\n            ),\n          ),\n          ListTile(\n            contentPadding: AppStyle.edgeInsetsL12,\n            visualDensity: VisualDensity.compact,\n            title: Text(\n              \"日志列表\",\n              style: Get.textTheme.titleSmall,\n            ),\n            trailing: TextButton.icon(\n              onPressed: () {\n                controller.cleanLog();\n              },\n              label: const Text(\"清空日志\"),\n              icon: const Icon(Icons.clear_all),\n            ),\n          ),\n          SettingsCard(\n            child: SizedBox(\n              height: 300,\n              child: Obx(\n                () => ListView.separated(\n                  itemCount: controller.logFiles.length,\n                  separatorBuilder: (context, index) => AppStyle.divider,\n                  itemBuilder: (context, index) {\n                    var item = controller.logFiles[index];\n                    return ListTile(\n                      visualDensity: VisualDensity.compact,\n                      contentPadding: AppStyle.edgeInsetsL12.copyWith(right: 4),\n                      title: Text(item.name),\n                      subtitle: Text(Utils.parseFileSize(item.size)),\n                      trailing: Row(\n                        mainAxisSize: MainAxisSize.min,\n                        children: [\n                          if (!Platform.isLinux)\n                            IconButton(\n                              onPressed: () {\n                                controller.shareLogFile(item);\n                              },\n                              icon: const Icon(Icons.share),\n                            ),\n                          IconButton(\n                            onPressed: () {\n                              controller.saveLogFile(item);\n                            },\n                            icon: const Icon(Icons.save),\n                          ),\n                        ],\n                      ),\n                    );\n                  },\n                ),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/settings/play_settings_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\nimport 'package:simple_live_app/widgets/settings/settings_menu.dart';\nimport 'package:simple_live_app/widgets/settings/settings_number.dart';\nimport 'package:simple_live_app/widgets/settings/settings_switch.dart';\n\nclass PlaySettingsPage extends GetView<AppSettingsController> {\n  const PlaySettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"直播间设置\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n            child: Text(\n              \"播放器\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                Obx(\n                  () => SettingsSwitch(\n                    title: \"硬件解码\",\n                    value: controller.hardwareDecode.value,\n                    subtitle: \"播放失败可尝试关闭此选项\",\n                    onChanged: (e) {\n                      controller.setHardwareDecode(e);\n                    },\n                  ),\n                ),\n                if (Platform.isAndroid) AppStyle.divider,\n                Obx(\n                  () => Visibility(\n                    visible: Platform.isAndroid,\n                    child: SettingsSwitch(\n                      title: \"兼容模式\",\n                      subtitle: \"若播放卡顿可尝试打开此选项\",\n                      value: controller.playerCompatMode.value,\n                      onChanged: (e) {\n                        controller.setPlayerCompatMode(e);\n                      },\n                    ),\n                  ),\n                ),\n                // AppStyle.divider,\n                // Obx(\n                //   () => SettingsNumber(\n                //     title: \"缓冲区大小\",\n                //     subtitle: \"若播放卡顿可尝试调高此选项\",\n                //     value: controller.playerBufferSize.value,\n                //     min: 32,\n                //     max: 1024,\n                //     step: 4,\n                //     unit: \"MB\",\n                //     onChanged: (e) {\n                //       controller.setPlayerBufferSize(e);\n                //     },\n                //   ),\n                // ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsSwitch(\n                    title: \"进入后台自动暂停\",\n                    value: controller.playerAutoPause.value,\n                    onChanged: (e) {\n                      controller.setPlayerAutoPause(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsMenu<int>(\n                    title: \"画面尺寸\",\n                    value: controller.scaleMode.value,\n                    valueMap: const {\n                      0: \"适应\",\n                      1: \"拉伸\",\n                      2: \"铺满\",\n                      3: \"16:9\",\n                      4: \"4:3\",\n                    },\n                    onChanged: (e) {\n                      controller.setScaleMode(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsSwitch(\n                    title: \"使用HTTPS链接\",\n                    subtitle: \"将http链接替换为https\",\n                    value: controller.playerForceHttps.value,\n                    onChanged: (e) {\n                      controller.setPlayerForceHttps(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsSwitch(\n                      title: \"抖音HLS流优先\",\n                      subtitle: \"hls流可缓解部分直播间抖动问题,重启后生效\",\n                      value: controller.douyinHlsFirst.value,\n                      onChanged: (e) {\n                        controller.setDouyinHlsFirst(e);\n                      }),\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"直播间\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                Obx(\n                  () => SettingsSwitch(\n                    title: \"进入直播间自动全屏\",\n                    value: controller.autoFullScreen.value,\n                    onChanged: (e) {\n                      controller.setAutoFullScreen(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => Visibility(\n                    visible: Platform.isAndroid,\n                    child: SettingsSwitch(\n                      title: \"进入小窗隐藏弹幕\",\n                      value: controller.pipHideDanmu.value,\n                      onChanged: (e) {\n                        controller.setPIPHideDanmu(e);\n                      },\n                    ),\n                  ),\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"清晰度\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              children: [\n                Obx(\n                  () => SettingsMenu<int>(\n                    title: \"默认清晰度\",\n                    value: controller.qualityLevel.value,\n                    valueMap: const {\n                      0: \"最低\",\n                      1: \"中等\",\n                      2: \"最高\",\n                    },\n                    onChanged: (e) {\n                      controller.setQualityLevel(e);\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsMenu<int>(\n                    title: \"数据网络清晰度\",\n                    value: controller.qualityLevelCellular.value,\n                    valueMap: const {\n                      0: \"最低\",\n                      1: \"中等\",\n                      2: \"最高\",\n                    },\n                    onChanged: (e) {\n                      controller.setQualityLevelCellular(e);\n                    },\n                  ),\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"聊天区\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                Obx(\n                  () => SettingsNumber(\n                    title: \"文字大小\",\n                    value: controller.chatTextSize.value.toInt(),\n                    min: 8,\n                    max: 36,\n                    onChanged: (e) {\n                      controller.setChatTextSize(e.toDouble());\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsNumber(\n                    title: \"上下间隔\",\n                    value: controller.chatTextGap.value.toInt(),\n                    min: 0,\n                    max: 12,\n                    onChanged: (e) {\n                      controller.setChatTextGap(e.toDouble());\n                    },\n                  ),\n                ),\n                AppStyle.divider,\n                Obx(\n                  () => SettingsSwitch(\n                    title: \"气泡样式\",\n                    value: controller.chatBubbleStyle.value,\n                    onChanged: (e) {\n                      controller.setChatBubbleStyle(e);\n                    },\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/device/sync_device_controller.dart",
    "content": "import 'dart:convert';\n\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/sync_client_info_model.dart';\nimport 'package:simple_live_app/requests/sync_client_request.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/sync_service.dart';\n\nclass SyncDeviceController extends BaseController {\n  final SyncClinet client;\n  final SyncClientInfoModel info;\n  SyncDeviceController({required this.client, required this.info});\n  SyncClientRequest request = SyncClientRequest();\n\n  Future<bool> showOverlayDialog() async {\n    var overlay = await Utils.showAlertDialog(\n      \"是否覆盖远端数据？\",\n      title: \"数据覆盖\",\n      confirm: \"覆盖\",\n      cancel: \"不覆盖\",\n    );\n    return overlay;\n  }\n\n  void syncFollowAndTag() async {\n    try {\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"同步中...\");\n      var users = DBService.instance.getFollowList();\n      var tags = DBService.instance.getFollowTagList();\n      var data = json.encode(users.map((e) => e.toJson()).toList());\n      var dataT = json.encode(tags.map((e) => e.toJson()).toList());\n      await request.syncFollow(client, data, overlay: overlay);\n      // 标签和关注必须同时同步\n      await request.syncTag(client, dataT, overlay: overlay);\n      SmartDialog.showToast(\"已同步关注列表和标签\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncHistory() async {\n    try {\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"同步中...\");\n      var histores = DBService.instance.getHistories();\n      var data = json.encode(histores.map((e) => e.toJson()).toList());\n      await request.syncHistory(client, data, overlay: overlay);\n      SmartDialog.showToast(\"已同步历史记录\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncBlockedWord() async {\n    try {\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"同步中...\");\n      var shieldList = AppSettingsController.instance.shieldList;\n      var data = json.encode(shieldList.toList());\n      await request.syncBlockedWord(client, data, overlay: overlay);\n      SmartDialog.showToast(\"已同步屏蔽词\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncBiliAccount() async {\n    try {\n      if (!BiliBiliAccountService.instance.logined.value) {\n        SmartDialog.showToast(\"未登录哔哩哔哩\");\n        return;\n      }\n      SmartDialog.showLoading(msg: \"同步中...\");\n\n      await request.syncBiliAccount(\n          client, BiliBiliAccountService.instance.cookie);\n      SmartDialog.showToast(\"已同步哔哩哔哩账号\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/device/sync_device_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/device/sync_device_controller.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass SyncDevicePage extends GetView<SyncDeviceController> {\n  const SyncDevicePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"同步\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n        children: [\n          SettingsCard(\n            child: ListTile(\n              leading: buildIcon(),\n              title: Text(controller.info.name),\n              subtitle: Text(\n                  \"${controller.info.type.toUpperCase()}   ${controller.info.address}\"),\n            ),\n          ),\n          AppStyle.vGap12,\n          SettingsCard(\n            child: Column(\n              children: [\n                ListTile(\n                  leading: const Icon(Remix.heart_line),\n                  title: const Text(\"同步关注列表\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncFollowAndTag();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Icons.history),\n                  title: const Text(\"同步观看记录\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncHistory();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Remix.shield_keyhole_line),\n                  title: const Text(\"同步弹幕屏蔽词\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncBlockedWord();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Remix.account_circle_line),\n                  title: const Text(\"同步哔哩哔哩账号\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncBiliAccount();\n                  },\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildIcon() {\n    var icon = controller.info.type.toLowerCase();\n\n    if (icon == \"android\") {\n      return const Icon(Remix.android_line);\n    } else if (icon == \"ios\") {\n      return const Icon(Remix.apple_line);\n    } else if (icon == \"tv\") {\n      return const Icon(Remix.tv_2_line);\n    } else if (icon == \"windows\") {\n      return const Icon(Remix.microsoft_fill);\n    } else if (icon == \"macos\") {\n      return const Icon(Remix.mac_line);\n    } else if (icon == \"linux\") {\n      return const Icon(Remix.ubuntu_line);\n    } else {\n      return const Icon(Remix.device_line);\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/local_sync_controller.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\n\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_flutter/qr_flutter.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/requests/sync_client_request.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\n\nimport 'package:simple_live_app/services/sync_service.dart';\n\nclass LocalSyncController extends BaseController {\n  final String? address;\n  LocalSyncController(this.address);\n\n  @override\n  void onInit() {\n    SyncService.instance.refreshClients();\n    Future.delayed(Duration.zero, initConnect);\n    super.onInit();\n  }\n\n  void initConnect() {\n    if (address != null && address!.isNotEmpty) {\n      addressController.text = address!;\n      connect();\n    }\n  }\n\n  TextEditingController addressController = TextEditingController();\n  SyncClientRequest request = SyncClientRequest();\n\n  void connect() async {\n    var address = addressController.text;\n    if (address.isEmpty) {\n      SmartDialog.showToast(\"请输入地址\");\n      return;\n    }\n    if (address.startsWith('http')) {\n      var uri = Uri.tryParse(address);\n      if (uri != null) {\n        address = uri.host;\n      }\n    } else if (address.contains(':')) {\n      var parts = address.split(\":\");\n      address = parts.first;\n    }\n\n    var client = SyncClinet(\n      id: 'manual',\n      address: address,\n      port: SyncService.httpPort,\n      name: \"手动输入\",\n      type: Platform.operatingSystem,\n    );\n    connectClient(client);\n  }\n\n  void connectClient(SyncClinet client) async {\n    try {\n      SmartDialog.showLoading(msg: \"连接中...\");\n      var info = await request.getClientInfo(client);\n      AppNavigator.toSyncDevice(client, info);\n    } catch (e) {\n      SmartDialog.showToast(\"连接失败:$e\");\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void toScanQr() async {\n    var result = await Get.toNamed(RoutePath.kSyncScan);\n    if (result == null || result.isEmpty) {\n      return;\n    }\n    var addressList = (result as String).split(\";\");\n    if (addressList.length >= 2) {\n      //弹窗选择\n      showPickerAddress(addressList);\n    } else {\n      addressController.text = result;\n      //connect();\n    }\n  }\n\n  void showPickerAddress(List<String> addressList) {\n    SmartDialog.showToast(\"扫描到多个地址，请选择一个连接\");\n    Utils.showBottomSheet(\n      title: '请选择地址',\n      child: ListView.builder(\n        itemBuilder: (_, i) {\n          return ListTile(\n            title: Text(addressList[i]),\n            onTap: () {\n              Get.back();\n              addressController.text = addressList[i];\n              // connect();\n            },\n          );\n        },\n        itemCount: addressList.length,\n      ),\n    );\n  }\n\n  void showInfo() {\n    Utils.showBottomSheet(\n      title: \"本机信息\",\n      child: Column(\n        children: [\n          Visibility(\n            visible: SyncService.instance.httpRunning.value,\n            child: GestureDetector(\n              onTap: () {\n                Get.back();\n              },\n              child: QrImageView(\n                data: SyncService.instance.ipAddress.value,\n                version: QrVersions.auto,\n                backgroundColor: Colors.white,\n                padding: AppStyle.edgeInsetsA12,\n                size: 200,\n              ),\n            ),\n          ),\n          AppStyle.vGap24,\n          Visibility(\n            visible: SyncService.instance.httpRunning.value,\n            child: Text(\n              '服务已启动：${SyncService.instance.ipAddress.value.split(';').map((e) => '$e:${SyncService.httpPort}').join('；')}',\n              textAlign: TextAlign.center,\n            ),\n          ),\n          Visibility(\n            visible: !SyncService.instance.httpRunning.value,\n            child: Text(\n              'HTTP服务未启动：${SyncService.instance.httpErrorMsg}，请尝试重启应用',\n              textAlign: TextAlign.center,\n            ),\n          ),\n          AppStyle.vGap12,\n          Visibility(\n            visible: SyncService.instance.httpRunning.value,\n            child: const Text(\n              \"请使用其他Slive客户端扫描上方二维码\\n建立连接后可选择需要同步的数据\",\n              textAlign: TextAlign.center,\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/local_sync_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/local_sync_controller.dart';\nimport 'package:simple_live_app/services/sync_service.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass LocalSyncPage extends GetView<LocalSyncController> {\n  const LocalSyncPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('局域网数据同步'),\n        actions: [\n          TextButton.icon(\n            onPressed: controller.showInfo,\n            icon: const Icon(Icons.qr_code),\n            label: const Text(\"信息\"),\n          ),\n        ],\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          SettingsCard(\n            child: Padding(\n              padding: AppStyle.edgeInsetsA12,\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.stretch,\n                mainAxisSize: MainAxisSize.min,\n                children: [\n                  TextField(\n                    controller: controller.addressController,\n                    onSubmitted: (e) {\n                      controller.connect();\n                    },\n                    decoration: InputDecoration(\n                      labelText: '客户端地址',\n                      hintText: '请输入地址或扫码自动填写',\n                      contentPadding: AppStyle.edgeInsetsH12,\n                      border: const OutlineInputBorder(),\n                      suffixIcon: Visibility(\n                        visible: Platform.isAndroid || Platform.isIOS,\n                        child: TextButton.icon(\n                          onPressed: controller.toScanQr,\n                          icon: const Icon(Remix.qr_scan_line),\n                          label: const Text(\"扫一扫\"),\n                        ),\n                      ),\n                    ),\n                  ),\n                  AppStyle.vGap12,\n                  ElevatedButton(\n                    onPressed: () {\n                      controller.connect();\n                    },\n                    child: const Text(\"连接\"),\n                  ),\n                ],\n              ),\n            ),\n          ),\n          AppStyle.vGap12,\n          ListTile(\n            title: Obx(\n              () => Text(\n                \"已发现设备(${SyncService.instance.scanClients.length})\",\n                style: Get.textTheme.titleSmall,\n              ),\n            ),\n            visualDensity: VisualDensity.compact,\n            contentPadding: AppStyle.edgeInsetsH12,\n            trailing: IconButton(\n              visualDensity: VisualDensity.compact,\n              onPressed: () {\n                SyncService.instance.refreshClients();\n              },\n              icon: const Icon(Icons.refresh),\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => ListView.separated(\n                shrinkWrap: true,\n                padding: EdgeInsets.zero,\n                physics: const NeverScrollableScrollPhysics(),\n                separatorBuilder: (BuildContext context, int index) =>\n                    AppStyle.divider,\n                itemCount: SyncService.instance.scanClients.length,\n                itemBuilder: (BuildContext context, int index) {\n                  var client = SyncService.instance.scanClients[index];\n                  return ListTile(\n                    title: Text(client.name),\n                    subtitle: Text(client.address),\n                    trailing: const Icon(Icons.chevron_right),\n                    onTap: () {\n                      controller.connectClient(client);\n                    },\n                  );\n                },\n              ),\n            ),\n          ),\n          AppStyle.vGap12,\n          const Text(\n            \"如果无法扫描到设备，请手动输入地址\",\n            textAlign: TextAlign.center,\n            style: TextStyle(\n              color: Colors.grey,\n              fontSize: 14,\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\n\nclass SyncScanQRControlelr extends BaseController {\n  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');\n  QRViewController? qrController;\n  StreamSubscription<Barcode>? barcodeStreamSubscription;\n  bool pause = false;\n  void onQRViewCreated(QRViewController controller) {\n    qrController = controller;\n    barcodeStreamSubscription =\n        qrController!.scannedDataStream.listen((scanData) async {\n      Log.d(scanData.toString());\n      if (pause) {\n        return;\n      }\n      pause = true;\n      // 扫码成功后暂停摄像头\n      await controller.pauseCamera();\n      var code = scanData.code ?? \"\";\n      // 处理扫码结果\n      if (code.isEmpty) {\n        pause = false;\n        await controller.resumeCamera();\n        return;\n      }\n\n      // 如果是5位字符串，为房间号\n      if (code.length == 5) {\n        Get.offAndToNamed(RoutePath.kRemoteSyncRoom, arguments: code);\n        return;\n      } else {\n        var addressList = code.split(\";\");\n        if (addressList.length >= 2) {\n          //弹窗选择\n          showPickerAddress(addressList);\n        } else {\n          Get.back(result: code);\n        }\n      }\n    });\n  }\n\n  void showPickerAddress(List<String> addressList) async {\n    SmartDialog.showToast(\"扫描到多个地址，请选择一个连接\");\n    var address = await Utils.showBottomSheet(\n      title: '请选择地址',\n      child: ListView.builder(\n        itemBuilder: (_, i) {\n          return ListTile(\n            title: Text(addressList[i]),\n            onTap: () {\n              Get.back(result: addressList[i]);\n            },\n          );\n        },\n        itemCount: addressList.length,\n      ),\n    );\n    if (address != null && address.isNotEmpty) {\n      Get.back(result: address);\n    }\n  }\n\n  @override\n  void onClose() {\n    barcodeStreamSubscription?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/local_sync/scan_qr/sync_scan_qr_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart';\n\nclass SyncScanQRPage extends GetView<SyncScanQRControlelr> {\n  const SyncScanQRPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('扫描二维码'),\n        actions: [\n          IconButton(\n            onPressed: () {\n              controller.qrController?.toggleFlash();\n            },\n            icon: const Icon(Icons.flash_on),\n          ),\n          // 反转摄像头\n          IconButton(\n            onPressed: () {\n              controller.qrController?.flipCamera();\n            },\n            icon: const Icon(Icons.flip_camera_android),\n          ),\n        ],\n      ),\n      body: Stack(\n        children: [\n          QRView(\n            key: controller.qrKey,\n            onQRViewCreated: controller.onQRViewCreated,\n          ),\n          const ScanRectangle(),\n        ],\n      ),\n    );\n  }\n}\n\nclass ScanRectangle extends StatefulWidget {\n  const ScanRectangle({super.key});\n\n  @override\n  State<ScanRectangle> createState() => _ScanRectangleState();\n}\n\nclass _ScanRectangleState extends State<ScanRectangle>\n    with SingleTickerProviderStateMixin {\n  late AnimationController animeController;\n  late Animation<Offset> animation;\n\n  @override\n  void initState() {\n    animeController =\n        AnimationController(duration: const Duration(seconds: 2), vsync: this);\n    animeController.addStatusListener((status) {\n      if (status == AnimationStatus.completed) {\n        animeController.reverse();\n      } else if (status == AnimationStatus.dismissed) {\n        animeController.forward();\n      }\n    });\n    animation = Tween(\n      begin: const Offset(0, 0),\n      end: const Offset(0, 1),\n    ).animate(animeController);\n    animeController.forward();\n    super.initState();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: Container(\n        height: 240,\n        width: 240,\n        decoration: BoxDecoration(\n          border: Border.all(\n            color: Colors.grey.withAlpha(50),\n            width: 2,\n          ),\n        ),\n        child: SlideTransition(\n          position: animation,\n          child: Container(\n            height: 240,\n            width: 240,\n            decoration: const BoxDecoration(\n              border: Border(\n                top: BorderSide(\n                  width: 2,\n                  color: Colors.green,\n                ),\n              ),\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n\n  @override\n  void dispose() {\n    animeController.dispose();\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/remote_sync/room/remote_sync_room_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_flutter/qr_flutter.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/signalr_service.dart';\n\nclass RemoteSyncRoomController extends BaseController {\n  final String roomId;\n  final SignalRService signalR = SignalRService();\n  RemoteSyncRoomController(this.roomId) {\n    if (roomId.isNotEmpty) {\n      currentRoomId.value = roomId;\n    }\n  }\n  StreamSubscription? _roomDestroyedSubscription;\n  StreamSubscription? _roomUserUpdatedSubscription;\n  StreamSubscription? _onFavoriteSubscription;\n  StreamSubscription? _onHistorySubscription;\n  StreamSubscription? _onShieldWordSubscription;\n  StreamSubscription? _onBiliAccountSubscription;\n  var currentRoomId = \"--\".obs;\n  RxList<RoomUser> roomUsers = <RoomUser>[].obs;\n\n  Timer? _timer;\n  var countDown = 600.obs;\n\n  @override\n  void onInit() {\n    connect();\n    super.onInit();\n  }\n\n  void connect() async {\n    listenSignalR();\n    await signalR.connect();\n    if (signalR.state == SignalRConnectionState.connected) {\n      if (roomId.isEmpty) {\n        createRoom();\n      } else {\n        joinRoom(roomId);\n      }\n    }\n  }\n\n  void createRoom() async {\n    try {\n      var resp = await signalR.createRoom();\n      if (resp.isSuccess) {\n        currentRoomId.value = resp.data!;\n        _startTimer();\n      } else {\n        SmartDialog.showToast(resp.message);\n        Get.back();\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"创建房间失败\");\n      Get.back();\n    }\n  }\n\n  void _startTimer() {\n    // 倒计时5分钟，自动关闭页面\n    countDown.value = 600;\n    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {\n      countDown--;\n      if (countDown <= 0) {\n        timer.cancel();\n        Get.back();\n      }\n    });\n  }\n\n  void joinRoom(String roomId) async {\n    try {\n      var resp = await signalR.joinRoom(roomId);\n      if (!resp.isSuccess) {\n        SmartDialog.showToast(resp.message);\n        Get.back();\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"加入房间失败\");\n      Get.back();\n    }\n  }\n\n  void listenSignalR() {\n    _roomDestroyedSubscription = signalR.onRoomDestroyedStream.listen((roomId) {\n      SmartDialog.showToast(\"房间已被销毁\");\n      Get.back();\n    });\n    _roomUserUpdatedSubscription = signalR.onRoomUserUpdatedStream.listen(\n      (roomUsers) {\n        this.roomUsers.assignAll(roomUsers);\n      },\n    );\n    _onFavoriteSubscription = signalR.onFavoriteStream.listen((data) {\n      onReceiveFavorite(data.$1, data.$2);\n    });\n    _onHistorySubscription = signalR.onHistoryStream.listen((data) {\n      onReceiveHistory(data.$1, data.$2);\n    });\n    _onShieldWordSubscription = signalR.onShieldWordStream.listen((data) {\n      onReceiveShieldWord(data.$1, data.$2);\n    });\n    _onBiliAccountSubscription = signalR.onBiliAccountStream.listen((data) {\n      onReceiveBiliAccount(data.$1, data.$2);\n    });\n  }\n\n  void onReceiveFavorite(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        await DBService.instance.followBox.clear();\n      }\n      for (var item in jsonBody) {\n        var user = FollowUser.fromJson(item);\n        await DBService.instance.followBox.put(user.id, user);\n      }\n      SmartDialog.showToast('已同步关注用户列表');\n      EventBus.instance.emit(Constant.kUpdateFollow, 0);\n      SmartDialog.showToast(\"已同步关注列表\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveHistory(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        await DBService.instance.historyBox.clear();\n      }\n      for (var item in jsonBody) {\n        var history = History.fromJson(item);\n        if (DBService.instance.historyBox.containsKey(history.id)) {\n          var old = DBService.instance.historyBox.get(history.id);\n          //如果本地的更新时间比较新，就不更新\n          if (old!.updateTime.isAfter(history.updateTime)) {\n            continue;\n          }\n        }\n        await DBService.instance.addOrUpdateHistory(history);\n      }\n      SmartDialog.showToast('已同步历史记录');\n      EventBus.instance.emit(Constant.kUpdateHistory, 0);\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveShieldWord(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        AppSettingsController.instance.clearShieldList();\n      }\n      for (var item in jsonBody) {\n        // add to Hive\n        AppSettingsController.instance.addShieldList(item);\n      }\n      SmartDialog.showToast('已同步屏蔽词');\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveBiliAccount(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      var cookie = jsonBody['cookie'];\n      BiliBiliAccountService.instance.setCookie(cookie);\n      BiliBiliAccountService.instance.loadUserInfo();\n      SmartDialog.showToast('已同步哔哩哔哩账号');\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  Future<bool> showOverlayDialog() async {\n    var overlay = await Utils.showAlertDialog(\n      \"是否覆盖远端数据？\",\n      title: \"数据覆盖\",\n      confirm: \"覆盖\",\n      cancel: \"不覆盖\",\n    );\n    return overlay;\n  }\n\n  void syncFollow() async {\n    try {\n      if (roomUsers.length <= 1) {\n        SmartDialog.showToast(\"无设备连接\");\n        return;\n      }\n\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"发送中...\");\n      var users = DBService.instance.getFollowList();\n      var data = json.encode(users.map((e) => e.toJson()).toList());\n\n      var resp = await signalR.sendContent(\n        roomName: currentRoomId.value,\n        action: \"SendFavorite\",\n        overlay: overlay,\n        content: data,\n      );\n      if (resp.isSuccess) {\n        SmartDialog.showToast(\"已发送关注列表\");\n      } else {\n        SmartDialog.showToast(\"发送失败:${resp.message}\");\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"发送失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncHistory() async {\n    try {\n      if (roomUsers.length <= 1) {\n        SmartDialog.showToast(\"无设备连接\");\n        return;\n      }\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"发送中...\");\n      var histores = DBService.instance.getHistories();\n      var data = json.encode(histores.map((e) => e.toJson()).toList());\n      var resp = await signalR.sendContent(\n        roomName: currentRoomId.value,\n        action: \"SendHistory\",\n        overlay: overlay,\n        content: data,\n      );\n      if (resp.isSuccess) {\n        SmartDialog.showToast(\"已发送历史记录\");\n      } else {\n        SmartDialog.showToast(\"发送失败:${resp.message}\");\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"发送失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncBlockedWord() async {\n    try {\n      if (roomUsers.length <= 1) {\n        SmartDialog.showToast(\"无设备连接\");\n        return;\n      }\n      var overlay = await showOverlayDialog();\n      SmartDialog.showLoading(msg: \"发送中...\");\n      var shieldList = AppSettingsController.instance.shieldList;\n      var data = json.encode(shieldList.toList());\n\n      var resp = await signalR.sendContent(\n        roomName: currentRoomId.value,\n        action: \"SendShieldWord\",\n        overlay: overlay,\n        content: data,\n      );\n      if (resp.isSuccess) {\n        SmartDialog.showToast(\"已发送屏蔽词\");\n      } else {\n        SmartDialog.showToast(\"发送失败:${resp.message}\");\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"发送失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void syncBiliAccount() async {\n    try {\n      if (roomUsers.length <= 1) {\n        SmartDialog.showToast(\"无设备连接\");\n        return;\n      }\n      if (!BiliBiliAccountService.instance.logined.value) {\n        SmartDialog.showToast(\"未登录哔哩哔哩\");\n        return;\n      }\n      SmartDialog.showLoading(msg: \"发送中...\");\n\n      var resp = await signalR.sendContent(\n        roomName: currentRoomId.value,\n        action: \"SendBiliAccount\",\n        overlay: true,\n        content: json.encode({\n          \"cookie\": BiliBiliAccountService.instance.cookie,\n        }),\n      );\n      if (resp.isSuccess) {\n        SmartDialog.showToast(\"已发送哔哩哔哩账号\");\n      } else {\n        SmartDialog.showToast(\"发送失败:${resp.message}\");\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    } finally {\n      SmartDialog.dismiss();\n    }\n  }\n\n  void showQRInfo() {\n    Utils.showBottomSheet(\n      title: \"房间信息\",\n      child: Column(\n        children: [\n          QrImageView(\n            data: currentRoomId.value,\n            version: QrVersions.auto,\n            backgroundColor: Colors.white,\n            padding: AppStyle.edgeInsetsA12,\n            size: 200,\n          ),\n          AppStyle.vGap24,\n          Text(\n            currentRoomId.value,\n            textAlign: TextAlign.center,\n            style: Get.textTheme.titleLarge,\n          ),\n          const Text(\n            \"请使用其他Simple Live客户端扫描上方二维码\\n建立连接后可选择需要同步的数据\",\n            textAlign: TextAlign.center,\n          ),\n        ],\n      ),\n    );\n  }\n\n  @override\n  void onClose() {\n    _timer?.cancel();\n    _roomDestroyedSubscription?.cancel();\n    _roomUserUpdatedSubscription?.cancel();\n    _onFavoriteSubscription?.cancel();\n    _onHistorySubscription?.cancel();\n    _onShieldWordSubscription?.cancel();\n    _onBiliAccountSubscription?.cancel();\n    signalR.dispose();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/remote_sync/room/remote_sync_room_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_controller.dart';\nimport 'package:simple_live_app/services/signalr_service.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass RemoteSyncRoomPage extends GetView<RemoteSyncRoomController> {\n  const RemoteSyncRoomPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"数据同步\"),\n        actions: [\n          Padding(\n            padding: AppStyle.edgeInsetsH12,\n            child: StreamBuilder<SignalRConnectionState>(\n              stream: controller.signalR.stateStream,\n              builder: (context, snapshot) {\n                if (snapshot.hasData) {\n                  switch (snapshot.data) {\n                    case SignalRConnectionState.connected:\n                      return Row(\n                        children: [\n                          Container(\n                            width: 8,\n                            height: 8,\n                            decoration: const BoxDecoration(\n                              color: Colors.green,\n                              shape: BoxShape.circle,\n                            ),\n                          ),\n                          AppStyle.hGap8,\n                          const Text(\n                            '已连接',\n                            style: TextStyle(\n                              fontSize: 14,\n                            ),\n                          ),\n                        ],\n                      );\n                    case SignalRConnectionState.disconnected:\n                      return Row(\n                        children: [\n                          Container(\n                            width: 8,\n                            height: 8,\n                            decoration: const BoxDecoration(\n                              color: Colors.red,\n                              shape: BoxShape.circle,\n                            ),\n                          ),\n                          AppStyle.hGap8,\n                          const Text(\n                            '断开连接',\n                            style: TextStyle(\n                              fontSize: 14,\n                            ),\n                          ),\n                        ],\n                      );\n                    default:\n                      return const Row(\n                        children: [\n                          SizedBox(\n                            width: 16,\n                            height: 16,\n                            child: CircularProgressIndicator(\n                              strokeWidth: 2,\n                            ),\n                          ),\n                          Text(\n                            '连接中',\n                            style: TextStyle(\n                              fontSize: 14,\n                            ),\n                          ),\n                        ],\n                      );\n                  }\n                }\n                return const SizedBox();\n              },\n            ),\n          ),\n        ],\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n        children: [\n          Visibility(\n            visible: controller.roomId.isEmpty,\n            child: SettingsCard(\n              child: ListTile(\n                visualDensity: VisualDensity.compact,\n                leading: const Icon(Remix.timer_line),\n                title: Obx(\n                  () => Text(\n                    \"${controller.countDown.value}秒后房间将会自动关闭\",\n                    style: const TextStyle(fontSize: 14),\n                  ),\n                ),\n              ),\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12,\n            child: Text(\n              \"房间号\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => ListTile(\n                contentPadding: AppStyle.edgeInsetsL12,\n                title: SelectableText(\n                  controller.currentRoomId.value,\n                  style: Theme.of(context).textTheme.titleLarge,\n                ),\n                trailing: Row(\n                  crossAxisAlignment: CrossAxisAlignment.center,\n                  mainAxisSize: MainAxisSize.min,\n                  children: [\n                    IconButton(\n                      icon: const Icon(\n                        Icons.copy,\n                        size: 20,\n                      ),\n                      onPressed: () {\n                        Utils.copyToClipboard(controller.currentRoomId.value);\n                      },\n                    ),\n                    IconButton(\n                      icon: const Icon(\n                        Icons.qr_code,\n                        size: 20,\n                      ),\n                      onPressed: () {\n                        controller.showQRInfo();\n                      },\n                    ),\n                    AppStyle.hGap4,\n                  ],\n                ),\n              ),\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 12),\n            child: Text(\n              \"同步数据至其他设备\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              mainAxisSize: MainAxisSize.min,\n              children: [\n                ListTile(\n                  leading: const Icon(Remix.heart_line),\n                  title: const Text(\"发送关注列表\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncFollow();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Icons.history),\n                  title: const Text(\"发送观看记录\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncHistory();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Remix.shield_keyhole_line),\n                  title: const Text(\"发送弹幕屏蔽词\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncBlockedWord();\n                  },\n                ),\n                AppStyle.divider,\n                ListTile(\n                  leading: const Icon(Remix.account_circle_line),\n                  title: const Text(\"发送哔哩哔哩账号\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    controller.syncBiliAccount();\n                  },\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 12),\n            child: Text(\n              \"已连接设备\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Obx(\n              () => ListView.separated(\n                padding: EdgeInsets.zero,\n                itemCount: controller.roomUsers.length,\n                shrinkWrap: true,\n                separatorBuilder: (context, index) => AppStyle.divider,\n                physics: const NeverScrollableScrollPhysics(),\n                itemBuilder: (BuildContext context, int index) {\n                  var user = controller.roomUsers[index];\n                  return ListTile(\n                    visualDensity: VisualDensity.compact,\n                    leading: SizedBox(\n                      width: 48,\n                      height: 48,\n                      child: Center(\n                        child: buildIcon(user.platform),\n                      ),\n                    ),\n                    title: Text.rich(\n                      TextSpan(\n                        text: user.shortId,\n                        style: const TextStyle(fontSize: 16),\n                        children: user.isCreator!\n                            ? [\n                                WidgetSpan(\n                                  child: Container(\n                                    margin: AppStyle.edgeInsetsL4,\n                                    padding: AppStyle.edgeInsetsH4,\n                                    decoration: BoxDecoration(\n                                      border: Border.all(color: Colors.blue),\n                                      borderRadius: BorderRadius.circular(4),\n                                    ),\n                                    child: const Text(\n                                      \"创建者\",\n                                      style: TextStyle(\n                                        color: Colors.blue,\n                                        fontSize: 12,\n                                      ),\n                                    ),\n                                  ),\n                                ),\n                              ]\n                            : null,\n                      ),\n                    ),\n                    subtitle: Text(\"${user.app} - v${user.version}\"),\n                    trailing: Visibility(\n                      visible: controller.signalR.hubConnection?.connectionId ==\n                          user.connectionId,\n                      child: const Text(\n                        \"本机\",\n                      ),\n                    ),\n                  );\n                },\n              ),\n            ),\n          )\n        ],\n      ),\n    );\n  }\n\n  Widget buildIcon(String platform) {\n    if (platform == \"android\") {\n      return const Icon(Remix.android_line);\n    } else if (platform == \"ios\") {\n      return const Icon(Remix.apple_line);\n    } else if (platform == \"tv\") {\n      return const Icon(Remix.tv_2_line);\n    } else if (platform == \"windows\") {\n      return const Icon(Remix.microsoft_fill);\n    } else if (platform == \"xbox\") {\n      return const Icon(Remix.xbox_line);\n    } else if (platform == \"macos\") {\n      return const Icon(Remix.mac_line);\n    } else if (platform == \"linux\") {\n      return const Icon(Remix.ubuntu_line);\n    } else {\n      return const Icon(Remix.device_line);\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_config_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart';\nimport 'package:simple_live_app/widgets/none_border_circular_textfield.dart';\n\nclass RemoteSyncWebDAVConfigPage extends StatefulWidget {\n  const RemoteSyncWebDAVConfigPage({super.key});\n\n  @override\n  State<RemoteSyncWebDAVConfigPage> createState() =>\n      _RemoteSyncWebDAVConfigPageState();\n}\n\nclass _RemoteSyncWebDAVConfigPageState\n    extends State<RemoteSyncWebDAVConfigPage> {\n  late TextEditingController _urlController;\n  late TextEditingController _userNameController;\n  late TextEditingController _passwordController;\n\n  @override\n  void initState() {\n    _urlController = TextEditingController();\n    _userNameController = TextEditingController();\n    _passwordController = TextEditingController();\n    super.initState();\n  }\n\n  @override\n  void dispose() {\n    _urlController.dispose();\n    _userNameController.dispose();\n    _passwordController.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"WebDAV账号配置\"),\n        centerTitle: true,\n        actions: [\n          IconButton(\n            icon: const Icon(Icons.help_outline),\n            onPressed: () {\n              Utils.showInformationHelpDialog(\n                content: [\n                  const Text(\"此功能可以将您的数据备份到 WebDAV 服务器中或者进行数据恢复.\\n\"),\n                  const Text(\n                      \"WebDAV 服务器地址请以 http:// 或 https:// 开头，如坚果云(点击复制)：\"),\n                  Padding(\n                    padding: const EdgeInsets.symmetric(vertical: 16),\n                    child: InkWell(\n                      onTap: () {\n                        Clipboard.setData(const ClipboardData(\n                            text: \"https://dav.jianguoyun.com/dav/\"));\n                        SmartDialog.showToast(\"复制成功\");\n                      },\n                      child: const Text(\"https://dav.jianguoyun.com/dav/\"),\n                    ),\n                  ),\n                ],\n              );\n            },\n          ),\n        ],\n      ),\n      body: GetX<RemoteSyncWebDAVController>(\n        builder: (controller) {\n          return SingleChildScrollView(\n            child: Padding(\n              padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n              child: Column(\n                mainAxisAlignment: MainAxisAlignment.center,\n                children: [\n                  NoneBorderCircularTextField(\n                    editingController: _urlController,\n                    labelText: \"WebDAV服务器地址\",\n                    hintText: \"请以http:// 或 http:// 开头\",\n                    prefixIcon: const Icon(Icons.public),\n                    trailing: InkWell(\n                      child: const Icon(\n                        Icons.cancel,\n                        size: 20,\n                      ),\n                      onTap: () => _urlController.clear(),\n                    ),\n                  ),\n                  NoneBorderCircularTextField(\n                    editingController: _userNameController,\n                    labelText: \"账号\",\n                    prefixIcon: const Icon(Icons.account_circle),\n                    trailing: InkWell(\n                        child: const Icon(\n                          Icons.cancel,\n                          size: 20,\n                        ),\n                        onTap: () => _userNameController.clear()),\n                  ),\n                  NoneBorderCircularTextField(\n                    editingController: _passwordController,\n                    labelText: \"密码\",\n                    prefixIcon: const Icon(Icons.lock),\n                    obscureText: controller.passwordVisible.value,\n                    trailing: Row(\n                      mainAxisSize: MainAxisSize.min,\n                      children: [\n                        InkWell(\n                          child: const Icon(\n                            Icons.cancel,\n                            size: 20,\n                          ),\n                          onTap: () => _passwordController.clear(),\n                        ),\n                        AppStyle.hGap12,\n                        InkWell(\n                          child: controller.passwordVisible.value\n                              ? const Icon(Icons.visibility_off)\n                              : const Icon(Icons.visibility),\n                          onTap: () {\n                            controller.changePasswordVisible();\n                          },\n                        ),\n                      ],\n                    ),\n                  ),\n                  Padding(\n                    padding: const EdgeInsets.only(top: 5, bottom: 15),\n                    child: MaterialButton(\n                      minWidth: double.infinity,\n                      color: Theme.of(context).primaryColor,\n                      focusElevation: 0,\n                      elevation: 0,\n                      highlightElevation: 4,\n                      height: 40,\n                      shape: const RoundedRectangleBorder(\n                        borderRadius: BorderRadius.all(Radius.circular(8.0)),\n                      ),\n                      child: const Text(\n                        \"登录\",\n                        style: TextStyle(color: Colors.white),\n                      ),\n                      onPressed: () {\n                        controller.doWebDAVLogin(\n                          _urlController.text,\n                          _userNameController.text,\n                          _passwordController.text,\n                        );\n                      },\n                    ),\n                  )\n                ],\n              ),\n            ),\n          );\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\nimport 'dart:isolate';\nimport 'dart:typed_data';\n\nimport 'package:archive/archive.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:path/path.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/archive.dart';\nimport 'package:simple_live_app/app/utils/document.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/requests/webdav_client.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/douyin_account_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\nimport 'package:simple_live_app/services/migration_service.dart';\n\nclass RemoteSyncWebDAVController extends BaseController {\n  // ui\n  var passwordVisible = true.obs;\n\n  // ui-用户选择是否同步\n  var isSyncFollows = true.obs;\n  var isSyncHistories = true.obs;\n  var isSyncBlockWord = true.obs;\n  var isSyncAccount = true.obs;\n  var isSyncSetting = true.obs;\n\n  late DAVClient davClient;\n  var user = \"--\".obs;\n  var lastRecoverTime = \"--\".obs;\n  var lastUploadTime = \"--\".obs;\n  var uri = \"\";\n  var password = \"\";\n  var webDavBackupDirectory = \"/simple_live_app\".obs;\n\n  final _userFollowJsonName = 'SimpleLive_follows.json';\n  final _userHistoriesJsonName = 'SimpleLive_histories.json';\n  final _userBlockedWordJsonName = 'SimpleLive_blocked_word.json';\n  final _userAccountJsonName = 'SimpleLive_bilibili_account.json';\n  final _userTagsJsonName = 'SimpleLive_Tags.json';\n  final _userSettingsJsonName = 'SimpleLive_Settings.json';\n\n  @override\n  void onInit() {\n    doWebDAVInit();\n    super.onInit();\n  }\n\n  void setWebDavBackupDirectory({required String newDirectory}) {\n    if (newDirectory == webDavBackupDirectory.value) {\n      return;\n    }\n    // 防呆\n    final filePathCheck = RegExp(r'^/[^/]+$');\n    if (!filePathCheck.hasMatch(newDirectory)) {\n      SmartDialog.showToast(\"请输入正确的文件路径\");\n      return;\n    }\n    webDavBackupDirectory.value = newDirectory;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kWebDAVDirectory,\n      webDavBackupDirectory.value,\n    );\n    // 重定义/应该单例化\n    davClient = DAVClient(\n      uri,\n      user.value,\n      password,\n      webDAVDirectory: webDavBackupDirectory.value,\n    );\n  }\n\n  // webDAV 逻辑\n  // 初始化webDAV\n  void doWebDAVInit() {\n    uri = LocalStorageService.instance\n        .getValue(LocalStorageService.kWebDAVUri, \"\");\n    if (uri.isEmpty) {\n      notLogin.value = true;\n    } else {\n      user.value = LocalStorageService.instance\n          .getValue(LocalStorageService.kWebDAVUser, \"\");\n      password = LocalStorageService.instance\n          .getValue(LocalStorageService.kWebDAVPassword, \"\");\n      webDavBackupDirectory.value = LocalStorageService.instance.getValue(\n        LocalStorageService.kWebDAVDirectory,\n        \"/simple_live_app\",\n      );\n      davClient = DAVClient(\n        uri,\n        user.value,\n        password,\n        webDAVDirectory: webDavBackupDirectory.value,\n      );\n      // 从未同步过默认为最新数据\n      lastRecoverTime.value = Utils.parseTime(\n        DateTime.fromMillisecondsSinceEpoch(\n          LocalStorageService.instance.getValue(\n            LocalStorageService.kWebDAVLastRecoverTime,\n            DateTime.now().millisecondsSinceEpoch,\n          ),\n        ),\n      );\n      lastUploadTime.value = Utils.parseTime(\n        DateTime.fromMillisecondsSinceEpoch(\n          LocalStorageService.instance.getValue(\n            LocalStorageService.kWebDAVLastUploadTime,\n            DateTime.now().millisecondsSinceEpoch,\n          ),\n        ),\n      );\n      checkIsLogin();\n    }\n  }\n\n  // 检查webDAV登录状态\n  Future<void> checkIsLogin() async {\n    try {\n      // 返回登录结果\n      bool value = await davClient.pingCompleter.future;\n      notLogin.value = !value;\n    } catch (e) {\n      Log.e(\"$e\", StackTrace.current);\n      notLogin.value = true;\n    }\n  }\n\n  // WebDAV登录\n  void doWebDAVLogin(\n      String webDAVUri, String webDAVUser, String webDAVPassword) async {\n    // 确认登录\n    davClient = DAVClient(webDAVUri, webDAVUser, webDAVPassword);\n    await checkIsLogin();\n    if (!notLogin.value) {\n      // 保存到本地\n      LocalStorageService.instance\n          .setValue(LocalStorageService.kWebDAVUri, webDAVUri);\n      LocalStorageService.instance\n          .setValue(LocalStorageService.kWebDAVUser, webDAVUser);\n      user.value = webDAVUser;\n      LocalStorageService.instance\n          .setValue(LocalStorageService.kWebDAVPassword, webDAVPassword);\n      Get.back();\n      SmartDialog.showToast(\"登录成功！\");\n    } else {\n      SmartDialog.showToast(\"WebDAV账号密码验证失败，请重新输入！\");\n    }\n  }\n\n  // WebDAV登出\n  @override\n  Future<void> onLogout() async {\n    var result = await Utils.showAlertDialog(\"确定要登出WebDAV账号？\", title: \"退出登录\");\n    if (result) {\n      // 清除本地账号数据\n      LocalStorageService.instance.setValue(LocalStorageService.kWebDAVUri, \"\");\n      LocalStorageService.instance\n          .setValue(LocalStorageService.kWebDAVUser, \"\");\n      LocalStorageService.instance\n          .setValue(LocalStorageService.kWebDAVPassword, \"\");\n      notLogin.value = true;\n    }\n  }\n\n  // webDAV上传到云端\n  Future<void> doWebDAVUpload() async {\n    SmartDialog.showLoading(msg: \"正在上传到云端\");\n    _backupData().then((value) async {\n      SmartDialog.dismiss();\n      if (value.isNotEmpty) {\n        var result = await davClient.backup(Uint8List.fromList(value));\n        if (result) {\n          SmartDialog.showToast(\"上传成功\");\n          DateTime uploadTime = DateTime.now();\n          lastUploadTime.value = Utils.parseTime(uploadTime);\n          LocalStorageService.instance.setValue(\n              LocalStorageService.kWebDAVLastUploadTime,\n              uploadTime.millisecondsSinceEpoch);\n        } else {\n          Log.e(\"备份失败\", StackTrace.current);\n          SmartDialog.showToast(\"上传失败\");\n        }\n      } else {\n        SmartDialog.showToast(\"上传失败\");\n      }\n    });\n  }\n\n  // 备份所有数据\n  Future<List<int>> _backupData() async {\n    final archive = Archive();\n    List<int> zipBytes = [];\n    // 获取本地备份路径\n    var dir = (await getApplicationSupportDirectory()).path;\n    var profile = Directory(join(dir, 'backup'));\n    if (!profile.existsSync()) {\n      profile.createSync();\n    }\n    try {\n      // archive.add(filepath, data_map) 会导致文件损坏\n      // follows\n      var userFollowList = DBService.instance.getFollowList();\n      var dataFollowsMap = {\n        'data': userFollowList.map((e) => e.toJson()).toList()\n      };\n      final userFollowJsonFile = File(join(profile.path, _userFollowJsonName));\n      await userFollowJsonFile.writeAsString(jsonEncode(dataFollowsMap));\n      // 用户自定义标签\n      var userTagsList = DBService.instance.getFollowTagList();\n      var dataTagsMap = {'data': userTagsList.map((e) => e.toJson()).toList()};\n      var userTagsJsonFile = File(join(profile.path, _userTagsJsonName));\n      await userTagsJsonFile.writeAsString(jsonEncode(dataTagsMap));\n      // histories\n      var userHistoriesList = DBService.instance.getHistories();\n      var dataHistoriesMap = {\n        'data': userHistoriesList.map((e) => e.toJson()).toList()\n      };\n      final userHistoriesJsonFile =\n          File(join(profile.path, _userHistoriesJsonName));\n      await userHistoriesJsonFile.writeAsString(jsonEncode(dataHistoriesMap));\n\n      // blocked_word\n      var userShieldList = AppSettingsController.instance.shieldList;\n      var dataShieldListMap = {'data': userShieldList.toList()};\n      final userBlockedWordJsonFile =\n          File(join(profile.path, _userBlockedWordJsonName));\n      await userBlockedWordJsonFile\n          .writeAsString(jsonEncode(dataShieldListMap));\n\n      // bilibili_account\n      var userAccountCookieMap = {\n        'data': {\n          'cookie': BiliBiliAccountService.instance.cookie,\n          'douyin_cookie': DouyinAccountService.instance.cookie\n        }\n      };\n      final accountJsonFile = File(join(profile.path, _userAccountJsonName));\n      await accountJsonFile.writeAsString(jsonEncode(userAccountCookieMap));\n      await userTagsJsonFile.writeAsString(jsonEncode(dataTagsMap));\n      // 全量备份用户设置，为修改包名无痛迁移数据做准备\n      // v1.8.3 修改为按平台备份/恢复用户设置\n      var settingList = LocalStorageService.instance.settingsBox.toMap();\n      settingList.remove(LocalStorageService.kHiveDbVer);\n      var dataSettingListMap = {\n        \"data\": {\n          LocalStorageService.kHiveDbVer: AppSettingsController.instance.dbVer,\n          Platform.operatingSystem: settingList,\n        },\n      };\n      final settingJsonFile = File(join(profile.path, _userSettingsJsonName));\n      await settingJsonFile.writeAsString(jsonEncode(dataSettingListMap));\n\n      // 遍历profile路径下的所有文件压缩\n      archive.addDirectoryToArchive(profile.path, profile.path);\n      final zipEncoder = ZipEncoder();\n      zipBytes = zipEncoder.encode(archive);\n      profile.clearSync();\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"备份失败：$e\");\n    }\n    return zipBytes;\n  }\n\n  // webDAV恢复到本地\n  void doWebDAVRecovery() async {\n    SmartDialog.showLoading(msg: \"正在恢复到本地\");\n    List<int> data;\n    try{\n      data = await davClient.recovery();\n    }catch(e,s){\n      Log.e(\"WebDAV恢复失败：$e\", s);\n      SmartDialog.dismiss();\n      SmartDialog.showToast('同步失败');\n      return;\n    }\n    final archive = await Isolate.run<Archive>(() {\n      final zipDecoder = ZipDecoder();\n      return zipDecoder.decodeBytes(data);\n    });\n    for (ArchiveFile file in archive) {\n      await _recovery(file);\n    }\n    // 旧版本备份需要迁移\n    MigrationService.migrateDataByVersion();\n    SmartDialog.dismiss();\n    SmartDialog.showToast('同步完成');\n    DateTime recoverTime = DateTime.now();\n    lastRecoverTime.value = Utils.parseTime(recoverTime);\n    LocalStorageService.instance.setValue(\n        LocalStorageService.kWebDAVLastRecoverTime,\n        recoverTime.millisecondsSinceEpoch);\n  }\n\n  // todo: 后续迁出实现无感同步\n  Future<void> _recovery(ArchiveFile file) async {\n    if (file.isFile && file.name.endsWith('.json')) {\n      var jsonString = utf8.decode(file.content);\n      var jsonData = json.decode(jsonString)['data'];\n      // 同步follows\n      if (file.name == _userFollowJsonName && isSyncFollows.value) {\n        // 修改为多端一致\n        try {\n          // 清空本地关注列表\n          await DBService.instance.followBox.clear();\n          for (var item in jsonData) {\n            var user = FollowUser.fromJson(item);\n            await DBService.instance.followBox.put(user.id, user);\n          }\n          Log.i('已同步关注用户列表');\n        } catch (e) {\n          Log.e('同步关注用户列表失败: $e', StackTrace.current);\n        }\n      } else if (file.name == _userHistoriesJsonName && isSyncHistories.value) {\n        try {\n          for (var item in jsonData) {\n            var history = History.fromJson(item);\n            // 完全同步机制\n            await DBService.instance.addOrUpdateHistory(history);\n          }\n          Log.i('已同步用户观看历史记录');\n        } catch (e) {\n          Log.e('同步用户观看历史记录失败: $e', StackTrace.current);\n        }\n      } else if (file.name == _userBlockedWordJsonName &&\n          isSyncBlockWord.value) {\n        try {\n          for (var keyword in jsonData) {\n            AppSettingsController.instance.addShieldList(keyword.trim());\n          }\n          Log.i('已同步用户屏蔽词');\n        } catch (e) {\n          Log.e('同步用户屏蔽词失败:$e', StackTrace.current);\n        }\n      } else if (file.name == _userAccountJsonName && isSyncAccount.value) {\n        try {\n          var biliCookie = jsonData['cookie'];\n          BiliBiliAccountService.instance.setCookie(biliCookie);\n          BiliBiliAccountService.instance.loadUserInfo();\n          var douyinCookie = jsonData['douyin_cookie'];\n          DouyinAccountService.instance.setCookie(douyinCookie);\n          DouyinAccountService.instance.loadUserInfo();\n          Log.i('已同步用户平台账号');\n        } catch (e) {\n          Log.e('同步用户平台账号失败：$e', StackTrace.current);\n        }\n      } else if (file.name == _userSettingsJsonName && isSyncSetting.value) {\n        try {\n          var platform = Platform.operatingSystem;\n          if ((jsonData as Map).containsKey(platform)) {\n            jsonDecode(jsonData[platform]).forEach(\n              (key, value) {\n                LocalStorageService.instance.setValue(key, value);\n              },\n            );\n          } else {\n            Log.i(\"缺少$platform对应平台用户设置备份\");\n          }\n          // 低于v1.8.5需要升级数据\n          LocalStorageService.instance.setValue(\n            LocalStorageService.kHiveDbVer,\n            (jsonData as Map).containsKey(LocalStorageService.kHiveDbVer)\n                ? jsonData[LocalStorageService.kHiveDbVer]\n                : \"10805\",\n          );\n          Log.i('已同步用户设置');\n        } catch (e) {\n          Log.e(\"同步用户设置失败：$e\", StackTrace.current);\n        }\n      } else if (file.name == _userTagsJsonName && isSyncFollows.value) {\n        try {\n          // 标签功能和关注具有依赖关系，必须同时同步\n          // 清空本地标签列表\n          await DBService.instance.clearFollowTag();\n          for (var item in jsonData) {\n            var tag = FollowUserTag.fromJson(item);\n            await DBService.instance.tagBox.put(tag.id, tag);\n            // 插入之后验证\n            var insertedTag = DBService.instance.tagBox.get(tag.id);\n            Log.i('Inserted tag: ${insertedTag?.tag}');\n          }\n          // 数据校准\n          await FollowService.instance.followUserAllDataCheck();\n          Log.i('已同步用户自定义标签');\n          // 确保tag同步完成后，更新关注列表\n          EventBus.instance.emit(Constant.kUpdateFollow, 0);\n        } catch (e) {\n          Log.e('同步用户自定义标签失败:$e', StackTrace.current);\n        }\n      } else {\n        return;\n      }\n    } else {\n      Log.i('不是正确的文件名');\n    }\n  }\n\n  // ui控制--密码可见控制\n  void changePasswordVisible() {\n    passwordVisible.value = !passwordVisible.value;\n  }\n\n  void changeIsSyncFollows() {\n    isSyncFollows.value = !isSyncFollows.value;\n  }\n\n  void changeIsSyncHistories() {\n    isSyncHistories.value = !isSyncHistories.value;\n  }\n\n  void changeIsSyncBlockWord() {\n    isSyncBlockWord.value = !isSyncBlockWord.value;\n  }\n\n  void changeIsSyncAccount() {\n    isSyncAccount.value = !isSyncAccount.value;\n  }\n\n  void changeIsSyncSetting() {\n    isSyncSetting.value = !isSyncSetting.value;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass RemoteSyncWebDAVPage extends GetView<RemoteSyncWebDAVController> {\n  const RemoteSyncWebDAVPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"WebDAV同步\"),\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          SettingsCard(\n            child: Obx(\n              () => Column(\n                children: controller.notLogin.value\n                    ? [\n                        ListTile(\n                          title: const Text(\"点击登录\"),\n                          leading: const Icon(Icons.login),\n                          subtitle: const Text(\"登录后可以同步您的所有数据\"),\n                          trailing: const Icon(Icons.chevron_right),\n                          onTap: () {\n                            Get.toNamed(RoutePath.kRemoteSyncWebDavConfig);\n                          },\n                        ),\n                      ]\n                    : [\n                        ListTile(\n                          title: const Text(\"已登录\"),\n                          leading: const Icon(Icons.cloud_circle_outlined),\n                          subtitle: Text(controller.user.value),\n                          trailing: const Icon(Icons.logout),\n                          onTap: () {\n                            controller.onLogout();\n                          },\n                        ),\n                        AppStyle.divider,\n                        Obx(\n                          () => ListTile(\n                            title: const Text(\"云端备份目录\"),\n                            leading: const Icon(Icons.drive_folder_upload),\n                            subtitle:\n                                Text(controller.webDavBackupDirectory.value),\n                            trailing: const Icon(Icons.chevron_right),\n                            onTap: _showEditBackupDirectory,\n                          ),\n                        ),\n                        AppStyle.divider,\n                        ListTile(\n                          title: const Text(\"上传到云端\"),\n                          subtitle: Text(\"上次上传：${controller.lastUploadTime}\"),\n                          leading: const Icon(Icons.cloud_upload_outlined),\n                          trailing: const Icon(Icons.chevron_right),\n                          onTap: () {\n                            controller.doWebDAVUpload();\n                          },\n                        ),\n                        AppStyle.divider,\n                        ListTile(\n                          title: const Text(\"恢复到本地\"),\n                          subtitle: Text(\"上次恢复：${controller.lastRecoverTime}\"),\n                          leading: const Icon(Icons.cloud_download_outlined),\n                          trailing: Row(\n                            mainAxisSize: MainAxisSize.min,\n                            children: [\n                              IconButton(\n                                icon: const Icon(Icons.settings),\n                                onPressed: showSetting,\n                              ),\n                              const Icon(Icons.chevron_right),\n                            ],\n                          ),\n                          onTap: () {\n                            controller.doWebDAVRecovery();\n                          },\n                          onLongPress: showSetting,\n                        ),\n                      ],\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void showSetting() {\n    Utils.showBottomSheet(\n      title: '同步选项',\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: [\n          AppStyle.divider,\n          Obx(\n            () => CheckboxListTile(\n              secondary: const Icon(Remix.heart_line),\n              title: const Text(\"同步关注列表\"),\n              value: controller.isSyncFollows.value,\n              controlAffinity: ListTileControlAffinity.trailing,\n              onChanged: (value) => controller.changeIsSyncFollows(),\n            ),\n          ),\n          AppStyle.divider,\n          Obx(\n            () => CheckboxListTile(\n              secondary: const Icon(Icons.history),\n              title: const Text(\"同步播放历史记录\"),\n              value: controller.isSyncHistories.value,\n              controlAffinity: ListTileControlAffinity.trailing,\n              onChanged: (value) => controller.changeIsSyncHistories(),\n            ),\n          ),\n          AppStyle.divider,\n          Obx(\n            () => CheckboxListTile(\n              secondary: const Icon(Remix.shield_keyhole_line),\n              title: const Text(\"同步屏蔽字\"),\n              value: controller.isSyncBlockWord.value,\n              controlAffinity: ListTileControlAffinity.trailing,\n              onChanged: (value) => controller.changeIsSyncBlockWord(),\n            ),\n          ),\n          AppStyle.divider,\n          Obx(\n            () => CheckboxListTile(\n              secondary: const Icon(Remix.account_circle_line),\n              title: const Text(\"同步用户平台账号\"),\n              value: controller.isSyncAccount.value,\n              controlAffinity: ListTileControlAffinity.trailing,\n              onChanged: (value) => controller.changeIsSyncAccount(),\n            ),\n          ),\n          AppStyle.divider,\n          Obx(\n            () => CheckboxListTile(\n              secondary: const Icon(Remix.user_settings_line),\n              title: const Text(\"同步用户设置\"),\n              value: controller.isSyncSetting.value,\n              controlAffinity: ListTileControlAffinity.trailing,\n              onChanged: (value) => controller.changeIsSyncSetting(),\n            ),\n          ),\n          //todo: 启动应用时自动同步数据\n        ],\n      ),\n    );\n  }\n\n  void _showEditBackupDirectory() async {\n    var directory = await Utils.showEditTextDialog(\n      controller.webDavBackupDirectory.value,\n      title: \"修改远程备份文件夹\",\n    );\n    if (directory == null || directory.isEmpty) {\n      return;\n    }\n    controller.setWebDavBackupDirectory(newDirectory: directory);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/modules/sync/sync_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/widgets/settings/settings_card.dart';\n\nclass SyncPage extends StatelessWidget {\n  const SyncPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text(\"数据同步\"),\n        actions: [\n          Visibility(\n            visible: GetPlatform.isAndroid || GetPlatform.isIOS,\n            child: TextButton.icon(\n              onPressed: () async {\n                var result = await Get.toNamed(RoutePath.kSyncScan);\n                if (result == null || result.isEmpty) {\n                  return;\n                }\n                if (result.length == 5) {\n                  Get.toNamed(RoutePath.kRemoteSyncRoom, arguments: result);\n                } else {\n                  Get.toNamed(RoutePath.kLocalSync, arguments: result);\n                }\n              },\n              icon: const Icon(Remix.qr_scan_line),\n              label: const Text(\"扫一扫\"),\n            ),\n          ),\n        ],\n      ),\n      body: ListView(\n        padding: AppStyle.edgeInsetsA12,\n        children: [\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 0),\n            child: Text(\n              \"远程同步\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              children: [\n                ListTile(\n                  title: const Text(\"WebDAV\"),\n                  leading: const Icon(Icons.cloud_upload_outlined),\n                  subtitle: const Text(\"通过WebDAV同步数据\"),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kRemoteSyncWebDav);\n                  },\n                ),\n              ],\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA12.copyWith(top: 24),\n            child: Text(\n              \"局域网同步\",\n              style: Get.textTheme.titleSmall,\n            ),\n          ),\n          SettingsCard(\n            child: Column(\n              children: [\n                ListTile(\n                  title: const Text(\"局域网同步\"),\n                  subtitle: const Text(\"在局域网内同步数据\"),\n                  leading: const Icon(Remix.device_line),\n                  trailing: const Icon(Icons.chevron_right),\n                  onTap: () {\n                    Get.toNamed(RoutePath.kLocalSync);\n                  },\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/common_request.dart",
    "content": "import 'dart:convert';\n\nimport 'package:simple_live_app/models/version_model.dart';\nimport 'package:simple_live_app/requests/http_client.dart';\n\n/// 通用的请求\nclass CommonRequest {\n  Future<VersionModel> checkUpdate() async {\n    try {\n      return await checkUpdateGitMirror();\n    } catch (e) {\n      return await checkUpdateJsDelivr();\n    }\n  }\n\n  /// 检查更新\n  Future<VersionModel> checkUpdateGitMirror() async {\n    var result = await HttpClient.instance.getJson(\n      \"https://raw.gitmirror.com/slotsun/dart_simple_live/master/assets/app_version.json\",\n      queryParameters: {\n        \"ts\": DateTime.now().millisecondsSinceEpoch,\n      },\n    );\n    if (result is Map) {\n      return VersionModel.fromJson(result as Map<String, dynamic>);\n    }\n    return VersionModel.fromJson(json.decode(result));\n  }\n\n  /// 检查更新\n  Future<VersionModel> checkUpdateJsDelivr() async {\n    var result = await HttpClient.instance.getJson(\n      \"https://cdn.jsdelivr.net/gh/slotsun/dart_simple_live@master/assets/app_version.json\",\n      queryParameters: {\n        \"ts\": DateTime.now().millisecondsSinceEpoch,\n      },\n    );\n    if (result is Map) {\n      return VersionModel.fromJson(result as Map<String, dynamic>);\n    }\n    return VersionModel.fromJson(json.decode(result));\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/custom_log_interceptor.dart",
    "content": "import 'package:dio/dio.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass CustomLogInterceptor extends Interceptor {\n  @override\n  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {\n    options.extra[\"ts\"] = DateTime.now().millisecondsSinceEpoch;\n\n    super.onRequest(options, handler);\n  }\n\n  @override\n  void onError(DioException err, ErrorInterceptorHandler handler) {\n    var time =\n        DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra[\"ts\"];\n    if (!kReleaseMode) {\n      Log.e('''【HTTP请求错误-${err.type}】 耗时:${time}ms\n${err.message}\n\nRequest Method：${err.requestOptions.method}\nResponse Code：${err.response?.statusCode}\nRequest URL：${err.requestOptions.uri}\nRequest Query：${err.requestOptions.queryParameters}\nRequest Data：${err.requestOptions.data}\nRequest Headers：${err.requestOptions.headers}\nResponse Headers：${err.response?.headers.map}\nResponse Data：${err.response?.data}''', err.stackTrace);\n    } else {\n      CoreLog.e('''[HTTP Error] [${err.type}] [Time:${time}ms]\n${err.message}\n\nRequest Method：${err.requestOptions.method}\nResponse Code：${err.response?.statusCode}\nRequest URL：${err.requestOptions.uri}\nRequest Query：${err.requestOptions.queryParameters}\nRequest Data：${err.requestOptions.data}\nRequest Headers：${_maskHeader(err.requestOptions.headers)}\nResponse Headers：${err.response?.headers.map}\nResponse Data：${err.response?.data}''', err.stackTrace);\n    }\n\n    super.onError(err, handler);\n  }\n\n  @override\n  void onResponse(Response response, ResponseInterceptorHandler handler) {\n    var time = DateTime.now().millisecondsSinceEpoch -\n        response.requestOptions.extra[\"ts\"];\n    if (!kReleaseMode) {\n      Log.i(\n        '''【HTTP请求响应】 耗时:${time}ms\nRequest Method：${response.requestOptions.method}\nRequest Code：${response.statusCode}\nRequest URL：${response.requestOptions.uri}\nRequest Query：${response.requestOptions.queryParameters}\nRequest Data：${response.requestOptions.data}\nRequest Headers：${response.requestOptions.headers}\nResponse Headers：${response.headers.map}\nResponse Data：${response.data}''',\n      );\n    } else {\n      CoreLog.i(\n        \"[HTTP Response] [time:${time}ms] [${response.statusCode}] ${response.requestOptions.uri}\",\n      );\n    }\n    super.onResponse(response, handler);\n  }\n\n  // Header脱敏\n  String _maskHeader(Map<String, dynamic> header) {\n    var result = <String, dynamic>{};\n    header.forEach((key, value) {\n      var k = key.toLowerCase();\n      if (k == \"cookie\" || k == \"authorization\") {\n        result[key] = \"******\";\n      } else {\n        result[key] = value;\n      }\n    });\n    return result.toString();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/http_client.dart",
    "content": "import 'dart:io';\n\nimport 'package:dio/dio.dart';\nimport 'package:simple_live_app/requests/custom_log_interceptor.dart';\nimport 'package:simple_live_app/requests/http_error.dart';\n\nclass HttpClient {\n  static HttpClient? _httpUtil;\n\n  static HttpClient get instance {\n    _httpUtil ??= HttpClient();\n    return _httpUtil!;\n  }\n\n  late Dio dio;\n  HttpClient() {\n    dio = Dio(\n      BaseOptions(\n        connectTimeout: const Duration(seconds: 20),\n        receiveTimeout: const Duration(seconds: 20),\n        sendTimeout: const Duration(seconds: 20),\n      ),\n    );\n    dio.interceptors.add(CustomLogInterceptor());\n  }\n\n  /// Get请求，返回String\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<String> getText(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.plain,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Get请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<dynamic> getJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Get请求，返回Response\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<Response<dynamic>> get(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Post请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [data] 内容\n  /// * [cancel] 任务取消Token\n  Future<dynamic> postJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    dynamic data,\n    Map<String, dynamic>? header,\n    bool formUrlEncoded = false,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      data ??= {};\n      var result = await dio.post(\n        url,\n        queryParameters: queryParameters,\n        data: data,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n          contentType:\n              formUrlEncoded ? Headers.formUrlEncodedContentType : null,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送POST请求失败\");\n      }\n    }\n  }\n\n  /// Head请求，返回Response\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<Response> head(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.head(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          headers: header,\n          receiveDataWhenStatusError: true,\n        ),\n        cancelToken: cancel,\n      );\n      return result;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        return e.response!;\n      } else {\n        throw HttpError(\"发送HEAD请求失败\");\n      }\n    }\n  }\n\n  /// DOWNLOAD 文件\n  /// * [url] 下载链接\n  /// * [savePath] 保存路径\n  /// * [header] 可选请求头\n  /// * [cancel] 任务取消Token\n  /// * [onProgress] 下载进度 0~1\n  Future<File> download(\n    String url,\n    String savePath, {\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n    Function(int value, int progress)? onReceiveProgress,\n  }) async {\n    header ??= {};\n    final tempPath = \"$savePath.part\";\n    final tempFile = File(tempPath);\n\n    try {\n      if (!await tempFile.exists()) {\n        await tempFile.create(recursive: true);\n      }\n      final response = await dio.download(\n        url,\n        tempPath,\n        cancelToken: cancel,\n        onReceiveProgress: onReceiveProgress,\n        options: Options(\n          headers: header,\n        ),\n      );\n\n      if (response.statusCode == 200 || response.statusCode == 206) {\n        // 下载完成重命名临时文件\n        return await tempFile.rename(savePath);\n      } else {\n        throw HttpError(\"下载失败\", statusCode: response.statusCode ?? 0);\n      }\n    } on DioException catch (e) {\n      if (CancelToken.isCancel(e)) {\n        throw HttpError(\"下载已取消\");\n      } else if (e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"下载请求失败\");\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/http_error.dart",
    "content": "class HttpError extends Error {\n  /// 错误码\n  final int statusCode;\n\n  /// 错误信息\n  final String message;\n\n  HttpError(\n    this.message, {\n    this.statusCode = 0,\n  });\n  @override\n  String toString() {\n    if (statusCode != 0) {\n      return statusCodeToString(statusCode);\n    }\n\n    return message;\n  }\n\n  String statusCodeToString(int statusCode) {\n    switch (statusCode) {\n      case 400:\n        return \"错误的请求(400)\";\n      case 401:\n        return \"无权限访问资源(401)\";\n      case 403:\n        return \"无权限访问资源(403)\";\n      case 404:\n        return \"服务器找不到请求的资源(404)\";\n      case 500:\n        return \"服务器出现错误(500)\";\n      case 502:\n        return \"服务器出现错误(502)\";\n      case 503:\n        return \"服务器出现错误(503)\";\n      default:\n        return \"连接服务器失败，请稍后再试($statusCode)\";\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/sync_client_request.dart",
    "content": "import 'package:simple_live_app/models/sync_client_info_model.dart';\nimport 'package:simple_live_app/requests/http_client.dart';\nimport 'package:simple_live_app/services/sync_service.dart';\n\nclass SyncClientRequest {\n  Future<SyncClientInfoModel> getClientInfo(SyncClinet client) async {\n    var url = \"http://${client.address}:${client.port}/info\";\n    var data = await HttpClient.instance.getJson(url);\n\n    return SyncClientInfoModel.fromJson(data);\n  }\n\n  Future<bool> syncFollow(\n    SyncClinet client,\n    dynamic body, {\n    bool overlay = false,\n  }) async {\n    var url = \"http://${client.address}:${client.port}/sync/follow\";\n    var data = await HttpClient.instance.postJson(\n      url,\n      data: body,\n      queryParameters: {\n        'overlay': overlay ? '1' : '0',\n      },\n    );\n\n    if (data[\"status\"]) {\n      return true;\n    } else {\n      throw data[\"message\"];\n    }\n  }\n\n  Future<bool> syncTag(\n    SyncClinet client,\n    dynamic body, {\n    bool overlay = false,\n  }) async {\n    var url = \"http://${client.address}:${client.port}/sync/tag\";\n    var data = await HttpClient.instance.postJson(\n      url,\n      data: body,\n      queryParameters: {\n        'overlay': overlay ? '1' : '0',\n      },\n    );\n\n    if (data[\"status\"]) {\n      return true;\n    } else {\n      throw data[\"message\"];\n    }\n  }\n\n  Future<bool> syncHistory(\n    SyncClinet client,\n    dynamic body, {\n    bool overlay = false,\n  }) async {\n    var url = \"http://${client.address}:${client.port}/sync/history\";\n    var data = await HttpClient.instance.postJson(\n      url,\n      data: body,\n      queryParameters: {\n        'overlay': overlay ? '1' : '0',\n      },\n    );\n\n    if (data[\"status\"]) {\n      return true;\n    } else {\n      throw data[\"message\"];\n    }\n  }\n\n  Future<bool> syncBlockedWord(\n    SyncClinet client,\n    dynamic body, {\n    bool overlay = false,\n  }) async {\n    var url = \"http://${client.address}:${client.port}/sync/blocked_word\";\n    var data = await HttpClient.instance.postJson(\n      url,\n      data: body,\n      queryParameters: {\n        'overlay': overlay ? '1' : '0',\n      },\n    );\n\n    if (data[\"status\"]) {\n      return true;\n    } else {\n      throw data[\"message\"];\n    }\n  }\n\n  Future<bool> syncBiliAccount(SyncClinet client, String cookie) async {\n    var url = \"http://${client.address}:${client.port}/sync/account/bilibili\";\n    var data = await HttpClient.instance.postJson(\n      url,\n      data: {\n        \"cookie\": cookie,\n      },\n    );\n\n    if (data[\"status\"]) {\n      return true;\n    } else {\n      throw data[\"message\"];\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/requests/webdav_client.dart",
    "content": "import 'dart:async';\nimport 'dart:typed_data';\n\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:webdav_client/webdav_client.dart';\n\nclass DAVClient {\n  late Client client;\n  Completer<bool> pingCompleter = Completer();\n  // 强制统一\n  String root = \"/simple_live_app\";\n\n  DAVClient(String webDAVUri, String webDAVUser, String webDAVPassword,\n      {String webDAVDirectory = \"/simple_live_app\"}) {\n    client = newClient(\n      webDAVUri,\n      user: webDAVUser,\n      password: webDAVPassword,\n    );\n    client.setHeaders(\n      {\n        'accept-charset': 'utf-8',\n        'Content-Type': 'text/xml',\n      },\n    );\n    client.setConnectTimeout(8000);\n    client.setSendTimeout(8000);\n    client.setReceiveTimeout(8000);\n    pingCompleter.complete(_ping());\n    root = webDAVDirectory;\n  }\n\n  Future<bool> _ping() async {\n    try {\n      await client.ping();\n      return true;\n    } catch (_) {\n      return false;\n    }\n  }\n\n  String get backupFile => \"$root/backup.zip\";\n\n  Future<bool> backup(Uint8List data) async {\n    try {\n      await client.mkdir(root);\n      await client.write(backupFile, data);\n    } catch (e, s) {\n      Log.e(\"WebDAV上传失败: $e\", s);\n      return false;\n    }\n    return true;\n  }\n\n  Future<List<int>> recovery() async {\n    await client.mkdir(root);\n    final data = await client.read(backupFile);\n    return data;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/routes/app_analytics_observer.dart",
    "content": "﻿import 'package:firebase_analytics/firebase_analytics.dart';\nimport 'package:flutter/cupertino.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\n\nclass AppAnalyticsObserver extends NavigatorObserver {\n\n  static AppAnalyticsObserver get observer => AppAnalyticsObserver();\n\n  void _log(Route<dynamic>? route) {\n    if (route == null) return;\n\n    if (!AppSettingsController.instance.firebaseEnable.value) {\n      return;\n    }\n\n    final name = route.settings.name;\n    if (name == null) return;\n\n    FirebaseAnalytics.instance.logScreenView(\n      screenName: name,\n      screenClass: name,\n    );\n  }\n\n  @override\n  void didPush(Route route, Route? previousRoute) {\n    _log(route);\n    super.didPush(route, previousRoute);\n  }\n\n  @override\n  void didPop(Route route, Route? previousRoute) {\n    _log(previousRoute);\n    super.didPop(route, previousRoute);\n  }\n\n  @override\n  void didReplace({Route? newRoute, Route? oldRoute}) {\n    _log(newRoute);\n    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/routes/app_navigation.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/sync_client_info_model.dart';\nimport 'package:simple_live_app/routes/route_path.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/sync_service.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\n\n/// APP页面跳转封装\n/// * 需要参数的页面都应使用此类\n/// * 如不需要参数，可以使用Get.toNamed\nclass AppNavigator {\n  /// 跳转至分类详情\n  static void toCategoryDetail(\n      {required Site site, required LiveSubCategory category}) {\n    Get.toNamed(RoutePath.kCategoryDetail, arguments: [site, category]);\n  }\n\n  /// 跳转至直播间\n  static void toLiveRoomDetail(\n      {required Site site, required String roomId}) async {\n    if (site.id == Constant.kBiliBili &&\n        !BiliBiliAccountService.instance.logined.value &&\n        AppSettingsController.instance.bilibiliLoginTip.value) {\n      var result = await Utils.showAlertDialog(\n        \"哔哩哔哩需要登录才能观看高清直播，是否前往登录？\",\n        title: \"登录哔哩哔哩\",\n        actions: [\n          TextButton(\n            onPressed: () {\n              AppSettingsController.instance.setBiliBiliLoginTip(false);\n              Get.back(result: false);\n            },\n            child: const Text(\"不再提示\"),\n          ),\n        ],\n      );\n      if (result == true) {\n        await toBiliBiliLogin();\n        if (!BiliBiliAccountService.instance.logined.value) {\n          SmartDialog.showToast(\"未完成登录\");\n        }\n      }\n    }\n\n    Get.toNamed(RoutePath.kLiveRoomDetail, arguments: site, parameters: {\n      \"roomId\": roomId,\n    });\n  }\n\n  /// 跳转至哔哩哔哩登录\n  static Future toBiliBiliLogin() async {\n    if (Platform.isAndroid || Platform.isIOS) {\n      await Get.toNamed(RoutePath.kBiliBiliWebLogin);\n    } else {\n      await Get.toNamed(RoutePath.kBiliBiliQRLogin);\n    }\n  }\n\n  /// 跳转至同步设备\n  static Future toSyncDevice(\n      SyncClinet client, SyncClientInfoModel info) async {\n    await Get.toNamed(\n      RoutePath.kLocalSyncDevice,\n      arguments: {\n        \"client\": client,\n        \"info\": info,\n      },\n    );\n  }\n\n  /// 跳转至关注用户信息详情\n  static void toFollowInfo(FollowUser follow) {\n    Get.toNamed(RoutePath.kFollowInfo, arguments: follow);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/routes/app_pages.dart",
    "content": "// ignore_for_file: prefer_inlined_adds\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/modules/category/detail/category_detail_controller.dart';\nimport 'package:simple_live_app/modules/category/detail/category_detail_page.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_app_setting/follow_app_settings_controller.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_app_setting/follow_app_settings_page.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_info_setting/follow_info_controller.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_info_setting/follow_info_page.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_user_controller.dart';\nimport 'package:simple_live_app/modules/follow_user/follow_user_page.dart';\nimport 'package:simple_live_app/modules/indexed/indexed_controller.dart';\nimport 'package:simple_live_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_app/modules/live_room/live_room_page.dart';\nimport 'package:simple_live_app/modules/mine/account/account_controller.dart';\nimport 'package:simple_live_app/modules/mine/account/account_page.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/qr_login_controller.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/qr_login_page.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/web_login_controller.dart';\nimport 'package:simple_live_app/modules/mine/account/bilibili/web_login_page.dart';\nimport 'package:simple_live_app/modules/mine/history/history_controller.dart';\nimport 'package:simple_live_app/modules/mine/history/history_page.dart';\nimport 'package:simple_live_app/modules/mine/parse/parse_controller.dart';\nimport 'package:simple_live_app/modules/mine/parse/parse_page.dart';\nimport 'package:simple_live_app/modules/search/search_controller.dart';\nimport 'package:simple_live_app/modules/search/search_page.dart';\nimport 'package:simple_live_app/modules/settings/appstyle_settings/appstyle_setting_page.dart';\nimport 'package:simple_live_app/modules/settings/auto_exit_settings_page.dart';\nimport 'package:simple_live_app/modules/settings/danmu_settings_page.dart';\nimport 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_controller.dart';\nimport 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_page.dart';\nimport 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_controller.dart';\nimport 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_page.dart';\nimport 'package:simple_live_app/modules/settings/other/other_settings_controller.dart';\nimport 'package:simple_live_app/modules/settings/other/other_settings_page.dart';\nimport 'package:simple_live_app/modules/settings/play_settings_page.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/device/sync_device_controller.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/device/sync_device_page.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/local_sync_controller.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/local_sync_page.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart';\nimport 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_page.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_controller.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_page.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_config_page.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart';\nimport 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_page.dart';\nimport 'package:simple_live_app/modules/sync/sync_page.dart';\n\nimport '../modules/indexed/indexed_page.dart';\nimport 'route_path.dart';\n\nclass AppPages {\n  AppPages._();\n  static final routes = [\n    // 首页\n    GetPage(\n      name: RoutePath.kIndex,\n      page: () => const IndexedPage(),\n      bindings: [\n        BindingsBuilder.put(() => IndexedController()),\n        //BindingsBuilder.put(() => HomeController()),\n      ],\n    ),\n    // 观看记录\n    GetPage(\n      name: RoutePath.kHistory,\n      page: () => const HistoryPage(),\n      bindings: [\n        BindingsBuilder.put(() => HistoryController()),\n      ],\n    ),\n    // 关注用户\n    GetPage(\n      name: RoutePath.kFollowUser,\n      page: () => const FollowUserPage(),\n      bindings: [\n        BindingsBuilder.put(() => FollowUserController()),\n      ],\n    ),\n    // 搜索\n    GetPage(\n      name: RoutePath.kSearch,\n      page: () => const SearchPage(),\n      bindings: [\n        BindingsBuilder.put(() => AppSearchController()),\n      ],\n    ),\n    //分类详情\n    GetPage(\n      name: RoutePath.kCategoryDetail,\n      page: () => const CategoryDetailPage(),\n      binding: BindingsBuilder.put(\n        () => CategoryDetailController(\n          site: Get.arguments[0],\n          subCategory: Get.arguments[1],\n        ),\n      ),\n    ),\n    //直播间\n    GetPage(\n      name: RoutePath.kLiveRoomDetail,\n      page: () => const LiveRoomPage(),\n      binding: BindingsBuilder.put(\n        () => LiveRoomController(\n          pSite: Get.arguments,\n          pRoomId: Get.parameters[\"roomId\"] ?? \"\",\n        ),\n      ),\n    ),\n    //弹幕设置\n    GetPage(\n      name: RoutePath.kSettingsDanmu,\n      page: () => const DanmuSettingsPage(),\n    ),\n    //外观设置\n    GetPage(\n        name: RoutePath.kAppstyleSetting,\n        page: () => const AppStyleSettingPage()),\n    //播放设置\n    GetPage(\n      name: RoutePath.kSettingsPlay,\n      page: () => const PlaySettingsPage(),\n    ),\n    //自动关闭\n    GetPage(\n      name: RoutePath.kSettingsAutoExit,\n      page: () => const AutoExitSettingsPage(),\n    ),\n    //工具箱\n    GetPage(\n      name: RoutePath.kTools,\n      page: () => const ParsePage(),\n      bindings: [\n        BindingsBuilder.put(() => ParseController()),\n      ],\n    ),\n    //关键词屏蔽\n    GetPage(\n      name: RoutePath.kSettingsDanmuShield,\n      page: () => const DanmuShieldPage(),\n      bindings: [\n        BindingsBuilder.put(() => DanmuShieldController()),\n      ],\n    ),\n    //主页设置\n    GetPage(\n      name: RoutePath.kSettingsIndexed,\n      page: () => const IndexedSettingsPage(),\n      bindings: [\n        BindingsBuilder.put(() => IndexedSettingsController()),\n      ],\n    ),\n    //账号设置\n    GetPage(\n      name: RoutePath.kSettingsAccount,\n      page: () => const AccountPage(),\n      bindings: [\n        BindingsBuilder.put(() => AccountController()),\n      ],\n    ),\n    //哔哩哔哩Web登录\n    GetPage(\n      name: RoutePath.kBiliBiliWebLogin,\n      page: () => const BiliBiliWebLoginPage(),\n      bindings: [\n        BindingsBuilder.put(() => BiliBiliWebLoginController()),\n      ],\n    ),\n    //哔哩哔哩二维码登录\n    GetPage(\n      name: RoutePath.kBiliBiliQRLogin,\n      page: () => const BiliBiliQRLoginPage(),\n      bindings: [\n        BindingsBuilder.put(() => BiliBiliQRLoginController()),\n      ],\n    ),\n    // 数据同步\n    GetPage(\n      name: RoutePath.kSync,\n      page: () => const SyncPage(),\n    ),\n    // 本地同步\n    GetPage(\n      name: RoutePath.kLocalSync,\n      page: () => const LocalSyncPage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => LocalSyncController(\n            Get.arguments ?? \"\",\n          ),\n        ),\n      ],\n    ),\n    //扫码\n    GetPage(\n      name: RoutePath.kSyncScan,\n      page: () => const SyncScanQRPage(),\n      bindings: [\n        BindingsBuilder.put(() => SyncScanQRControlelr()),\n      ],\n    ),\n    //同步设备\n    GetPage(\n      name: RoutePath.kLocalSyncDevice,\n      page: () => const SyncDevicePage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => SyncDeviceController(\n            client: Get.arguments['client'],\n            info: Get.arguments['info'],\n          ),\n        ),\n      ],\n    ),\n    //远程同步-房间\n    GetPage(\n      name: RoutePath.kRemoteSyncRoom,\n      page: () => const RemoteSyncRoomPage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => RemoteSyncRoomController(Get.arguments ?? \"\"),\n        ),\n      ],\n    ),\n    //远程同步-WebDAV\n    GetPage(\n      name: RoutePath.kRemoteSyncWebDav,\n      page: () => const RemoteSyncWebDAVPage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => RemoteSyncWebDAVController(),\n        ),\n      ],\n    ),\n    //远程同步-WebDAVConfig\n    GetPage(\n      name: RoutePath.kRemoteSyncWebDavConfig,\n      page: () => const RemoteSyncWebDAVConfigPage(),\n    ),\n    //其他设置\n    GetPage(\n      name: RoutePath.kSettingsOther,\n      page: () => const OtherSettingsPage(),\n      bindings: [\n        BindingsBuilder.put(() => OtherSettingsController()),\n      ],\n    ),\n    //关注设置\n    GetPage(\n      name: RoutePath.kSettingsFollow,\n      page: () => const FollowSettingsPage(),\n      bindings: [\n        BindingsBuilder.put(() => FollowAppSettingsController()),\n      ],\n    ),\n    // 关注用户-信息详情\n    GetPage(\n      name: RoutePath.kFollowInfo,\n      page: () => const FollowInfoPage(),\n      bindings: [\n        BindingsBuilder.put(() => FollowInfoController()),\n      ],\n    ),\n  ];\n}\n"
  },
  {
    "path": "simple_live_app/lib/routes/route_path.dart",
    "content": "/// 路由路径\nclass RoutePath {\n  /// 首页\n  static const kIndex = \"/index\";\n\n  /// 搜索\n  static const kSearch = \"/search\";\n\n  /// 分类详情\n  static const kCategoryDetail = \"/category/detail\";\n\n  /// 直播间\n  static const kLiveRoomDetail = \"/room/detail\";\n\n  /// 弹幕设置\n  static const kSettingsDanmu = \"/settings/danmu\";\n\n  /// 定时关闭设置\n  static const kSettingsAutoExit = \"/settings/auto_exit\";\n\n  /// 直播间设置\n  static const kSettingsPlay = \"/settings/play\";\n\n  /// 弹幕关键词屏蔽\n  static const kSettingsDanmuShield = \"/settings/danmu/shield\";\n\n  /// 其他设置\n  static const kSettingsOther = \"/settings/other\";\n\n  /// 赞助\n  static const kSponsor = \"/sponsor\";\n\n  /// 历史记录\n  static const kHistory = \"/user/history\";\n\n  /// 我的关注\n  static const kFollowUser = \"/user/follow\";\n\n  /// 关注用户-信息详情\n  static const kFollowInfo = \"/user/follow/info\";\n\n  /// 工具箱\n  static const kTools = \"/other/tools\";\n\n  /// 主页设置\n  static const kSettingsIndexed = \"/settings/indexed\";\n\n  /// 外观设置\n  static const kAppstyleSetting = \"/settings/appstyle\";\n\n  /// 账号管理\n  static const kSettingsAccount = \"/settings/account\";\n\n  /// 关注设置\n  static const kSettingsFollow = \"/settings/follow\";\n\n  /// BiliBili Web登录\n  static const kBiliBiliWebLogin = \"/settings/account/bilibili/web_login\";\n\n  /// BiliBili 二维码登录\n  static const kBiliBiliQRLogin = \"/settings/account/bilibili/qr_login\";\n\n  /// 数据同步\n  static const kLocalSync = \"/local_sync\";\n\n  /// 数据同步\n  static const kSync = \"/sync\";\n\n  /// 扫描\n  static const kSyncScan = \"/sync/scan\";\n\n  /// 同步设备\n  static const kLocalSyncDevice = \"/sync/device\";\n\n  /// 远程同步-房间\n  static const kRemoteSyncRoom = \"/remote_sync/room\";\n\n  /// 远程同步-WebDAVConfig\n  static const kRemoteSyncWebDav = \"/remote_sync/webDAV\";\n\n  /// 远程同步-WebDAVConfig\n  static const kRemoteSyncWebDavConfig = \"/remote_sync/webDAVConfig\";\n\n  /// 测试页面\n  static const kTest = \"/test\";\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/bilibili_account_service.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter_inappwebview/flutter_inappwebview.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/models/account/bilibili_user_info_page.dart';\nimport 'package:simple_live_app/requests/http_client.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass BiliBiliAccountService extends GetxService {\n  static BiliBiliAccountService get instance =>\n      Get.find<BiliBiliAccountService>();\n\n  var logined = false.obs;\n\n  var cookie = \"\";\n  var uid = 0;\n  var name = \"未登录\".obs;\n\n  @override\n  void onInit() {\n    cookie = LocalStorageService.instance\n        .getValue(LocalStorageService.kBilibiliCookie, \"\");\n    logined.value = cookie.isNotEmpty;\n    loadUserInfo();\n    super.onInit();\n  }\n\n  Future loadUserInfo() async {\n    if (cookie.isEmpty) {\n      return;\n    }\n    try {\n      var result = await HttpClient.instance.getJson(\n        \"https://api.bilibili.com/x/member/web/account\",\n        header: {\n          \"Cookie\": cookie,\n        },\n      );\n      if (result[\"code\"] == 0) {\n        var info = BiliBiliUserInfoModel.fromJson(result[\"data\"]);\n        name.value = info.uname ?? \"未登录\";\n        uid = info.mid ?? 0;\n        setSite();\n      } else {\n        SmartDialog.showToast(\"哔哩哔哩登录已失效，请重新登录\");\n        logout();\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"获取哔哩哔哩用户信息失败，可前往账号管理重试\");\n    }\n  }\n\n  void setSite() {\n    var site = (Sites.allSites[Constant.kBiliBili]!.liveSite as BiliBiliSite);\n    site.userId = uid;\n    site.cookie = cookie;\n  }\n\n  void setCookie(String cookie) {\n    this.cookie = cookie;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliCookie, cookie);\n    logined.value = cookie.isNotEmpty;\n  }\n\n  void logout() async {\n    cookie = \"\";\n    uid = 0;\n    name.value = \"未登录\";\n    setSite();\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliCookie, \"\");\n    logined.value = false;\n\n    if (Platform.isAndroid || Platform.isIOS) {\n      CookieManager cookieManager = CookieManager.instance();\n      await cookieManager.deleteAllCookies();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/core_api_service.dart",
    "content": "// 用于解耦simple_live_core\n// 候选方案，目前项目强耦合core，需要逐步剥离\nimport 'package:get/get.dart';\n\n/// api:\n/// 获取All-Sites: getAllSites()->List<Site>\n/// 获取平台首页推荐： site.getRecommends()->List<Room>\n/// 获取平台分类：site.getCategories()->List<Category>()\n/// 获取平台分类详情： site.getCategoryDetail()->List<Room>\n/// 更新关注列表状态： site.roomId.getFollowLiveState()->bool\n/// 获取房间详情： site.roomId.getRoomDetail()->roomDetail\n/// 获取房间播放链列表：site.roomId.getRoomPlayList()->List<playList>\n/// 获取房间清晰度列表： site.roomId.getRoomPlayQualities()->List<playQuality>\n/// 获取房间弹幕：site.roomId.getRoomDanmaku()->websocket\n/// 获取平台cookie有效性检测：site.getUserInfo(\"cookie\")->bool\n///\n/// 实现逻辑：\n/// 1: 命令模式-example：\n/// core.api(\n///   {\n///     site: \"bilibli\",\n///     roomId:\"\",\n///     func: getRecommends,\n///     func-params:{...}\n///   }\n/// )\n///\n/// 2。 builder设计-example:\n/// builder\n///       .setSite(\"douyu\")\n///       .setRoomId(\"\")\n///       .setFuncName(\"getRecommendation\")\n///       .getParam(\"limit\":\"50\")\n///       .build();\n/// 均需要多重设计，部分model需要copy并实现json接口\n/// 参数列表，函数列表字典\n/// api字典\n\nclass CoreApiBuilder {\n  String? _site;\n  String? _roomId;\n  String? _funcName;\n  final Map<String, dynamic> _params = {};\n\n  CoreApiBuilder();\n\n  CoreApiBuilder site(String site) {\n    _site = site;\n    return this;\n  }\n\n  CoreApiBuilder room(String roomId) {\n    _roomId = roomId;\n    return this;\n  }\n\n  CoreApiBuilder func(String funcName) {\n    _funcName = funcName;\n    return this;\n  }\n\n  CoreApiBuilder param(String key, dynamic value) {\n    _params[key] = value;\n    return this;\n  }\n\n  CoreApiBuilder params(Map<String, dynamic> params) {\n    _params.addAll(params);\n    return this;\n  }\n\n  Future<Map<String, dynamic>> build() {\n    if (_site == null) {\n      throw Exception(\"site must be set.\");\n    }\n    if (_funcName == null) {\n      throw Exception(\"funcName must be set.\");\n    }\n\n    return CoreDispatcher.dispatch(\n      site: _site!,\n      funcName: _funcName!,\n      roomId: _roomId,\n      params: _params,\n    );\n  }\n}\n\nclass CoreDispatcher {\n  static Future<Map<String, dynamic>> dispatch({\n    required String site,\n    required String funcName,\n    String? roomId,\n    Map<String, dynamic>? params,\n  }) async {\n    //缺少参数检查\n    return {\n      'site': site,\n      'roomId': roomId,\n      'funcName': funcName,\n      'func-params': params ?? {},\n    };\n  }\n}\n\nclass CoreApiService extends GetxService {\n  CoreApiBuilder get builder => CoreApiBuilder();\n\n  // demo\n  void exampleUsage() {\n    builder.site(\"bilibili\").func(\"getRecommends\").param(\"limit\", 1).build();\n    // builder\n    //     .site(\"douyu\")\n    //     .room(\"12345\")\n    //     .func(\"getRoomDetail\")\n    //     .build();\n    // var res = core.api(arg=builder)\n    // 参数类型选择器->json to model\n\n    // simple_live_core 应该实现 参数解析器->统一返回json->调用端：json to model 实现解耦\n    // 目的： 自建 api 或 ffi 调用\n    // 该工作非必要，暂且备份为草稿\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/db_service.dart",
    "content": "import 'dart:async';\n\nimport 'package:fractional_indexing_dart/fractional_indexing_dart.dart';\nimport 'package:get/get.dart';\nimport 'package:hive/hive.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:collection/collection.dart';\n\nclass DBService extends GetxService {\n  static DBService get instance => Get.find<DBService>();\n  late Box<History> historyBox;\n  late Box<FollowUser> followBox;\n  late Box<FollowUserTag> tagBox;\n\n  Future init() async {\n    historyBox = await Hive.openBox(\"History\");\n    followBox = await Hive.openBox(\"FollowUser\");\n    tagBox = await Hive.openBox(\"FollowUserTag\");\n  }\n\n  Future<void> clearFollowTag() async {\n    await tagBox.clear();\n  }\n\n  bool getFollowTagExist(String id) {\n    return tagBox.containsKey(id);\n  }\n\n  List<FollowUserTag> getFollowTagList() {\n    return tagBox.values.toList();\n  }\n\n  Future updateFollowTag(FollowUserTag followTag) async {\n    await tagBox.put(followTag.id, followTag);\n  }\n\n  Future<FollowUserTag> addFollowTag(String tag) async {\n    // 查找数据库中是否已存在 存在则直接返回\n    if (getFollowTagExistByTag(tag)) {\n      return getFollowTag(tag)!;\n    }\n    String? lastKey = tagBox.keys.lastOrNull;\n    final String uniqueId =  FractionalIndexing.generateKeyBetween(lastKey, null);\n    final followUserTag = FollowUserTag(id: uniqueId, tag: tag, userId: []);\n    await tagBox.put(uniqueId, followUserTag);\n    return followUserTag;\n  }\n\n  Future deleteFollowTag(String id) async {\n    await tagBox.delete(id);\n  }\n\n  FollowUserTag? getFollowTag(String tag) {\n    return tagBox.values.firstWhereOrNull((item) => item.tag == tag);\n  }\n\n  // 判断tag名称是否重复\n  bool getFollowTagExistByTag(String tag) {\n    return tagBox.values.any((item) => item.tag == tag);\n  }\n\n  bool getFollowExist(String id) {\n    return followBox.containsKey(id);\n  }\n\n  List<FollowUser> getFollowList() {\n    return followBox.values.toList();\n  }\n\n  Future addFollow(FollowUser follow) async {\n    await followBox.put(follow.id, follow);\n  }\n\n  Future deleteFollow(String id) async {\n    await followBox.delete(id);\n  }\n\n  History? getHistory(String id) {\n    if (historyBox.containsKey(id)) {\n      return historyBox.get(id);\n    }\n    return null;\n  }\n\n  Future addOrUpdateHistory(History history) async {\n    await historyBox.put(history.id, history);\n  }\n\n  Future delHistory(String id) async {\n    await historyBox.delete(id);\n  }\n\n  List<History> getHistories() {\n    var his = historyBox.values.toList();\n    his.sort((a, b) => b.updateTime.compareTo(a.updateTime));\n    return his;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/douyin_account_service.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter_inappwebview/flutter_inappwebview.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/models/account/douyin_user_info.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass DouyinAccountService extends GetxService {\n  static DouyinAccountService get instance => Get.find<DouyinAccountService>();\n  final site = (Sites.allSites[Constant.kDouyin]!.liveSite as DouyinSite);\n  var logined = false.obs;\n  var cookie = \"\";\n  var name = \"未登录\".obs;\n  var hlsFirst = false;\n\n  @override\n  void onInit() {\n    hlsFirst = LocalStorageService.instance\n        .getValue(LocalStorageService.kDouyinHlsFirst, false);\n    _setSiteHlsFirst();\n    cookie = LocalStorageService.instance\n        .getValue(LocalStorageService.kDouyinCookie, \"\");\n    logined.value = cookie.isNotEmpty;\n    loadUserInfo();\n    super.onInit();\n  }\n\n  // 设置DouyinHlsFirst\n  void _setSiteHlsFirst() {\n    site.hlsFirst = hlsFirst;\n  }\n\n  Future loadUserInfo() async {\n    if (cookie.isEmpty) {\n      return;\n    }\n    try {\n      final data = await site.getUserInfoByCookie(cookie);\n      if (data.isEmpty) {\n        SmartDialog.showToast(\"抖音登录已失效，请重新登录\");\n        logout();\n        return;\n      }\n      var info = DouyinUserInfoModel.fromJson(data);\n      name.value = info.nickname!;\n      logined.value = true;\n      _setSiteCookie();\n    } catch (e) {\n      SmartDialog.showToast(\"获取抖音登录用户信息失败，可前往账号管理重试\");\n    }\n  }\n\n  void _setSiteCookie() {\n    if (cookie.isEmpty) {\n      site.headers.remove(\"cookie\");\n    } else {\n      site.headers[\"cookie\"] = cookie;\n    }\n  }\n\n  void setCookie(String cookie) {\n    this.cookie = cookie;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDouyinCookie, cookie);\n  }\n\n  void logout() async {\n    cookie = \"\";\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDouyinCookie, \"\");\n    logined.value = false;\n    name.value = \"未登录\";\n    _setSiteCookie();\n    if (Platform.isAndroid || Platform.isIOS) {\n      CookieManager cookieManager = CookieManager.instance();\n      await cookieManager.deleteAllCookies();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/firebase_service.dart",
    "content": "﻿// only for Android\nimport 'dart:ui';\n\nimport 'package:firebase_analytics/firebase_analytics.dart';\nimport 'package:firebase_crashlytics/firebase_crashlytics.dart';\nimport 'package:flutter/cupertino.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\n\nclass FirebaseService extends GetxService {\n  static FirebaseService get instance => Get.find<FirebaseService>();\n\n  @override\n  onInit() {\n    bool e = AppSettingsController.instance.firebaseEnable.value;\n    setCrashlytics(e);\n    super.onInit();\n  }\n\n  static Future<void> setCrashlytics(bool enable) async {\n    await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(enable);\n\n    if (enable) {\n      FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;\n      PlatformDispatcher.instance.onError = (error, stack) {\n        FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);\n        return true;\n      };\n    }else{\n      FlutterError.onError = FlutterError.dumpErrorToConsole;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/follow_service.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:io';\n\nimport 'package:file_picker/file_picker.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:fractional_indexing_dart/fractional_indexing_dart.dart';\nimport 'package:get/get.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:pinyin/pinyin.dart';\nimport 'package:pool/pool.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/app/utils/duration_2_str_utils.dart';\nimport 'package:simple_live_app/app/utils/dynamic_sort.dart';\nimport 'package:simple_live_app/app/utils/string_normalizer.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:synchronized/synchronized.dart';\n\nclass FollowService extends GetxService {\n  StreamSubscription<dynamic>? subscription;\n\n  static FollowService get instance => Get.find<FollowService>();\n\n  final StreamController _updatedListController = StreamController.broadcast();\n\n  Stream get updatedListStream => _updatedListController.stream;\n\n  /// 关注用户列表\n  RxList<FollowUser> followList = RxList<FollowUser>();\n\n  /// 直播中的用户列表\n  RxList<FollowUser> liveList = RxList<FollowUser>();\n\n  /// 未直播的用户列表\n  RxList<FollowUser> notLiveList = RxList<FollowUser>();\n\n  /// 用户自定义的tag\n  RxList<FollowUserTag> followTagList = RxList<FollowUserTag>();\n\n  /// 当前tag的用户列表\n  RxList<FollowUser> curTagFollowList = RxList<FollowUser>();\n\n  /// 线程安全\n  final _lock = Lock();\n\n  /// 已经更新状态的数量\n  var updatedCount = 0;\n\n  /// 是否正在更新\n  var updating = false.obs;\n\n  Timer? updateTimer;\n\n  int _totalToUpdate = 0;\n\n  int _refreshCycle = 0;\n\n  @override\n  void onInit() {\n    subscription = EventBus.instance.listen(Constant.kUpdateFollow, (data) {\n      if (data is History) {\n        updateFollowHistory(data);\n      } else {\n        loadData(updateStatus: false);\n      }\n    });\n    initTimer();\n    super.onInit();\n  }\n\n  void updateTagName(FollowUserTag followUserTag, String newTagName) {\n    final FollowUserTag newTag = followUserTag.copyWith(tag: newTagName);\n    updateFollowUserTag(newTag);\n    // update item's tag when update tagName\n    for (var i in newTag.userId) {\n      var follow = DBService.instance.followBox.get(i);\n      if (follow != null) {\n        follow.tag = newTagName;\n        addFollow(follow);\n      }\n    }\n  }\n\n  Future<void> updateFollowUserTag(FollowUserTag tag) async {\n    if (tag.tag == '全部') {\n      return;\n    }\n    await DBService.instance.updateFollowTag(tag);\n    // 查找并修改\n    var index = followTagList.indexWhere((oTag) => oTag.id == tag.id);\n    followTagList[index] = tag;\n  }\n\n  Future<void> addFollowUserTag(String tag) async {\n    // 判断待添加tag是否已存在，存在则return\n    if (followTagList.any((item) => item.tag == tag)) {\n      SmartDialog.showToast(\"标签名重复，修改失败\");\n      return;\n    }\n    FollowUserTag item = await DBService.instance.addFollowTag(tag);\n    followTagList.add(item);\n  }\n\n  Future removeFollowUserTag(FollowUserTag tag) async {\n    // 将tag下的所有follow设置为全部\n    for (var i in tag.userId) {\n      var follow = DBService.instance.followBox.get(i);\n      if (follow != null) {\n        follow.tag = \"全部\";\n        FollowService.instance.addFollow(follow);\n      }\n    }\n    followTagList.remove(tag);\n    await DBService.instance.deleteFollowTag(tag.id);\n  }\n\n  // 获取用户自定义标签列表\n  void getAllTagList() {\n    var list = DBService.instance.getFollowTagList();\n    followTagList.assignAll(list);\n  }\n\n  /// 获取包含“全部”的标签选项列表\n  List<FollowUserTag> getTagOptionsWithAll() {\n    return [\n      FollowUserTag(id: '0', tag: '全部', userId: []),\n      ...followTagList,\n    ];\n  }\n\n  /// 为关注项设置标签（统一逻辑）\n  void setFollowTag(FollowUser item, FollowUserTag targetTag) {\n    // 当前标签对象（可能为“全部”且不在 followTagList 中）\n    FollowUserTag? currentTag;\n    if (item.tag != '全部') {\n      for (final t in followTagList) {\n        if (t.tag == item.tag) {\n          currentTag = t;\n          break;\n        }\n      }\n    }\n\n    // 从旧标签移除\n    if (currentTag != null) {\n      currentTag.userId.remove(item.id);\n      DBService.instance.updateFollowTag(currentTag);\n    }\n\n    // 添加到新标签（跳过“全部”）\n    if (targetTag.tag != '全部') {\n      // targetTag来源于UI选项，需定位真实对象\n      FollowUserTag? tar;\n      for (final t in followTagList) {\n        if (t.tag == targetTag.tag) {\n          tar = t;\n          break;\n        }\n      }\n      if (tar != null) {\n        tar.userId.addIf(!tar.userId.contains(item.id), item.id);\n        DBService.instance.updateFollowTag(tar);\n      }\n    }\n\n    // 更新FollowUser本身\n    item.tag = targetTag.tag;\n    addFollow(item);\n  }\n\n  void filterDataByTag(FollowUserTag tag) {\n    // 清空curTagFollowList\n    curTagFollowList.clear();\n    // 用一个新的列表来存储需要删除的 userId\n    List<String> toRemove = [];\n    for (var id in tag.userId) {\n      if (followList.any((x) => x.id == id)) {\n        // 找到对应的 followUser 添加到 curTagFollowList\n        curTagFollowList.add(followList.firstWhere((x) => x.id == id));\n      } else {\n        // 标记要删除的 id\n        toRemove.add(id);\n      }\n    }\n    // 在遍历结束后统一移除不在 followList 中的 id\n    tag.userId.removeWhere((id) => toRemove.contains(id));\n    // 更新数据库\n    if (toRemove.isNotEmpty) {\n      DBService.instance.updateFollowTag(tag);\n    }\n    listSortByMethod(curTagFollowList,  AppSettingsController.instance.followSortMethod.value);\n  }\n\n  Future<void> updateFollowTagOrder(FollowUserTag oldTag,FollowUserTag newTag) async {\n    await DBService.instance.deleteFollowTag(oldTag.id);\n    await DBService.instance.updateFollowTag(newTag);\n    loadData(updateStatus: false);\n  }\n\n  // 添加关注\n  void addFollow(FollowUser follow) {\n    // follow变动过程中romanName统一变化\n    String romanName = \"\";\n    if(follow.remark !=null && follow.remark!.isNotEmpty){\n      romanName = PinyinHelper.getShortPinyin(follow.romanName!);\n    }else{\n      romanName = PinyinHelper.getShortPinyin(follow.userName);\n    }\n    follow.romanName = romanName.normalize();\n\n    DBService.instance.addFollow(follow);\n  }\n\n  // 取消关注\n  Future<void> removeFollowUser(String id) async {\n    await DBService.instance.deleteFollow(id);\n  }\n\n  // 判断关注是否存在\n  bool getFollowExist(String id) {\n    return DBService.instance.getFollowExist(id);\n  }\n\n  // 更新关注的历史记录\n  void updateFollowHistory(History history) {\n    var follow =\n        followList.where((follow) => follow.id == history.id).firstOrNull;\n    if (follow == null) {\n      return;\n    } else {\n      follow.watchDuration = history.watchDuration;\n      addFollow(follow);\n    }\n    Log.i(\"已更新当前播放的观看时长：${follow.watchDuration}\");\n  }\n\n  void initTimer() {\n    if (AppSettingsController.instance.autoUpdateFollowEnable.value) {\n      updateTimer?.cancel();\n      _refreshCycle = 0;\n      updateTimer = Timer.periodic(\n        Duration(\n            minutes:\n                AppSettingsController.instance.autoUpdateFollowDuration.value),\n        (timer) {\n          CoreLog.i(\"Update Follow Timer - Cycle: $_refreshCycle\");\n          loadData(updateStatus: true, cycle: _refreshCycle);\n          _refreshCycle = (_refreshCycle + 1) % 2; // 2-cycle rotation\n        },\n      );\n    } else {\n      updateTimer?.cancel();\n    }\n  }\n\n  Future<void> loadData({bool updateStatus = true, int? cycle}) async {\n    var list = DBService.instance.getFollowList();\n    getAllTagList();\n    if (list.isEmpty) {\n      updating.value = false;\n      followList.assignAll(list);\n      liveList.clear();\n      notLiveList.clear();\n      _updatedListController.add(0);\n      return;\n    }\n    if (updateStatus) {\n      followList.assignAll(list);\n      startUpdateStatus(cycle: cycle);\n    }else{\n      _updatedListController.add(0);\n    }\n  }\n\n  void multiRoundPriority() {\n    final historyList = DBService.instance.getHistories();\n    final Map<String, int> historyRankMap = {\n      for (var i = 0; i < historyList.length; i++) historyList[i].id: i\n    };\n    final int maxRank = historyList.isNotEmpty ? historyList.length : 1;\n\n    Duration maxDuration = const Duration();\n    for (var user in followList) {\n      final duration = user.watchDuration!.toDuration();\n      if (duration > maxDuration) {\n        maxDuration = duration;\n      }\n    }\n    final double maxDurationInSeconds =\n        maxDuration.inSeconds > 0 ? maxDuration.inSeconds.toDouble() : 1.0;\n    // 简单线性加权组合算法，目前认定观看时长和最近观看时间权重一致\n    // 如果用户历史行为序列非常长：可替换为时间衰减 + 观看时长加权\n    followList.sort((a, b) {\n      // 静态权重\n      const double wDuration = 0.5;\n      const double wRecency = 0.5;\n      // 在线降权，离线增权\n      const double wOnline = 0.3;\n      const double wOffline = 1 - wOnline;\n\n      // 动态权重\n      double normDurationA =\n          a.watchDuration!.toDuration().inSeconds.toDouble() /\n              maxDurationInSeconds;\n      int rankA = historyRankMap[a.id] ?? maxRank;\n      double normRecencyA = (maxRank - rankA).toDouble() / maxRank;\n      double scoreA =\n          ((wDuration * normDurationA) + (wRecency * normRecencyA)) *\n              (a.liveStatus.value == 2 ? wOnline : wOffline);\n\n      double normDurationB =\n          b.watchDuration!.toDuration().inSeconds.toDouble() /\n              maxDurationInSeconds;\n      int rankB = historyRankMap[b.id] ?? maxRank;\n      double normRecencyB = (maxRank - rankB).toDouble() / maxRank;\n      double scoreB =\n          ((wDuration * normDurationB) + (wRecency * normRecencyB)) *\n              (b.liveStatus.value == 2 ? wOnline : wOffline);\n\n      return scoreB.compareTo(scoreA);\n    });\n  }\n\n  void startUpdateStatus({int? cycle}) async {\n    List<FollowUser> usersToUpdate;\n    final totalUsers = followList.length;\n    final douyinCount = followList.where((x) => x.siteId == 'douyin').length;\n\n    //tips: 噪音用户画像（高风险平台：90%; 多次手刷; 单高关注数>50; 频繁切直播间; 不登录反复高危操作; 移动宽带用户; 反复关注取消; 多ip切换; 特殊地区风控; 多端在线请求; 黑号）\n    if (cycle != null && (totalUsers > 100 || douyinCount > 50)) {\n      // 简单28\n      final topNCount = (totalUsers * 0.2).round(); // Top 20%\n      final bottomNCount = (totalUsers * 0.2).round(); // Bottom 20%\n      final middlePartEndIndex = totalUsers - bottomNCount;\n      multiRoundPriority();\n      final topNUsers = followList.sublist(0, topNCount);\n      final middleUsers = followList.sublist(topNCount, middlePartEndIndex);\n      if (cycle == 0) {\n        usersToUpdate = topNUsers;\n        CoreLog.i(\n            \"Update Follow: Cycle 0, updating top ${usersToUpdate.length}/$totalUsers users.\");\n      } else {\n        usersToUpdate = [...topNUsers, ...middleUsers];\n        CoreLog.i(\n            \"Update Follow: Cycle 1, updating top+middle ${usersToUpdate.length}/$totalUsers users.\");\n      }\n    } else {\n      usersToUpdate = List.from(followList);\n      if (cycle != null) {\n        CoreLog.i(\n            \"Update Follow: List <= 100, updating all ${usersToUpdate.length} users.\");\n      }\n    }\n    _totalToUpdate = usersToUpdate.length;\n    updatedCount = 0;\n    updating.value = true;\n\n    if (_totalToUpdate == 0) {\n      updating.value = false;\n      filterData();\n      return;\n    }\n\n    var threadCount =\n        AppSettingsController.instance.updateFollowThreadCount.value;\n\n    var pool = Pool(threadCount);\n    var tasks = <Future>[];\n\n    for (var user in usersToUpdate) {\n      tasks.add(pool.withResource(() => updateLiveInformation(user)));\n    }\n    await Future.wait(tasks);\n    await pool.close();\n  }\n\n  Future updateLiveInformation(FollowUser item) async {\n    try {\n      var site = Sites.allSites[item.siteId]!;\n      LiveRoomDetail detail =\n          await site.liveSite.getRoomDetail(roomId: item.roomId);\n      item.liveStatus.value = detail.status ? 2 : 1;\n      item.cover.value = detail.status ? detail.cover : \"\";\n      item.title.value = detail.title;\n      item.online.value = detail.online;\n    } catch (e) {\n      Log.logPrint(e);\n    } finally {\n      await _lock.synchronized(() {\n        updatedCount++;\n      });\n      if (updatedCount >= _totalToUpdate) {\n        filterData();\n        updating.value = false;\n      }\n    }\n  }\n\n  void filterData() {\n    liveListSort();\n    liveList.assignAll(followList.where((x) => x.liveStatus.value == 2));\n    notLiveList.assignAll(followList.where((x) => x.liveStatus.value == 1));\n    _updatedListController.add(0);\n  }\n\n  void liveListSort(){\n    listSortByMethod(followList, AppSettingsController.instance.followSortMethod.value);\n    liveList.assignAll(followList.where((x) => x.liveStatus.value == 2));\n    notLiveList.assignAll(followList.where((x) => x.liveStatus.value == 1));\n  }\n\n  void listSortByMethod(List<FollowUser> list, SortMethod sortMethod) {\n    var liveCondition = SortCondition<FollowUser>(\n      valueGetter: (item) => item.liveStatus.value, // Rx<int>\n      ascending: false,\n    );\n    var watchDurationCondition = SortCondition<FollowUser>(\n      valueGetter: (item) => item.watchDuration?.toDuration() ?? Duration.zero,\n      ascending: false,\n    );\n    var siteIdCondition = SortCondition<FollowUser>(\n      valueGetter: (item) {\n        final order = AppSettingsController.instance.siteSort;\n        // 返回索引作为 Comparable\n        return order.indexOf(item.siteId);\n      },\n    );\n    var recentlyCondition = SortCondition<FollowUser>(\n      valueGetter: (item) => item.addTime,\n      ascending: false,\n    );\n    var userNameASCCondition = SortCondition<FollowUser>(\n      valueGetter: (item) => item.romanName ?? \"\",\n      ascending: true,\n    );\n    var userNameDESCCondition = SortCondition<FollowUser>(\n      valueGetter: (item) => item.romanName ?? \"\",\n      ascending: false,\n    );\n    switch (sortMethod) {\n      case SortMethod.watchDuration:\n        list.dynamicSort([liveCondition, watchDurationCondition]);\n      case SortMethod.siteId:\n        list.dynamicSort([liveCondition, siteIdCondition]);\n      case SortMethod.recently:\n        list.dynamicSort([liveCondition, recentlyCondition]);\n      case SortMethod.userNameASC:\n        list.dynamicSort([liveCondition, userNameASCCondition]);\n      case SortMethod.userNameDESC:\n        list.dynamicSort([liveCondition, userNameDESCCondition]);\n    }\n  }\n\n  void exportFile() async {\n    if (followList.isEmpty) {\n      SmartDialog.showToast(\"列表为空\");\n      return;\n    }\n\n    try {\n      var status = await Utils.checkStorgePermission();\n      if (!status) {\n        SmartDialog.showToast(\"无权限\");\n        return;\n      }\n\n      var dir = \"\";\n      if (Platform.isIOS) {\n        dir = (await getApplicationDocumentsDirectory()).path;\n      } else {\n        dir = await FilePicker.platform.getDirectoryPath() ?? \"\";\n      }\n\n      if (dir.isEmpty) {\n        return;\n      }\n      var jsonFile = File(\n          '$dir/SimpleLive_${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json');\n      var jsonText = generateJson();\n      await jsonFile.writeAsString(jsonText);\n      SmartDialog.showToast(\"已导出关注列表\");\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"导出失败：$e\");\n    }\n  }\n\n  void inputFile() async {\n    try {\n      var status = await Utils.checkStorgePermission();\n      if (!status) {\n        SmartDialog.showToast(\"无权限\");\n        return;\n      }\n      var file = await FilePicker.platform.pickFiles(\n        type: FileType.custom,\n        allowedExtensions: ['json'],\n      );\n      if (file == null) {\n        return;\n      }\n      var jsonFile = File(file.files.single.path!);\n      await inputJson(await jsonFile.readAsString());\n      SmartDialog.showToast(\"导入成功\");\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"导入失败:$e\");\n    } finally {\n      loadData();\n    }\n  }\n\n  void exportText() {\n    if (followList.isEmpty) {\n      SmartDialog.showToast(\"列表为空\");\n      return;\n    }\n    var content = generateJson();\n    Get.dialog(\n      AlertDialog(\n        title: const Text(\"导出为文本\"),\n        content: TextField(\n          controller: TextEditingController(text: content),\n          decoration: const InputDecoration(\n            border: OutlineInputBorder(),\n          ),\n          minLines: 5,\n          maxLines: 8,\n        ),\n        actions: [\n          TextButton(\n            onPressed: () {\n              Get.back();\n            },\n            child: const Text(\"关闭\"),\n          ),\n          TextButton(\n            onPressed: () {\n              Utils.copyToClipboard(content);\n              Get.back();\n            },\n            child: const Text(\"复制\"),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void inputText() async {\n    final TextEditingController textController = TextEditingController();\n    await Get.dialog(\n      AlertDialog(\n        title: const Text(\"从文本导入\"),\n        content: TextField(\n          controller: textController,\n          decoration: const InputDecoration(\n            border: OutlineInputBorder(),\n            hintText: \"请输入内容\",\n          ),\n          minLines: 5,\n          maxLines: 8,\n        ),\n        actions: [\n          TextButton(\n            onPressed: () {\n              Get.back();\n            },\n            child: const Text(\"关闭\"),\n          ),\n          TextButton(\n            onPressed: () async {\n              var content = await Utils.getClipboard();\n              if (content != null) {\n                textController.text = content;\n              }\n            },\n            child: const Text(\"粘贴\"),\n          ),\n          TextButton(\n            onPressed: () async {\n              if (textController.text.isEmpty) {\n                SmartDialog.showToast(\"内容为空\");\n                return;\n              }\n              try {\n                await inputJson(textController.text);\n                SmartDialog.showToast(\"导入成功\");\n                Get.back();\n                loadData();\n              } catch (e) {\n                SmartDialog.showToast(\"导入失败，请检查内容是否正确\");\n              }\n            },\n            child: const Text(\"导入\"),\n          ),\n        ],\n      ),\n    );\n  }\n\n  String generateJson() {\n    var data = followList\n        .map(\n          (item) => {\n            \"siteId\": item.siteId,\n            \"id\": item.id,\n            \"roomId\": item.roomId,\n            \"userName\": item.userName,\n            \"face\": item.face,\n            \"watchDuration\": item.watchDuration,\n            \"addTime\": item.addTime.toString(),\n            \"remark\": item.remark,\n            \"romanName\": item.romanName,\n            \"tag\": item.tag\n          },\n        )\n        .toList();\n    return jsonEncode(data);\n  }\n\n  Future inputJson(String content) async {\n    var data = jsonDecode(content);\n\n    for (var item in data) {\n      var follow = FollowUser.fromJson(item);\n      await DBService.instance.addFollow(follow);\n    }\n\n    await followUserAllDataCheck();\n  }\n\n  // 数据校对\n  // 核心关注数据有几种错乱情况，需要进行校对，需要一定时间复核代码\n  // 1：未关注，但标签包含关注\n  // 2: 已关注，且设置标签，但标签不包含\n  // 3: 已关注，且设置标签，但标签不存在\n  // 4: 标签重复\n  // 5: webdav同步导致的数据错乱\n  // 校对思路，followList是基础数据源，tagList为索引数据，重建数据即可\n  // 根据此思路，可以重写文件导入导出以及webdav恢复逻辑\n  Future<void> followUserAllDataCheck() async {\n    var followUserListTemp = DBService.instance.getFollowList();\n    var oldTagList = DBService.instance.getFollowTagList();\n    final Map<String, List<String>> tagMap = {\n      for (var tag in oldTagList) tag.tag: <String>[],\n    };\n    // 手动添加罗马音\n    for (FollowUser follow in followUserListTemp) {\n      if (follow.remark != null && follow.remark!.isNotEmpty) {\n        var roman = PinyinHelper.getShortPinyin(follow.remark!).normalize();\n        follow.romanName = roman;\n      } else {\n        follow.romanName = PinyinHelper.getShortPinyin(follow.userName).normalize();\n      }\n      await DBService.instance.addFollow(follow);\n    }\n    Log.i(\"transfer follow.name to roman is down!\");\n    for (var follow in followUserListTemp) {\n      if(follow.tag!=\"全部\"){\n        tagMap.putIfAbsent(follow.tag, () => <String>[]).add(follow.id);\n      }\n    }\n    // 落库\n    final Map<String, FollowUserTag> res = {};\n    String? lastKey;\n    for (var entry in tagMap.entries) {\n      lastKey = FractionalIndexing.generateKeyBetween(lastKey, null);\n      final followUserTag = FollowUserTag(\n        id: lastKey,\n        tag: entry.key,\n        userId: entry.value,\n      );\n      res[followUserTag.id] = followUserTag;\n    }\n    await DBService.instance.tagBox.clear();\n    await DBService.instance.tagBox.putAll(res);\n    Log.i(\"Follow-Service: data check down，follows:${followUserListTemp.length}，tags:${tagMap.length}\");\n  }\n\n  @override\n  void onClose() {\n    updateTimer?.cancel();\n    subscription?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/history_service.dart",
    "content": "import 'dart:async';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils/duration_2_str_utils.dart';\nimport 'package:simple_live_app/models/db/history.dart';\n\nimport 'db_service.dart';\n\nclass HistoryService extends GetxService {\n  static HistoryService get instance => Get.find<HistoryService>();\n  final Stopwatch _stopwatch = Stopwatch();\n  var _elapsed = Duration.zero;\n  Duration _oldWatchedDuration = Duration.zero;\n  History? curLiveRoomHistory;\n\n  //两分钟自动保存一次，防止用户直接关闭app，丢失数据\n  final _saveInterval = const Duration(minutes: 2);\n  Timer? _timer; // 定时器\n\n  // 开始计时\n  void start(History history) {\n    _loadHistory(history);\n    _stopwatch.start();\n    _timer = Timer.periodic(_saveInterval, (timer) {\n      _updateHistory();\n    });\n  }\n\n  // reset\n  void reset(String roomId) {\n    _updateHistory();\n    _stopwatch.reset();\n    History? history = DBService.instance.getHistory(roomId);\n    if(history != null){\n      _loadHistory(history);\n    }\n  }\n\n  // 停止计时\n  void stop() {\n    _stopwatch.stop();\n    _updateHistory();\n    _stopwatch.reset();\n    _elapsed = Duration.zero;\n    // 取消定时器\n    _timer?.cancel();\n    _timer = null;\n    curLiveRoomHistory = null;\n    Log.i(\"本次观看时长：$_elapsed\");\n  }\n\n  void _loadHistory(History history) {\n    curLiveRoomHistory = DBService.instance.getHistory(history.id);\n    // 首次观看则创建\n    if (curLiveRoomHistory == null) {\n      curLiveRoomHistory = history;\n      DBService.instance.addOrUpdateHistory(history);\n    }\n    _oldWatchedDuration = curLiveRoomHistory!.duration;\n  }\n\n  // updateHistory\n  void _updateHistory() {\n    if (curLiveRoomHistory == null) {\n      return;\n    }\n    // 累加到当前历史记录\n    _elapsed = _stopwatch.elapsed;\n    Duration curTime = _oldWatchedDuration + _elapsed;\n    Log.i(\n        \"已观看时间：${_oldWatchedDuration.toHMSString()}_增加时间：${_elapsed.toHMSString()}\");\n    curLiveRoomHistory?.watchDuration = curTime.toHMSString();\n    curLiveRoomHistory?.updateTime = DateTime.now();\n    DBService.instance.addOrUpdateHistory(curLiveRoomHistory!);\n    EventBus.instance.emit(Constant.kUpdateFollow, curLiveRoomHistory);\n  }\n\n  // 获取历史记录中存储的累计观看时长\n  String getHistoryDuration({required String followUserId}) {\n    var historyWatchDuration = \"00:00:00\";\n    History? history = DBService.instance.getHistory(followUserId);\n    historyWatchDuration = history?.watchDuration ?? \"00:00:00\";\n    return historyWatchDuration;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/local_storage_service.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:hive/hive.dart';\nimport 'package:simple_live_app/app/log.dart';\n\nclass LocalStorageService extends GetxService {\n  static LocalStorageService get instance => Get.find<LocalStorageService>();\n\n  /// 首次运行\n  static const String kFirstRun = \"FirstRun\";\n\n  /// 缩放模式\n  static const String kPlayerScaleMode = \"ScaleMode\";\n\n  /// 网站排序\n  static const String kSiteSort = \"SiteSort\";\n\n  /// 首页排序\n  static const String kHomeSort = \"HomeSort\";\n\n  /// 显示模式\n  /// * [0] 跟随系统\n  /// * [1] 浅色模式\n  /// * [2] 深色模式\n  static const String kThemeMode = \"ThemeMode\";\n\n  /// DEBUG模式\n  static const String kDebugModeKey = \"DebugMode\";\n\n  /// 弹幕大小\n  static const String kDanmuSize = \"DanmuSize\";\n\n  /// 弹幕速度\n  static const String kDanmuSpeed = \"DanmuSpeed\";\n\n  /// 弹幕区域\n  static const String kDanmuArea = \"DanmuArea\";\n\n  /// 弹幕透明度\n  static const String kDanmuOpacity = \"DanmuOpacity\";\n\n  /// 弹幕描边大小\n  static const String kDanmuStrokeWidth = \"DanmuStrokeWidth\";\n\n  /// 弹幕-屏蔽滚动\n  static const String kDanmuHideScroll = \"DanmuHideScroll\";\n\n  /// 弹幕-屏蔽底部\n  static const String kDanmuHideBottom = \"DanmuHideBottom\";\n\n  /// 弹幕-屏蔽顶部\n  static const String kDanmuHideTop = \"DanmuHideTop\";\n\n  /// 弹幕-顶部边距\n  static const String kDanmuTopMargin = \"DanmuTopMargin\";\n\n  /// 弹幕-底部边距\n  static const String kDanmuBottomMargin = \"DanmuBottomMargin\";\n\n  /// 弹幕开启\n  static const String kDanmuEnable = \"DanmuEnable\";\n\n  /// 弹幕去重\n  static const String kDanmakuMaskEnable = \"DanmakuMaskEnable\";\n\n  /// 弹幕字重\n  static const String kDanmuFontWeight = \"DanmuFontWeight\";\n\n  /// 弹幕去重参数--文本归一化\n  static const String kDanmuTextNormalization = \"DanmuTextNormalization\";\n\n  /// 弹幕去重参数--窗口大小：10s-60s\n  static const String kDanmuWindowMs = \"DanmuWindowMs\";\n\n  /// 弹幕去重参数--开启去重频率限制\n  static const String kDanmuFrequencyControl = \"DanmuFrequencyControl\";\n\n  /// 弹幕去重参数--去重频率限制\n  static const String kDanmuMaxFrequency = \"DanmuMaxFrequency\";\n\n  /// 硬件解码\n  static const String kHardwareDecode = \"HardwareDecode\";\n\n  /// 聊天区文字大小\n  static const String kChatTextSize = \"ChatTextSize\";\n\n  /// 聊天区间隔\n  static const String kChatTextGap = \"ChatTextGap\";\n\n  /// 聊天区-气泡样式\n  static const String kChatBubbleStyle = \"ChatBubbleStyle\";\n\n  /// 播放清晰度，0=低，1=中，2=高\n  static const String kQualityLevel = \"QualityLevel\";\n\n  /// 蜂窝网络下播放清晰度，0=低，1=中，2=高\n  static const String kQualityLevelCellular = \"QualityLevelCellular\";\n\n  /// 开启定时关闭\n  static const String kAutoExitEnable = \"AutoExitEnable\";\n\n  /// 定时关闭时间（分钟）\n  static const String kAutoExitDuration = \"AutoExitDuration\";\n\n  /// 房间内定时关闭时间（分钟）\n  /// 需要一个不同的 key，因为用户在房间内设置的倒计时和全局的可能不同。\n  static const String kRoomAutoExitDuration = \"RoomAutoExitDuration\";\n\n  /// 播放器兼容模式\n  static const String kPlayerCompatMode = \"PlayerCompatMode\";\n\n  /// 播放器后台自动暂停\n  static const String kPlayerAutoPause = \"PlayerAutoPause\";\n\n  /// 播放器缓冲区大小\n  static const String kPlayerBufferSize = \"PlayerBufferSize\";\n\n  /// 播放器强制使用HTTPS\n  static const String kPlayerForceHttps = \"PlayerForceHttps\";\n\n  /// Douyin设置hls优先\n  static const String kDouyinHlsFirst = \"DouyinHlsFirst\";\n\n  /// 自动全屏\n  static const String kAutoFullScreen = \"AutoFullScreen\";\n\n  /// 播放器音量\n  static const String kPlayerVolume = \"PlayerVolume\";\n\n  /// 小窗隐藏弹幕\n  static const String kPIPHideDanmu = \"PIPHideDanmu\";\n\n  /// 哔哩哔哩cookie\n  static const String kBilibiliCookie = \"BilibiliCookie\";\n\n  /// 抖音cookie\n  static const String kDouyinCookie = \"DouyinCookie\";\n\n  ///主题色\n  static const String kStyleColor = \"kStyleColor\";\n\n  ///动态取色\n  static const String kIsDynamic = \"kIsDynamic\";\n\n  /// 自定义字体\n  static const String kCustomFont = \"CustomFont\";\n\n  /// 提示哔哩哔哩登录\n  static const String kBilibiliLoginTip = \"BilibiliLoginTip\";\n\n  /// 日志记录\n  static const String kLogEnable = \"LogEnable\";\n\n  /// Firebase数据分析\n  static const String kFirebaseEnable = \"FirebaseEnable\";\n\n  /// 开启自定义播放器视频输出\n  static const String kCustomPlayerOutput = \"CustomPlayerOutput\";\n\n  /// 视频输出驱动\n  static const String kVideoOutputDriver = \"VideoOutputDriver\";\n\n  /// 视频硬件解码器\n  static const String kVideoHardwareDecoder = \"VideoHardwareDecoder\";\n\n  /// 音频输出驱动\n  static const String kAudioOutputDriver = \"AudioOutputDriver\";\n\n  /// 视频硬件解码器\n  static const String kVideoDoubleBuffering = \"VideoDoubleBuffering\";\n\n  /// 开启自动更新关注\n  static const String kAutoUpdateFollowEnable = \"AutoUpdateFollowEnable\";\n\n  /// 定时自动更新关注间隔（分钟）\n  static const String kUpdateFollowDuration = \"AutoUpdateFollowDuration\";\n\n  /// 开启多线程更新关注\n  static const String kUpdateFollowThreadCount = \"UpdateFollowThreadCount\";\n\n  /// WebDAV_服务器地址\n  static const String kWebDAVUri = \"WebDAVUri\";\n\n  /// WebDAV_文件夹\n  static const String kWebDAVDirectory = \"WebDAVDirectory\";\n\n  /// WebDAV_登录账号\n  static const String kWebDAVUser = \"WebDAVUser\";\n\n  /// WebDAV_登录密码\n  static const String kWebDAVPassword = \"kWebDAVPassword\";\n\n  /// WebDAV_最后一次上传时间\n  static const String kWebDAVLastUploadTime = \"kWebDAVLastUploadTime\";\n\n  /// WebDAV_最后一次备份时间\n  static const String kWebDAVLastRecoverTime = \"kWebDAVLastRecoverTime\";\n\n  /// windows窗口size\n  static const String kWindowX = \"WindowX\";\n\n  static const String kWindowY = \"WindowY\";\n\n  static const String kWindowWidth = \"WindowWidth\";\n\n  static const String kWindowHeight = \"WindowHeight\";\n\n  /// 关注列表排序方法\n  static const String kFollowSortMethod = \"FollowSortMethod\";\n\n  /// 关注列表样式\n  static const String kFollowStyleNotGrid = \"FollowStyleNotGrid\";\n\n  /// 数据库版本\n  static const String kHiveDbVer = \"kHiveDbVer\";\n\n  late Box settingsBox;\n  late Box<String> shieldBox;\n\n  Future init() async {\n    settingsBox = await Hive.openBox(\n      \"LocalStorage\",\n    );\n    shieldBox = await Hive.openBox(\n      \"DanmuShield\",\n    );\n  }\n\n  T getValue<T>(dynamic key, T defaultValue) {\n    try {\n      var value = settingsBox.get(key, defaultValue: defaultValue) as T;\n      Log.d(\"Get LocalStorage：$key\\r\\n$value\");\n      return value;\n    } catch (e) {\n      Log.logPrint(e);\n      return defaultValue;\n    }\n  }\n\n  T? getNullValue<T>(dynamic key, T? defaultValue) {\n    try {\n      var value = settingsBox.get(key, defaultValue: defaultValue) as T?;\n      Log.d(\"Get LocalStorage：$key\\r\\n$value\");\n      return value;\n    } catch (e) {\n      Log.logPrint(e);\n      return defaultValue;\n    }\n  }\n\n  Future setValue<T>(dynamic key, T value) async {\n    Log.d(\"Set LocalStorage：$key\\r\\n$value\");\n    return await settingsBox.put(key, value);\n  }\n\n  Future removeValue<T>(dynamic key) async {\n    Log.d(\"Remove LocalStorage：$key\");\n    return await settingsBox.delete(key);\n  }\n\n  Future flush() async {\n    return await settingsBox.flush();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/migration_service.dart",
    "content": "import 'dart:io';\n\nimport 'package:path/path.dart' as p;\nimport 'package:path_provider/path_provider.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:simple_live_app/services/follow_service.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\n\nclass MigrationService {\n  /// 将Hive数据迁移到Application Support\n  static Future migrateData() async {\n    if (Platform.isAndroid || Platform.isIOS) {\n      return;\n    }\n    var hiveFileList = [\n      \"followuser\",\n      //旧版本写错成hostiry了\n      \"hostiry\",\n      \"followusertag\",\n      \"localstorage\",\n      \"danmushield\",\n    ];\n    try {\n      var newDir = await getApplicationSupportDirectory();\n      var hiveFile = File(p.join(newDir.path, \"followuser.hive\"));\n      if (await hiveFile.exists()) {\n        return;\n      }\n\n      var oldDir = await getApplicationDocumentsDirectory();\n      for (var element in hiveFileList) {\n        var oldFile = File(p.join(oldDir.path, \"$element.hive\"));\n        if (await oldFile.exists()) {\n          var fileName = \"$element.hive\";\n          if (element == \"hostiry\") {\n            fileName = \"history.hive\";\n          }\n          await oldFile.copy(p.join(newDir.path, fileName));\n          await oldFile.delete();\n        }\n        var lockFile = File(p.join(oldDir.path, \"$element.lock\"));\n        if (await lockFile.exists()) {\n          await lockFile.delete();\n        }\n      }\n    } catch (e) {\n      Log.logPrint(e);\n    }\n  }\n\n  /// 数据迁移根据版本：from 1.7.8\n  static Future<void> migrateDataByVersion() async {\n    int curAppVer = Utils.parseVersion(Utils.packageInfo.version);\n    int curDBVer = LocalStorageService.instance\n        .getValue(LocalStorageService.kHiveDbVer, 10708);\n    Log.i(\"curDBVer: $curDBVer, curAppVer: $curAppVer\");\n    if (curDBVer <= 10708) {\n      LocalStorageService.instance.settingsBox\n          .delete(LocalStorageService.kWebDAVLastUploadTime);\n      LocalStorageService.instance.settingsBox\n          .delete(LocalStorageService.kWebDAVLastRecoverTime);\n    }\n    // follow_user 添加 tag属性\n    // 从followUserTag 读取 标签\n    if (curDBVer <= 10709) {\n      List tagList = DBService.instance.tagBox.values.toList();\n      List<FollowUser> followList =\n          DBService.instance.followBox.values.toList();\n      for (int i = 0; i < followList.length; i++) {\n        for (FollowUserTag tag in tagList) {\n          if (tag.userId.contains(followList[i].id)) {\n            followList[i].tag = tag.tag;\n            DBService.instance.addFollow(followList[i]);\n            break;\n          }\n        }\n      }\n    }\n    // sortkey-romanName\n    if (curDBVer <= 10805) {\n       await FollowService.instance.followUserAllDataCheck();\n    }\n    LocalStorageService.instance.settingsBox\n        .put(LocalStorageService.kHiveDbVer, curAppVer);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/signalr_service.dart",
    "content": "import 'dart:async';\nimport 'dart:io';\n\nimport 'package:signalr_netcore/signalr_client.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\n\nenum SignalRConnectionState {\n  connecting,\n  connected,\n  disconnected,\n}\n\nclass SignalRService {\n  static const String kUrl = \"https://sync1.nsapps.cn/sync\";\n\n  SignalRConnectionState state = SignalRConnectionState.connecting;\n\n  final _stateStreamController =\n      StreamController<SignalRConnectionState>.broadcast();\n  Stream<SignalRConnectionState> get stateStream =>\n      _stateStreamController.stream;\n\n  final _onFavoriteStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onFavoriteStream =>\n      _onFavoriteStreamController.stream;\n\n  final _onHistoryStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onHistoryStream =>\n      _onHistoryStreamController.stream;\n\n  final _onShieldWordStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onShieldWordStream =>\n      _onShieldWordStreamController.stream;\n\n  final _onBiliAccountStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onBiliAccountStream =>\n      _onBiliAccountStreamController.stream;\n\n  final _onRoomDestroyedStreamController = StreamController<String>.broadcast();\n  Stream<String> get onRoomDestroyedStream =>\n      _onRoomDestroyedStreamController.stream;\n\n  final _onRoomUserUpdatedStreamController =\n      StreamController<List<RoomUser>>.broadcast();\n  Stream<List<RoomUser>> get onRoomUserUpdatedStream =>\n      _onRoomUserUpdatedStreamController.stream;\n\n  HubConnection? hubConnection;\n  Future<void> connect() async {\n    hubConnection = HubConnectionBuilder().withUrl(kUrl).build();\n    hubConnection!.onclose(({Exception? error}) {\n      state = SignalRConnectionState.disconnected;\n      _stateStreamController.add(state);\n    });\n    hubConnection!.onreconnected(({String? connectionId}) {\n      Log.d(\"reconnected: $connectionId\");\n      state = SignalRConnectionState.connected;\n      _stateStreamController.add(state);\n    });\n    await hubConnection!.start();\n    state = SignalRConnectionState.connected;\n    _stateStreamController.add(state);\n    _listen();\n  }\n\n  void _listen() {\n    hubConnection?.on(\"onFavoriteReceived\", (args) {\n      _onFavoriteStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onHistoryReceived\", (args) {\n      _onHistoryStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onShieldWordReceived\", (args) {\n      _onShieldWordStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onBiliAccountReceived\", (args) {\n      _onBiliAccountStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onRoomDestroyed\", (args) {\n      _onRoomDestroyedStreamController.add(args![0].toString());\n    });\n    hubConnection?.on(\"onUserUpdated\", (args) {\n      var list = (args![0] as List).map((e) => RoomUser.fromObject(e)).toList();\n      _onRoomUserUpdatedStreamController.add(list);\n    });\n  }\n\n  Future<void> disconnect() async {\n    await hubConnection?.stop();\n    state = SignalRConnectionState.disconnected;\n    _stateStreamController.add(state);\n  }\n\n  Future<Resp<String>> createRoom() async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    String app = \"Slive\";\n    String platform = Platform.operatingSystem;\n    String version = Utils.packageInfo.version;\n    var resp = await hubConnection\n        ?.invoke(\"CreateRoom\", args: [app, platform, version]);\n    return Resp<String>.fromObject(resp);\n  }\n\n  Future<Resp> joinRoom(String roomId) async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    String app = \"Simple Live\";\n    String platform = Platform.operatingSystem;\n    String version = Utils.packageInfo.version;\n    var resp = await hubConnection\n        ?.invoke(\"JoinRoom\", args: [roomId, app, platform, version]);\n    return Resp.fromObject(resp);\n  }\n\n  Future<Resp> sendContent({\n    required String roomName,\n    required String action,\n    required bool overlay,\n    required String content,\n  }) async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    var resp =\n        await hubConnection?.invoke(action, args: [roomName, overlay, content]);\n    return Resp.fromObject(resp);\n  }\n\n  void dispose() {\n    _stateStreamController.close();\n    _onFavoriteStreamController.close();\n    _onHistoryStreamController.close();\n    _onShieldWordStreamController.close();\n    _onBiliAccountStreamController.close();\n    _onRoomDestroyedStreamController.close();\n    _onRoomUserUpdatedStreamController.close();\n\n    hubConnection?.stop();\n  }\n}\n\nclass Resp<T> {\n  final bool isSuccess;\n  final String message;\n  final T? data;\n  Resp(this.isSuccess, this.message, this.data);\n\n  factory Resp.fromJson(Map<String, dynamic> json) {\n    return Resp(\n      json['isSuccess'],\n      json['message'] ?? \"\",\n      json['data'],\n    );\n  }\n\n  factory Resp.fromObject(Object? obj) {\n    if (obj is Map<String, dynamic>) {\n      return Resp.fromJson(obj);\n    }\n    return Resp(false, \"unknown\", null);\n  }\n}\n\nclass RoomUser {\n  final String connectionId;\n  final String shortId;\n  final String platform;\n  final String version;\n  final String app;\n  final bool? isCreator;\n\n  RoomUser({\n    required this.connectionId,\n    required this.shortId,\n    required this.platform,\n    required this.version,\n    required this.app,\n    this.isCreator = false,\n  });\n\n  factory RoomUser.fromJson(Map<String, dynamic> json) {\n    return RoomUser(\n      connectionId: json['connectionId'],\n      shortId: json['shortId'],\n      platform: json['platform'],\n      version: json['version'],\n      app: json['app'],\n      isCreator: json['isCreator'],\n    );\n  }\n\n  factory RoomUser.fromObject(Object? obj) {\n    if (obj is Map<String, dynamic>) {\n      return RoomUser.fromJson(obj);\n    }\n    return RoomUser(\n      connectionId: \"\",\n      shortId: \"\",\n      platform: \"\",\n      version: \"\",\n      app: \"\",\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/sync_service.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:network_info_plus/network_info_plus.dart';\nimport 'package:simple_live_app/app/constant.dart';\nimport 'package:simple_live_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_app/app/event_bus.dart';\nimport 'package:simple_live_app/app/log.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/models/db/follow_user_tag.dart';\nimport 'package:simple_live_app/models/db/history.dart';\nimport 'package:simple_live_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_app/services/db_service.dart';\nimport 'package:udp/udp.dart';\nimport 'package:shelf/shelf.dart' as shelf;\nimport 'package:shelf/shelf_io.dart' as shelf_io;\nimport 'package:shelf_router/shelf_router.dart';\nimport 'package:uuid/uuid.dart';\n\nclass SyncService extends GetxService {\n  static SyncService get instance => Get.find<SyncService>();\n\n  UDP? udp;\n  RxList<SyncClinet> scanClients = <SyncClinet>[].obs;\n  static const int udpPort = 23235;\n  static const int httpPort = 23234;\n  DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n  NetworkInfo networkInfo = NetworkInfo();\n  HttpServer? server;\n  var ipAddress = \"\".obs;\n  var httpRunning = false.obs;\n  var httpErrorMsg = \"\".obs;\n\n  var deviceId = \"\";\n\n  @override\n  void onInit() {\n    Log.d('TVService init');\n    deviceId = (const Uuid().v4()).split('-').first;\n    listenUDP();\n    initServer();\n    super.onInit();\n  }\n\n  /// 监听其他端UDP广播的回复\n  void listenUDP() async {\n    udp = await UDP.bind(Endpoint.any(port: const Port(udpPort)));\n    udp!.asStream().listen(listenUdp);\n  }\n\n  void listenUdp(Datagram? datagram) {\n    var str = String.fromCharCodes(datagram!.data);\n    Log.i(\"Received: $str from ${datagram.address}:${datagram.port}\");\n    if (str.startsWith('{') && str.endsWith('}')) {\n      var data = json.decode(str);\n      //如果是自己的广播，就不处理\n      if (data['id'] == deviceId) {\n        return;\n      }\n      //处理Hello的广播\n      if (data[\"type\"] == \"hello\") {\n        //如果http服务已经启动，就回复自己的信息\n        if (httpRunning.value) {\n          sendInfo();\n        }\n        return;\n      }\n      // 处理其他端的广播\n      // 地址直接从datagram中获取，能收到回复说明地址是可以连通的\n      var address = datagram.address.address;\n      //检查是否已经存在\n      var index =\n          scanClients.indexWhere((element) => element.address == address);\n      if (index == -1) {\n        scanClients.add(\n          SyncClinet(\n            id: data['id'],\n            name: data['name'],\n            address: address,\n            port: httpPort,\n            type: data['type'],\n          ),\n        );\n      }\n    }\n  }\n\n  /// 发送UDP广播至其他端\n  void sendHello() async {\n    await udp!.send(\n      json.encode({\n        \"id\": deviceId,\n        \"type\": \"hello\",\n      }).codeUnits,\n      Endpoint.broadcast(\n        port: const Port(udpPort),\n      ),\n    );\n    Log.i(\"send udp: hello\");\n  }\n\n  /// UDP广播自身信息\n  void sendInfo() async {\n    //var ip = await getLocalIP();\n\n    var name = await getDeviceName();\n\n    var data = {\n      \"id\": deviceId,\n      \"type\": Platform.operatingSystem,\n      //'version': Utils.packageInfo.version,\n      \"name\": name,\n      //\"address\": ip,\n      //\"port\": httpPort,\n    };\n\n    await udp!.send(\n      json.encode(data).codeUnits,\n      Endpoint.broadcast(\n        port: const Port(udpPort),\n      ),\n    );\n    Log.i(\"send udp info: $data\");\n  }\n\n  Future<String> getDeviceName() async {\n    var name = \"SimpleLive-${Platform.operatingSystem}\";\n    if (Platform.isAndroid) {\n      var info = await deviceInfo.androidInfo;\n      name = info.model;\n    } else if (Platform.isIOS) {\n      var info = await deviceInfo.iosInfo;\n      name = info.name;\n    } else if (Platform.isMacOS) {\n      var info = await deviceInfo.macOsInfo;\n      name = info.computerName;\n    } else if (Platform.isLinux) {\n      var info = await deviceInfo.linuxInfo;\n      name = info.name;\n    } else if (Platform.isWindows) {\n      var info = await deviceInfo.windowsInfo;\n      name = info.userName;\n    }\n    return name;\n  }\n\n  void refreshClients() {\n    scanClients.clear();\n    sendHello();\n  }\n\n  /// 读取本地IP\n  /// - 如果是wifi，直接获取wifi的IP\n  /// - 如果是有线，获取所有的IP，找到全部的IP\n  Future<String> getLocalIP() async {\n    String? ip = \"\";\n    try {\n      ip = await networkInfo.getWifiIP();\n    } catch (e) {\n      Log.logPrint(e);\n    }\n    try {\n      if (ip == null || ip.isEmpty) {\n        var interfaces = await NetworkInterface.list();\n        var ipList = <String>[];\n        for (var interface in interfaces) {\n          for (var addr in interface.addresses) {\n            if (addr.type.name == 'IPv4' &&\n                !addr.address.startsWith('127') &&\n                !addr.isMulticast &&\n                !addr.isLoopback) {\n              ipList.add(addr.address);\n              break;\n            }\n          }\n        }\n        ip = ipList.join(';');\n      }\n    } catch (e) {\n      Log.logPrint(e);\n    }\n    return ip ?? \"\";\n  }\n\n  /// 初始化HTTP服务\n  void initServer() async {\n    try {\n      var serverRouter = Router();\n      serverRouter.get('/', _helloRequest);\n      serverRouter.get('/info', _infoRequest);\n      serverRouter.post('/sync/follow', _syncFollowUserReuqest);\n      serverRouter.post('/sync/tag', _syncFollowUserTagRequest);\n      serverRouter.post('/sync/history', _syncHistoryReuqest);\n      serverRouter.post('/sync/blocked_word', _syncBlockedWordReuqest);\n      serverRouter.post('/sync/account/bilibili', _syncBiliAccountReuqest);\n\n      var server = await shelf_io.serve(\n        serverRouter.call,\n        InternetAddress.anyIPv4,\n        httpPort,\n      );\n\n      // Enable content compression\n      server.autoCompress = true;\n\n      httpRunning.value = true;\n\n      var ip = await getLocalIP();\n      ipAddress.value = ip;\n\n      Log.d('Serving at http://$ip:${server.port}');\n    } catch (e) {\n      httpErrorMsg.value = e.toString();\n      Log.logPrint(e);\n    }\n  }\n\n  /// 测试服务能否正常访问\n  shelf.Response _helloRequest(shelf.Request request) {\n    return toJsonResponse({\n      'status': true,\n      'message': 'http server is running...',\n      \"version\":\n          'SimpeLive ${Platform.operatingSystem} v${Utils.packageInfo.version}',\n    });\n  }\n\n  /// 发送自己的信息\n  Future<shelf.Response> _infoRequest(shelf.Request request) async {\n    var name = await getDeviceName();\n    return toJsonResponse({\n      \"id\": deviceId,\n      'type': Platform.operatingSystem,\n      'name': name,\n      'version': Utils.packageInfo.version,\n      'address': ipAddress.value,\n      'port': httpPort,\n    });\n  }\n\n  /// 同步关注用户列表\n  Future<shelf.Response> _syncFollowUserReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n\n      var body = await request.readAsString();\n      Log.d('_syncFollowUserReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        await DBService.instance.followBox.clear();\n      }\n      for (var item in jsonBody) {\n        var user = FollowUser.fromJson(item);\n        await DBService.instance.followBox.put(user.id, user);\n      }\n\n      SmartDialog.showToast('已同步关注用户列表');\n      EventBus.instance.emit(Constant.kUpdateFollow, 0);\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步标签列表\n  Future<shelf.Response> _syncFollowUserTagRequest(\n      shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n\n      var body = await request.readAsString();\n      Log.d('_syncFollowUserTagRequest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        await DBService.instance.tagBox.clear();\n      }\n      for (var item in jsonBody) {\n        var tag = FollowUserTag.fromJson(item);\n        await DBService.instance.tagBox.put(tag.id, tag);\n      }\n\n      SmartDialog.showToast('已同步标签列表');\n      EventBus.instance.emit(Constant.kUpdateFollow, 0);\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步观看记录\n  Future<shelf.Response> _syncHistoryReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n      var body = await request.readAsString();\n      Log.d('_syncFollowUserReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        await DBService.instance.historyBox.clear();\n      }\n      for (var item in jsonBody) {\n        var history = History.fromJson(item);\n        if (DBService.instance.historyBox.containsKey(history.id)) {\n          var old = DBService.instance.historyBox.get(history.id);\n          //如果本地的更新时间比较新，就不更新\n          if (old!.updateTime.isAfter(history.updateTime)) {\n            continue;\n          }\n        }\n        await DBService.instance.addOrUpdateHistory(history);\n      }\n\n      SmartDialog.showToast('已同步观看记录');\n      EventBus.instance.emit(Constant.kUpdateHistory, 0);\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步弹幕屏蔽词\n  Future<shelf.Response> _syncBlockedWordReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n      var body = await request.readAsString();\n      Log.d('_syncBlockedWordReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        AppSettingsController.instance.clearShieldList();\n      }\n      for (var keyword in jsonBody) {\n        AppSettingsController.instance.addShieldList(keyword.trim());\n      }\n      SmartDialog.showToast('已同步弹幕屏蔽词');\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步哔哩哔哩账号\n  Future<shelf.Response> _syncBiliAccountReuqest(shelf.Request request) async {\n    try {\n      var body = await request.readAsString();\n      Log.d('_syncBiliAccountReuqest: $body');\n      var jsonBody = json.decode(body);\n      var cookie = jsonBody['cookie'];\n      BiliBiliAccountService.instance.setCookie(cookie);\n      BiliBiliAccountService.instance.loadUserInfo();\n      SmartDialog.showToast('已同步哔哩哔哩账号');\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  shelf.Response toJsonResponse(Map<String, dynamic> data) {\n    return shelf.Response.ok(\n      json.encode(data),\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      encoding: Encoding.getByName('utf-8'),\n    );\n  }\n\n  @override\n  void onClose() {\n    Log.d('SyncService close');\n    udp?.close();\n    server?.close(force: true);\n    super.onClose();\n  }\n}\n\nclass SyncClinet {\n  final String id;\n  final String name;\n  final String address;\n  final int port;\n  final String type;\n  SyncClinet({\n    required this.id,\n    required this.name,\n    required this.address,\n    required this.port,\n    required this.type,\n  });\n}\n"
  },
  {
    "path": "simple_live_app/lib/services/window_service.dart",
    "content": "import 'dart:io';\nimport 'dart:ui';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/services/local_storage_service.dart';\nimport 'package:window_manager/window_manager.dart';\n\nclass WindowService extends GetxService implements WindowListener {\n  static WindowService get instance => Get.find<WindowService>();\n\n  bool isPIP = false;\n\n  WindowService() {\n    windowManager.addListener(this);\n  }\n\n  Future<void> init() async {\n    await resize();\n    WindowOptions windowOptions = WindowOptions(\n      minimumSize: Size(280, 280),\n      center: false,\n      title: \"Slive\",\n    );\n    windowManager.waitUntilReadyToShow(windowOptions, () async {\n      await windowManager.show();\n      await windowManager.focus();\n    });\n  }\n\n  Future<void> resize() async {\n    // 初始分辨率默认 1920×1080\n    final width = LocalStorageService.instance\n        .getValue(LocalStorageService.kWindowWidth, 1280.0);\n    final height = LocalStorageService.instance\n        .getValue(LocalStorageService.kWindowHeight, 720.0);\n    final x = LocalStorageService.instance\n        .getValue(LocalStorageService.kWindowX, 320.0);\n    final y = LocalStorageService.instance\n        .getValue(LocalStorageService.kWindowY, 180.0);\n    windowManager.setBounds(Rect.fromLTWH(x, y, width, height));\n  }\n\n  @override\n  void onWindowBlur() {}\n\n  @override\n  void onWindowClose() {\n    if (Platform.isLinux) {\n      exit(0);\n    }\n  }\n\n  @override\n  void onWindowDocked() {}\n\n  @override\n  void onWindowEnterFullScreen() {}\n\n  @override\n  void onWindowEvent(String eventName) {}\n\n  @override\n  void onWindowFocus() {}\n\n  @override\n  void onWindowLeaveFullScreen() {}\n\n  @override\n  void onWindowMaximize() {}\n\n  @override\n  void onWindowMinimize() {}\n\n  @override\n  Future<void> onWindowMove() async {}\n\n  @override\n  Future<void> onWindowMoved() async {\n    if (!isPIP) {\n      final bounds = await windowManager.getBounds();\n      _saveBounds(bounds);\n    }\n  }\n\n  @override\n  Future<void> onWindowResize() async {}\n\n  @override\n  Future<void> onWindowResized() async {\n    if (!isPIP) {\n      final bounds = await windowManager.getBounds();\n      _saveBounds(bounds);\n    }\n  }\n\n  @override\n  void onWindowRestore() {}\n\n  @override\n  void onWindowUndocked() {}\n\n  @override\n  void onWindowUnmaximize() {}\n\n  void _saveBounds(Rect bounds) {\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kWindowX, bounds.left);\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kWindowY, bounds.top);\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kWindowWidth, bounds.width);\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kWindowHeight, bounds.height);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/src/rust/api/danmaku_mask.dart",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import\n\nimport '../frb_generated.dart';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';\n\n// These functions are ignored because they are not marked as `pub`: `adapt_window`, `normalize`, `shift_if_needed`\n\n// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>\nabstract class DanmakuMask implements RustOpaqueInterface {\n  /// 批量判断是否允许\n  /// 返回 Vec<u8>：1 = 允许，0 = 屏蔽\n  Future<Uint8List> allowListBatch(\n      {required List<String> texts, required BigInt nowMs});\n\n  @override\n  void dispose();\n\n  /// 构造函数（会生成 Dart 构造器）\n  factory DanmakuMask(\n          {required int baseWindowMs,\n          required int bucketCount,\n          required bool useNormalization,\n          required bool useFrequencyControl,\n          required int maxFrequency,\n          required bool adaptiveWindow}) =>\n      RustLib.instance.api.crateApiDanmakuMaskDanmakuMaskNew(\n          baseWindowMs: baseWindowMs,\n          bucketCount: bucketCount,\n          useNormalization: useNormalization,\n          useFrequencyControl: useFrequencyControl,\n          maxFrequency: maxFrequency,\n          adaptiveWindow: adaptiveWindow);\n\n  /// 重置状态\n  void reset();\n}\n"
  },
  {
    "path": "simple_live_app/lib/src/rust/api/simple.dart",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import\n\nimport '../frb_generated.dart';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';\n\n// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `SINGLETON_MASK`\n// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `deref`, `initialize`\n"
  },
  {
    "path": "simple_live_app/lib/src/rust/frb_generated.dart",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field\n\nimport 'api/danmaku_mask.dart';\nimport 'dart:async';\nimport 'dart:convert';\nimport 'frb_generated.dart';\nimport 'frb_generated.io.dart'\n    if (dart.library.js_interop) 'frb_generated.web.dart';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';\n\n/// Main entrypoint of the Rust API\nclass RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {\n  @internal\n  static final instance = RustLib._();\n\n  RustLib._();\n\n  /// Initialize flutter_rust_bridge\n  static Future<void> init({\n    RustLibApi? api,\n    BaseHandler? handler,\n    ExternalLibrary? externalLibrary,\n    bool forceSameCodegenVersion = true,\n  }) async {\n    await instance.initImpl(\n      api: api,\n      handler: handler,\n      externalLibrary: externalLibrary,\n      forceSameCodegenVersion: forceSameCodegenVersion,\n    );\n  }\n\n  /// Initialize flutter_rust_bridge in mock mode.\n  /// No libraries for FFI are loaded.\n  static void initMock({\n    required RustLibApi api,\n  }) {\n    instance.initMockImpl(\n      api: api,\n    );\n  }\n\n  /// Dispose flutter_rust_bridge\n  ///\n  /// The call to this function is optional, since flutter_rust_bridge (and everything else)\n  /// is automatically disposed when the app stops.\n  static void dispose() => instance.disposeImpl();\n\n  @override\n  ApiImplConstructor<RustLibApiImpl, RustLibWire> get apiImplConstructor =>\n      RustLibApiImpl.new;\n\n  @override\n  WireConstructor<RustLibWire> get wireConstructor =>\n      RustLibWire.fromExternalLibrary;\n\n  @override\n  Future<void> executeRustInitializers() async {\n    await api.crateApiSimpleInitApp();\n  }\n\n  @override\n  ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig =>\n      kDefaultExternalLibraryLoaderConfig;\n\n  @override\n  String get codegenVersion => '2.11.1';\n\n  @override\n  int get rustContentHash => -1540820557;\n\n  static const kDefaultExternalLibraryLoaderConfig =\n      ExternalLibraryLoaderConfig(\n    stem: 'rust_lib_simple_live_app',\n    ioDirectory: 'rust/target/release/',\n    webPrefix: 'pkg/',\n  );\n}\n\nabstract class RustLibApi extends BaseApi {\n  Future<Uint8List> crateApiDanmakuMaskDanmakuMaskAllowListBatch(\n      {required DanmakuMask that,\n      required List<String> texts,\n      required BigInt nowMs});\n\n  void crateApiDanmakuMaskDanmakuMaskDispose({required DanmakuMask that});\n\n  DanmakuMask crateApiDanmakuMaskDanmakuMaskNew(\n      {required int baseWindowMs,\n      required int bucketCount,\n      required bool useNormalization,\n      required bool useFrequencyControl,\n      required int maxFrequency,\n      required bool adaptiveWindow});\n\n  void crateApiDanmakuMaskDanmakuMaskReset({required DanmakuMask that});\n\n  Future<void> crateApiSimpleInitApp();\n\n  RustArcIncrementStrongCountFnType\n      get rust_arc_increment_strong_count_DanmakuMask;\n\n  RustArcDecrementStrongCountFnType\n      get rust_arc_decrement_strong_count_DanmakuMask;\n\n  CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_DanmakuMaskPtr;\n}\n\nclass RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {\n  RustLibApiImpl({\n    required super.handler,\n    required super.wire,\n    required super.generalizedFrbRustBinding,\n    required super.portManager,\n  });\n\n  @override\n  Future<Uint8List> crateApiDanmakuMaskDanmakuMaskAllowListBatch(\n      {required DanmakuMask that,\n      required List<String> texts,\n      required BigInt nowMs}) {\n    return handler.executeNormal(NormalTask(\n      callFfi: (port_) {\n        final serializer = SseSerializer(generalizedFrbRustBinding);\n        sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n            that, serializer);\n        sse_encode_list_String(texts, serializer);\n        sse_encode_u_64(nowMs, serializer);\n        pdeCallFfi(generalizedFrbRustBinding, serializer,\n            funcId: 1, port: port_);\n      },\n      codec: SseCodec(\n        decodeSuccessData: sse_decode_list_prim_u_8_strict,\n        decodeErrorData: null,\n      ),\n      constMeta: kCrateApiDanmakuMaskDanmakuMaskAllowListBatchConstMeta,\n      argValues: [that, texts, nowMs],\n      apiImpl: this,\n    ));\n  }\n\n  TaskConstMeta get kCrateApiDanmakuMaskDanmakuMaskAllowListBatchConstMeta =>\n      const TaskConstMeta(\n        debugName: \"DanmakuMask_allow_list_batch\",\n        argNames: [\"that\", \"texts\", \"nowMs\"],\n      );\n\n  @override\n  void crateApiDanmakuMaskDanmakuMaskDispose({required DanmakuMask that}) {\n    return handler.executeSync(SyncTask(\n      callFfi: () {\n        final serializer = SseSerializer(generalizedFrbRustBinding);\n        sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n            that, serializer);\n        return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 2)!;\n      },\n      codec: SseCodec(\n        decodeSuccessData: sse_decode_unit,\n        decodeErrorData: null,\n      ),\n      constMeta: kCrateApiDanmakuMaskDanmakuMaskDisposeConstMeta,\n      argValues: [that],\n      apiImpl: this,\n    ));\n  }\n\n  TaskConstMeta get kCrateApiDanmakuMaskDanmakuMaskDisposeConstMeta =>\n      const TaskConstMeta(\n        debugName: \"DanmakuMask_dispose\",\n        argNames: [\"that\"],\n      );\n\n  @override\n  DanmakuMask crateApiDanmakuMaskDanmakuMaskNew(\n      {required int baseWindowMs,\n      required int bucketCount,\n      required bool useNormalization,\n      required bool useFrequencyControl,\n      required int maxFrequency,\n      required bool adaptiveWindow}) {\n    return handler.executeSync(SyncTask(\n      callFfi: () {\n        final serializer = SseSerializer(generalizedFrbRustBinding);\n        sse_encode_u_32(baseWindowMs, serializer);\n        sse_encode_u_16(bucketCount, serializer);\n        sse_encode_bool(useNormalization, serializer);\n        sse_encode_bool(useFrequencyControl, serializer);\n        sse_encode_u_16(maxFrequency, serializer);\n        sse_encode_bool(adaptiveWindow, serializer);\n        return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 3)!;\n      },\n      codec: SseCodec(\n        decodeSuccessData:\n            sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask,\n        decodeErrorData: null,\n      ),\n      constMeta: kCrateApiDanmakuMaskDanmakuMaskNewConstMeta,\n      argValues: [\n        baseWindowMs,\n        bucketCount,\n        useNormalization,\n        useFrequencyControl,\n        maxFrequency,\n        adaptiveWindow\n      ],\n      apiImpl: this,\n    ));\n  }\n\n  TaskConstMeta get kCrateApiDanmakuMaskDanmakuMaskNewConstMeta =>\n      const TaskConstMeta(\n        debugName: \"DanmakuMask_new\",\n        argNames: [\n          \"baseWindowMs\",\n          \"bucketCount\",\n          \"useNormalization\",\n          \"useFrequencyControl\",\n          \"maxFrequency\",\n          \"adaptiveWindow\"\n        ],\n      );\n\n  @override\n  void crateApiDanmakuMaskDanmakuMaskReset({required DanmakuMask that}) {\n    return handler.executeSync(SyncTask(\n      callFfi: () {\n        final serializer = SseSerializer(generalizedFrbRustBinding);\n        sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n            that, serializer);\n        return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 4)!;\n      },\n      codec: SseCodec(\n        decodeSuccessData: sse_decode_unit,\n        decodeErrorData: null,\n      ),\n      constMeta: kCrateApiDanmakuMaskDanmakuMaskResetConstMeta,\n      argValues: [that],\n      apiImpl: this,\n    ));\n  }\n\n  TaskConstMeta get kCrateApiDanmakuMaskDanmakuMaskResetConstMeta =>\n      const TaskConstMeta(\n        debugName: \"DanmakuMask_reset\",\n        argNames: [\"that\"],\n      );\n\n  @override\n  Future<void> crateApiSimpleInitApp() {\n    return handler.executeNormal(NormalTask(\n      callFfi: (port_) {\n        final serializer = SseSerializer(generalizedFrbRustBinding);\n        pdeCallFfi(generalizedFrbRustBinding, serializer,\n            funcId: 5, port: port_);\n      },\n      codec: SseCodec(\n        decodeSuccessData: sse_decode_unit,\n        decodeErrorData: null,\n      ),\n      constMeta: kCrateApiSimpleInitAppConstMeta,\n      argValues: [],\n      apiImpl: this,\n    ));\n  }\n\n  TaskConstMeta get kCrateApiSimpleInitAppConstMeta => const TaskConstMeta(\n        debugName: \"init_app\",\n        argNames: [],\n      );\n\n  RustArcIncrementStrongCountFnType\n      get rust_arc_increment_strong_count_DanmakuMask => wire\n          .rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask;\n\n  RustArcDecrementStrongCountFnType\n      get rust_arc_decrement_strong_count_DanmakuMask => wire\n          .rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask;\n\n  @protected\n  DanmakuMask\n      dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalDcoDecode(raw as List<dynamic>);\n  }\n\n  @protected\n  DanmakuMask\n      dco_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalDcoDecode(raw as List<dynamic>);\n  }\n\n  @protected\n  DanmakuMask\n      dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalDcoDecode(raw as List<dynamic>);\n  }\n\n  @protected\n  String dco_decode_String(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as String;\n  }\n\n  @protected\n  bool dco_decode_bool(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as bool;\n  }\n\n  @protected\n  List<String> dco_decode_list_String(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return (raw as List<dynamic>).map(dco_decode_String).toList();\n  }\n\n  @protected\n  Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as Uint8List;\n  }\n\n  @protected\n  int dco_decode_u_16(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as int;\n  }\n\n  @protected\n  int dco_decode_u_32(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as int;\n  }\n\n  @protected\n  BigInt dco_decode_u_64(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return dcoDecodeU64(raw);\n  }\n\n  @protected\n  int dco_decode_u_8(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return raw as int;\n  }\n\n  @protected\n  void dco_decode_unit(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return;\n  }\n\n  @protected\n  BigInt dco_decode_usize(dynamic raw) {\n    // Codec=Dco (DartCObject based), see doc to use other codecs\n    return dcoDecodeU64(raw);\n  }\n\n  @protected\n  DanmakuMask\n      sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalSseDecode(\n        sse_decode_usize(deserializer), sse_decode_i_32(deserializer));\n  }\n\n  @protected\n  DanmakuMask\n      sse_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalSseDecode(\n        sse_decode_usize(deserializer), sse_decode_i_32(deserializer));\n  }\n\n  @protected\n  DanmakuMask\n      sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return DanmakuMaskImpl.frbInternalSseDecode(\n        sse_decode_usize(deserializer), sse_decode_i_32(deserializer));\n  }\n\n  @protected\n  String sse_decode_String(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    var inner = sse_decode_list_prim_u_8_strict(deserializer);\n    return utf8.decoder.convert(inner);\n  }\n\n  @protected\n  bool sse_decode_bool(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getUint8() != 0;\n  }\n\n  @protected\n  List<String> sse_decode_list_String(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n\n    var len_ = sse_decode_i_32(deserializer);\n    var ans_ = <String>[];\n    for (var idx_ = 0; idx_ < len_; ++idx_) {\n      ans_.add(sse_decode_String(deserializer));\n    }\n    return ans_;\n  }\n\n  @protected\n  Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    var len_ = sse_decode_i_32(deserializer);\n    return deserializer.buffer.getUint8List(len_);\n  }\n\n  @protected\n  int sse_decode_u_16(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getUint16();\n  }\n\n  @protected\n  int sse_decode_u_32(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getUint32();\n  }\n\n  @protected\n  BigInt sse_decode_u_64(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getBigUint64();\n  }\n\n  @protected\n  int sse_decode_u_8(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getUint8();\n  }\n\n  @protected\n  void sse_decode_unit(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n  }\n\n  @protected\n  BigInt sse_decode_usize(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getBigUint64();\n  }\n\n  @protected\n  int sse_decode_i_32(SseDeserializer deserializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    return deserializer.buffer.getInt32();\n  }\n\n  @protected\n  void\n      sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_usize(\n        (self as DanmakuMaskImpl).frbInternalSseEncode(move: true), serializer);\n  }\n\n  @protected\n  void\n      sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_usize(\n        (self as DanmakuMaskImpl).frbInternalSseEncode(move: false),\n        serializer);\n  }\n\n  @protected\n  void\n      sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_usize(\n        (self as DanmakuMaskImpl).frbInternalSseEncode(move: null), serializer);\n  }\n\n  @protected\n  void sse_encode_String(String self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);\n  }\n\n  @protected\n  void sse_encode_bool(bool self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putUint8(self ? 1 : 0);\n  }\n\n  @protected\n  void sse_encode_list_String(List<String> self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_i_32(self.length, serializer);\n    for (final item in self) {\n      sse_encode_String(item, serializer);\n    }\n  }\n\n  @protected\n  void sse_encode_list_prim_u_8_strict(\n      Uint8List self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    sse_encode_i_32(self.length, serializer);\n    serializer.buffer.putUint8List(self);\n  }\n\n  @protected\n  void sse_encode_u_16(int self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putUint16(self);\n  }\n\n  @protected\n  void sse_encode_u_32(int self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putUint32(self);\n  }\n\n  @protected\n  void sse_encode_u_64(BigInt self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putBigUint64(self);\n  }\n\n  @protected\n  void sse_encode_u_8(int self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putUint8(self);\n  }\n\n  @protected\n  void sse_encode_unit(void self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n  }\n\n  @protected\n  void sse_encode_usize(BigInt self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putBigUint64(self);\n  }\n\n  @protected\n  void sse_encode_i_32(int self, SseSerializer serializer) {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    serializer.buffer.putInt32(self);\n  }\n}\n\n@sealed\nclass DanmakuMaskImpl extends RustOpaque implements DanmakuMask {\n  // Not to be used by end users\n  DanmakuMaskImpl.frbInternalDcoDecode(List<dynamic> wire)\n      : super.frbInternalDcoDecode(wire, _kStaticData);\n\n  // Not to be used by end users\n  DanmakuMaskImpl.frbInternalSseDecode(BigInt ptr, int externalSizeOnNative)\n      : super.frbInternalSseDecode(ptr, externalSizeOnNative, _kStaticData);\n\n  static final _kStaticData = RustArcStaticData(\n    rustArcIncrementStrongCount:\n        RustLib.instance.api.rust_arc_increment_strong_count_DanmakuMask,\n    rustArcDecrementStrongCount:\n        RustLib.instance.api.rust_arc_decrement_strong_count_DanmakuMask,\n    rustArcDecrementStrongCountPtr:\n        RustLib.instance.api.rust_arc_decrement_strong_count_DanmakuMaskPtr,\n  );\n\n  /// 批量判断是否允许\n  /// 返回 Vec<u8>：1 = 允许，0 = 屏蔽\n  Future<Uint8List> allowListBatch(\n          {required List<String> texts, required BigInt nowMs}) =>\n      RustLib.instance.api.crateApiDanmakuMaskDanmakuMaskAllowListBatch(\n          that: this, texts: texts, nowMs: nowMs);\n\n  void dispose() => RustLib.instance.api.crateApiDanmakuMaskDanmakuMaskDispose(\n        that: this,\n      );\n\n  /// 重置状态\n  void reset() => RustLib.instance.api.crateApiDanmakuMaskDanmakuMaskReset(\n        that: this,\n      );\n}\n"
  },
  {
    "path": "simple_live_app/lib/src/rust/frb_generated.io.dart",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field\n\nimport 'api/danmaku_mask.dart';\nimport 'dart:async';\nimport 'dart:convert';\nimport 'dart:ffi' as ffi;\nimport 'frb_generated.dart';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';\n\nabstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {\n  RustLibApiImplPlatform({\n    required super.handler,\n    required super.wire,\n    required super.generalizedFrbRustBinding,\n    required super.portManager,\n  });\n\n  CrossPlatformFinalizerArg\n      get rust_arc_decrement_strong_count_DanmakuMaskPtr => wire\n          ._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMaskPtr;\n\n  @protected\n  DanmakuMask\n      dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw);\n\n  @protected\n  DanmakuMask\n      dco_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw);\n\n  @protected\n  DanmakuMask\n      dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          dynamic raw);\n\n  @protected\n  String dco_decode_String(dynamic raw);\n\n  @protected\n  bool dco_decode_bool(dynamic raw);\n\n  @protected\n  List<String> dco_decode_list_String(dynamic raw);\n\n  @protected\n  Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);\n\n  @protected\n  int dco_decode_u_16(dynamic raw);\n\n  @protected\n  int dco_decode_u_32(dynamic raw);\n\n  @protected\n  BigInt dco_decode_u_64(dynamic raw);\n\n  @protected\n  int dco_decode_u_8(dynamic raw);\n\n  @protected\n  void dco_decode_unit(dynamic raw);\n\n  @protected\n  BigInt dco_decode_usize(dynamic raw);\n\n  @protected\n  DanmakuMask\n      sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer);\n\n  @protected\n  DanmakuMask\n      sse_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer);\n\n  @protected\n  DanmakuMask\n      sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          SseDeserializer deserializer);\n\n  @protected\n  String sse_decode_String(SseDeserializer deserializer);\n\n  @protected\n  bool sse_decode_bool(SseDeserializer deserializer);\n\n  @protected\n  List<String> sse_decode_list_String(SseDeserializer deserializer);\n\n  @protected\n  Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);\n\n  @protected\n  int sse_decode_u_16(SseDeserializer deserializer);\n\n  @protected\n  int sse_decode_u_32(SseDeserializer deserializer);\n\n  @protected\n  BigInt sse_decode_u_64(SseDeserializer deserializer);\n\n  @protected\n  int sse_decode_u_8(SseDeserializer deserializer);\n\n  @protected\n  void sse_decode_unit(SseDeserializer deserializer);\n\n  @protected\n  BigInt sse_decode_usize(SseDeserializer deserializer);\n\n  @protected\n  int sse_decode_i_32(SseDeserializer deserializer);\n\n  @protected\n  void\n      sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer);\n\n  @protected\n  void\n      sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer);\n\n  @protected\n  void\n      sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n          DanmakuMask self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_String(String self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_bool(bool self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_list_String(List<String> self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_list_prim_u_8_strict(\n      Uint8List self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_u_16(int self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_u_32(int self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_u_64(BigInt self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_u_8(int self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_unit(void self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_usize(BigInt self, SseSerializer serializer);\n\n  @protected\n  void sse_encode_i_32(int self, SseSerializer serializer);\n}\n\n// Section: wire_class\n\nclass RustLibWire implements BaseWire {\n  factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) =>\n      RustLibWire(lib.ffiDynamicLibrary);\n\n  /// Holds the symbol lookup function.\n  final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)\n      _lookup;\n\n  /// The symbols are looked up in [dynamicLibrary].\n  RustLibWire(ffi.DynamicLibrary dynamicLibrary)\n      : _lookup = dynamicLibrary.lookup;\n\n  void\n      rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n    ffi.Pointer<ffi.Void> ptr,\n  ) {\n    return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n      ptr,\n    );\n  }\n\n  late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMaskPtr =\n      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(\n          'frbgen_simple_live_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask');\n  late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask =\n      _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMaskPtr\n          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();\n\n  void\n      rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n    ffi.Pointer<ffi.Void> ptr,\n  ) {\n    return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n      ptr,\n    );\n  }\n\n  late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMaskPtr =\n      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(\n          'frbgen_simple_live_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask');\n  late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask =\n      _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMaskPtr\n          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();\n}\n"
  },
  {
    "path": "simple_live_app/lib/src/rust/frb_generated.web.dart",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field\n\n\n// Static analysis wrongly picks the IO variant, thus ignore this\n// ignore_for_file: argument_type_not_assignable\n\nimport 'api/danmaku_mask.dart';\nimport 'dart:async';\nimport 'dart:convert';\nimport 'frb_generated.dart';\nimport 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';\n\n\n\n\n                abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {\n                  RustLibApiImplPlatform({\n                    required super.handler,\n                    required super.wire,\n                    required super.generalizedFrbRustBinding,\n                    required super.portManager,\n                  });\n\n                  CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_DanmakuMaskPtr => wire.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask;\n\n\n\n                  @protected DanmakuMask dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(dynamic raw);\n\n@protected DanmakuMask dco_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(dynamic raw);\n\n@protected DanmakuMask dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(dynamic raw);\n\n@protected String dco_decode_String(dynamic raw);\n\n@protected bool dco_decode_bool(dynamic raw);\n\n@protected List<String> dco_decode_list_String(dynamic raw);\n\n@protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);\n\n@protected int dco_decode_u_16(dynamic raw);\n\n@protected int dco_decode_u_32(dynamic raw);\n\n@protected BigInt dco_decode_u_64(dynamic raw);\n\n@protected int dco_decode_u_8(dynamic raw);\n\n@protected void dco_decode_unit(dynamic raw);\n\n@protected BigInt dco_decode_usize(dynamic raw);\n\n@protected DanmakuMask sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(SseDeserializer deserializer);\n\n@protected DanmakuMask sse_decode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(SseDeserializer deserializer);\n\n@protected DanmakuMask sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(SseDeserializer deserializer);\n\n@protected String sse_decode_String(SseDeserializer deserializer);\n\n@protected bool sse_decode_bool(SseDeserializer deserializer);\n\n@protected List<String> sse_decode_list_String(SseDeserializer deserializer);\n\n@protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);\n\n@protected int sse_decode_u_16(SseDeserializer deserializer);\n\n@protected int sse_decode_u_32(SseDeserializer deserializer);\n\n@protected BigInt sse_decode_u_64(SseDeserializer deserializer);\n\n@protected int sse_decode_u_8(SseDeserializer deserializer);\n\n@protected void sse_decode_unit(SseDeserializer deserializer);\n\n@protected BigInt sse_decode_usize(SseDeserializer deserializer);\n\n@protected int sse_decode_i_32(SseDeserializer deserializer);\n\n@protected void sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(DanmakuMask self, SseSerializer serializer);\n\n@protected void sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(DanmakuMask self, SseSerializer serializer);\n\n@protected void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(DanmakuMask self, SseSerializer serializer);\n\n@protected void sse_encode_String(String self, SseSerializer serializer);\n\n@protected void sse_encode_bool(bool self, SseSerializer serializer);\n\n@protected void sse_encode_list_String(List<String> self, SseSerializer serializer);\n\n@protected void sse_encode_list_prim_u_8_strict(Uint8List self, SseSerializer serializer);\n\n@protected void sse_encode_u_16(int self, SseSerializer serializer);\n\n@protected void sse_encode_u_32(int self, SseSerializer serializer);\n\n@protected void sse_encode_u_64(BigInt self, SseSerializer serializer);\n\n@protected void sse_encode_u_8(int self, SseSerializer serializer);\n\n@protected void sse_encode_unit(void self, SseSerializer serializer);\n\n@protected void sse_encode_usize(BigInt self, SseSerializer serializer);\n\n@protected void sse_encode_i_32(int self, SseSerializer serializer);\n                }\n                \n\n\n// Section: wire_class\n\nclass RustLibWire implements BaseWire {\n            RustLibWire.fromExternalLibrary(ExternalLibrary lib);\n\n            void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(int ptr) => wasmModule.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(ptr);\n\nvoid rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(int ptr) => wasmModule.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(ptr);\n        }\n        @JS('wasm_bindgen') external RustLibWasmModule get wasmModule;\n\n        @JS() @anonymous extension type RustLibWasmModule._(JSObject _) implements JSObject {\n            external void rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(int ptr);\n\nexternal void rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(int ptr);\n        }\n        "
  },
  {
    "path": "simple_live_app/lib/widgets/desktop_refresh_button.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass DesktopRefreshButton extends StatelessWidget {\n  final bool refreshing;\n  final Function()? onPressed;\n  const DesktopRefreshButton(\n      {required this.refreshing, this.onPressed, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      decoration: BoxDecoration(\n        color: Theme.of(context).cardColor,\n        borderRadius: AppStyle.radius48,\n        boxShadow: [\n          BoxShadow(\n            color: Colors.grey.withAlpha(50),\n            blurRadius: 4,\n          ),\n        ],\n      ),\n      width: 40,\n      height: 40,\n      child: refreshing\n          ? const Center(\n              child: SizedBox(\n                width: 20,\n                height: 20,\n                child: CircularProgressIndicator(\n                  strokeWidth: 2,\n                ),\n              ),\n            )\n          : IconButton(\n              onPressed: onPressed,\n              icon: const Icon(Icons.refresh),\n            ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/filter_button.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass FilterButton extends StatelessWidget {\n  final bool selected;\n  final String text;\n  final Function()? onTap;\n  const FilterButton({\n    this.selected = false,\n    required this.text,\n    this.onTap,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return InkWell(\n      borderRadius: AppStyle.radius24,\n      onTap: onTap,\n      child: Container(\n        padding: AppStyle.edgeInsetsH12.copyWith(top: 4, bottom: 4),\n        decoration: BoxDecoration(\n          border: Border.all(\n              color: selected\n                  ? Theme.of(context).textTheme.bodyMedium!.color!\n                  : Colors.grey),\n          borderRadius: AppStyle.radius24,\n        ),\n        child: Text(\n          text,\n          style: selected\n              ? Theme.of(context).textTheme.bodyMedium\n              : Theme.of(context).textTheme.bodyMedium!.copyWith(\n                    color: Colors.grey,\n                  ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/follow_user_item.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/models/db/follow_user.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'dart:ui' as ui;\n\nclass FollowUserItem extends StatelessWidget {\n  final FollowUser item;\n  final Function()? onRemove;\n  final Function()? onTap;\n  final Function()? onLongPress;\n  final bool playing;\n  const FollowUserItem({\n    required this.item,\n    this.onRemove,\n    this.onTap,\n    this.onLongPress,\n    this.playing = false,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    var site = Sites.allSites[item.siteId]!;\n    return ListTile(\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 4),\n      leading: NetImage(\n        item.face,\n        width: 48,\n        height: 48,\n        borderRadius: 24,\n      ),\n      title: Text.rich(\n        TextSpan(\n          text: item.remark?.isNotEmpty == true ? item.remark : item.userName,\n          children: [\n            WidgetSpan(\n              alignment: ui.PlaceholderAlignment.middle,\n              child: Obx(\n                () => Offstage(\n                  offstage: item.liveStatus.value == 0,\n                  child: Row(\n                    mainAxisSize: MainAxisSize.min,\n                    children: [\n                      AppStyle.hGap12,\n                      Container(\n                        width: 8,\n                        height: 8,\n                        decoration: BoxDecoration(\n                          color: item.liveStatus.value == 2\n                              ? Colors.green\n                              : Colors.grey,\n                          borderRadius: AppStyle.radius12,\n                        ),\n                      ),\n                      AppStyle.hGap4,\n                      Text(\n                        getStatus(item.liveStatus.value),\n                        style: TextStyle(\n                          fontSize: 12,\n                          fontWeight: FontWeight.normal,\n                          color:\n                              item.liveStatus.value == 2 ? null : Colors.grey,\n                        ),\n                      ),\n                    ],\n                  ),\n                ),\n              ),\n            ),\n          ],\n        ),\n      ),\n      subtitle: Wrap(\n        runSpacing: 1.0,\n        children: [\n          Image.asset(\n            site.logo,\n            width: 20,\n          ),\n          AppStyle.hGap4,\n          Text(\n            site.name,\n            style: const TextStyle(\n              fontSize: 12,\n              color: Colors.grey,\n            ),\n          ),\n          AppStyle.hGap4,\n          Text(\n            item.watchDuration ?? \"00:00:00\",\n            style: const TextStyle(\n              fontSize: 12,\n              color: Colors.grey,\n            ),\n          ),\n          AppStyle.hGap4,\n          Text(\n            item.tag.length > 8 ? '${item.tag.substring(0, 8)}...' : item.tag,\n            style: const TextStyle(\n              fontSize: 12,\n              color: Colors.grey,\n            ),\n            maxLines: 1,\n            overflow: TextOverflow.ellipsis,\n          ),\n        ],\n      ),\n      trailing: playing\n          ? const SizedBox(\n              width: 64,\n              child: Center(\n                child: Icon(\n                  Icons.play_arrow,\n                ),\n              ),\n            )\n          : (onRemove == null\n              ? null\n              : IconButton(\n                  onPressed: () {\n                    onRemove?.call();\n                  },\n                  icon: const Icon(Remix.dislike_line),\n                )),\n      onTap: onTap,\n      onLongPress: onLongPress,\n    );\n  }\n\n  String getStatus(int status) {\n    if (status == 0) {\n      return \"读取中\";\n    } else if (status == 1) {\n      return \"未开播\";\n    } else {\n      return \"直播中\";\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/keep_alive_wrapper.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass KeepAliveWrapper extends StatefulWidget {\n  final Widget child;\n\n  const KeepAliveWrapper({super.key, required this.child});\n\n  @override\n  State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();\n}\n\nclass _KeepAliveWrapperState extends State<KeepAliveWrapper>\n    with AutomaticKeepAliveClientMixin {\n  @override\n  Widget build(BuildContext context) {\n    super.build(context);\n    return widget.child;\n  }\n\n  @override\n  bool get wantKeepAlive => true;\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/live_room_card.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/sites.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/routes/app_navigation.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_app/widgets/shadow_card.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass LiveRoomCard extends StatelessWidget {\n  final Site site;\n  final LiveRoomItem item;\n  final Function()? onLongPress;\n  const LiveRoomCard(this.site, this.item, {super.key, this.onLongPress});\n\n  @override\n  Widget build(BuildContext context) {\n    return ShadowCard(\n      onTap: () {\n        AppNavigator.toLiveRoomDetail(site: site, roomId: item.roomId);\n      },\n      onLongPress: onLongPress,\n      child: Column(\n        crossAxisAlignment: CrossAxisAlignment.start,\n        children: [\n          Stack(\n            children: [\n              ClipRRect(\n                borderRadius: const BorderRadius.only(\n                  topLeft: Radius.circular(8),\n                  topRight: Radius.circular(8),\n                ),\n                child: NetImage(\n                  item.cover,\n                  fit: BoxFit.cover,\n                  height: 110,\n                  width: double.infinity,\n                ),\n              ),\n              Positioned(\n                right: 0,\n                left: 0,\n                bottom: 0,\n                child: Container(\n                  padding: const EdgeInsets.symmetric(\n                    horizontal: 4,\n                    vertical: 8,\n                  ),\n                  decoration: const BoxDecoration(\n                    gradient: LinearGradient(\n                      begin: Alignment.bottomCenter,\n                      end: Alignment.topCenter,\n                      colors: [\n                        Colors.black87,\n                        Colors.transparent,\n                      ],\n                    ),\n                  ),\n                  child: Row(\n                    mainAxisAlignment: MainAxisAlignment.end,\n                    children: [\n                      Icon(\n                        site.iconData,\n                        color: Colors.white,\n                        size: 14,\n                      ),\n                      AppStyle.hGap4,\n                      Text(\n                        Utils.onlineToString(item.online),\n                        style: const TextStyle(\n                          fontSize: 12,\n                          color: Colors.white,\n                        ),\n                      )\n                    ],\n                  ),\n                ),\n              ),\n            ],\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsA8.copyWith(bottom: 4),\n            child: Text(\n              item.title,\n              maxLines: 1,\n              overflow: TextOverflow.ellipsis,\n            ),\n          ),\n          Padding(\n            padding: AppStyle.edgeInsetsH8.copyWith(bottom: 8),\n            child: Text(\n              item.userName,\n              maxLines: 1,\n              style: const TextStyle(\n                  height: 1.4, fontSize: 12, color: Colors.grey),\n            ),\n          )\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/net_image.dart",
    "content": "import 'package:extended_image/extended_image.dart';\nimport 'package:flutter/material.dart';\n\nclass NetImage extends StatelessWidget {\n  final String picUrl;\n  final double? width;\n  final double? height;\n  final BoxFit? fit;\n  final double borderRadius;\n  const NetImage(this.picUrl,\n      {this.width,\n      this.height,\n      this.fit = BoxFit.cover,\n      this.borderRadius = 0,\n      super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    if (picUrl.isEmpty) {\n      return Image.asset(\n        'assets/images/logo.png',\n        width: width,\n        height: height,\n      );\n    }\n    var pic = picUrl;\n    if (pic.startsWith(\"//\")) {\n      pic = 'https:$pic';\n    }\n    return ClipRRect(\n      borderRadius: BorderRadius.circular(borderRadius),\n      child: ExtendedImage.network(\n        pic,\n        fit: fit,\n        height: height,\n        width: width,\n        shape: BoxShape.rectangle,\n        borderRadius: BorderRadius.circular(borderRadius),\n        loadStateChanged: (e) {\n          if (e.extendedImageLoadState == LoadState.loading) {\n            return const Icon(\n              Icons.image,\n              color: Colors.grey,\n              size: 24,\n            );\n          }\n          if (e.extendedImageLoadState == LoadState.failed) {\n            return const Icon(\n              Icons.broken_image,\n              color: Colors.grey,\n              size: 24,\n            );\n          }\n          return null;\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/none_border_circular_textfield.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass NoneBorderCircularTextField extends StatelessWidget {\n  final TextEditingController editingController;\n  final String? hintText;\n  final String? helperText;\n  final String? labelText;\n  final String? errorText;\n  final Widget? prefixIcon;\n  final bool obscureText;\n  final VoidCallback? onEditingComplete;\n  final ValueChanged<String>? onChanged;\n  final VoidCallback? onTap;\n  final TextAlign textAlign;\n  final Widget? trailing;\n  final TextInputType? inputType;\n  final int? maxLines;\n  final bool autoFocus;\n  final FocusNode? focusNode;\n  final bool? enable;\n  final bool readOnly;\n\n  final bool needPadding;\n\n  const NoneBorderCircularTextField({\n    super.key,\n    required this.editingController,\n    this.hintText,\n    this.helperText,\n    this.labelText,\n    this.errorText,\n    this.prefixIcon,\n    this.textAlign = TextAlign.start,\n    this.obscureText = false,\n    this.maxLines = 1,\n    this.onEditingComplete,\n    this.trailing,\n    this.autoFocus = false,\n    this.focusNode,\n    this.inputType,\n    this.onChanged,\n    this.onTap,\n    this.enable,\n    this.readOnly = false,\n    this.needPadding = true,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    TextField common = TextField(\n      enabled: enable,\n      readOnly: readOnly,\n      decoration: InputDecoration(\n        prefixIcon: prefixIcon,\n        hintText: hintText,\n        filled: true,\n        contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),\n        suffix: trailing,\n        helperText: helperText,\n        helperMaxLines: 3,\n        border: OutlineInputBorder(\n          borderSide: BorderSide.none,\n          borderRadius: const BorderRadius.all(Radius.circular(8.0)),\n        ),\n        labelText: labelText,\n        errorText: errorText,\n        errorMaxLines: 3,\n      ),\n      textAlign: textAlign,\n      autofocus: autoFocus,\n      keyboardType: inputType,\n      maxLines: maxLines,\n      controller: editingController,\n      obscureText: obscureText,\n      onEditingComplete: onEditingComplete,\n      onChanged: onChanged,\n      onTap: onTap,\n      focusNode: focusNode,\n    );\n    if (needPadding) {\n      return Padding(\n        padding: const EdgeInsets.only(\n          top: 10,\n          bottom: 10,\n        ),\n        child: common,\n      );\n    } else {\n      return common;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/page_grid_view.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/widgets/status/app_empty_widget.dart';\nimport 'package:simple_live_app/widgets/status/app_error_widget.dart';\nimport 'package:simple_live_app/widgets/status/app_loadding_widget.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:flutter_easyrefresh/easy_refresh.dart';\nimport 'package:get/get.dart';\n\nclass PageGridView extends StatelessWidget {\n  final BasePageController pageController;\n  final IndexedWidgetBuilder itemBuilder;\n  final EdgeInsets? padding;\n  final bool firstRefresh;\n  final Function()? onLoginSuccess;\n  final bool showPageLoadding;\n  final double crossAxisSpacing, mainAxisSpacing;\n  final int crossAxisCount;\n  final bool showPCRefreshButton;\n  const PageGridView({\n    required this.itemBuilder,\n    required this.pageController,\n    this.padding,\n    this.firstRefresh = false,\n    this.showPageLoadding = false,\n    this.onLoginSuccess,\n    this.crossAxisSpacing = 0.0,\n    this.mainAxisSpacing = 0.0,\n    this.showPCRefreshButton = true,\n    required this.crossAxisCount,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => Stack(\n        children: [\n          EasyRefresh(\n            header: MaterialHeader(\n              completeDuration: const Duration(milliseconds: 400),\n            ),\n            footer: MaterialFooter(\n              completeDuration: const Duration(milliseconds: 400),\n            ),\n            scrollController: pageController.scrollController,\n            controller: pageController.easyRefreshController,\n            firstRefresh: firstRefresh,\n            onLoad: pageController.loadData,\n            onRefresh: pageController.refreshData,\n            child: MasonryGridView.count(\n              padding: padding,\n              itemCount: pageController.list.length,\n              itemBuilder: itemBuilder,\n              crossAxisCount: crossAxisCount,\n              crossAxisSpacing: crossAxisSpacing,\n              mainAxisSpacing: mainAxisSpacing,\n            ),\n          ),\n          Positioned(\n            bottom: 0,\n            left: 0,\n            right: 0,\n            child: // 加载更多按钮\n                Visibility(\n              visible: (Platform.isWindows ||\n                      Platform.isLinux ||\n                      Platform.isMacOS) &&\n                  pageController.canLoadMore.value &&\n                  !pageController.pageLoadding.value &&\n                  !pageController.pageEmpty.value,\n              child: Center(\n                child: TextButton(\n                  onPressed: pageController.loadData,\n                  child: const Text(\"加载更多\"),\n                ),\n              ),\n            ),\n          ),\n          Positioned(\n            bottom: 12,\n            right: 12,\n            child: // 加载更多按钮\n                Visibility(\n              visible: (Platform.isWindows ||\n                      Platform.isLinux ||\n                      Platform.isMacOS) &&\n                  pageController.canLoadMore.value &&\n                  !pageController.pageLoadding.value &&\n                  !pageController.pageEmpty.value &&\n                  showPCRefreshButton,\n              child: Center(\n                child: IconButton(\n                  style: IconButton.styleFrom(\n                    backgroundColor: Get.theme.cardColor.withAlpha(200),\n                    elevation: 4,\n                  ),\n                  onPressed: () {\n                    pageController.refreshData();\n                  },\n                  icon: const Icon(Icons.refresh),\n                ),\n              ),\n            ),\n          ),\n          Offstage(\n            offstage: !pageController.pageEmpty.value,\n            child: AppEmptyWidget(\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n          Offstage(\n            offstage: !(showPageLoadding && pageController.pageLoadding.value),\n            child: const AppLoaddingWidget(),\n          ),\n          Offstage(\n            offstage: !pageController.pageError.value,\n            child: AppErrorWidget(\n              errorMsg: pageController.errorMsg.value,\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/page_list_view.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/controller/base_controller.dart';\nimport 'package:simple_live_app/widgets/status/app_empty_widget.dart';\nimport 'package:simple_live_app/widgets/status/app_error_widget.dart';\nimport 'package:simple_live_app/widgets/status/app_loadding_widget.dart';\n\nimport 'package:flutter_easyrefresh/easy_refresh.dart';\nimport 'package:get/get.dart';\n\ntypedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);\n\nclass PageListView extends StatelessWidget {\n  final BasePageController pageController;\n  final IndexedWidgetBuilder itemBuilder;\n  final IndexedWidgetBuilder? separatorBuilder;\n  final EdgeInsets? padding;\n  final bool firstRefresh;\n  final Function()? onLoginSuccess;\n  final bool showPageLoadding;\n  final bool showPCRefreshButton;\n  const PageListView({\n    required this.itemBuilder,\n    required this.pageController,\n    this.padding,\n    this.firstRefresh = false,\n    this.showPageLoadding = false,\n    this.showPCRefreshButton = true,\n    this.separatorBuilder,\n    this.onLoginSuccess,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => Stack(\n        children: [\n          EasyRefresh(\n            header: MaterialHeader(\n              completeDuration: const Duration(milliseconds: 400),\n            ),\n            footer: MaterialFooter(\n              completeDuration: const Duration(milliseconds: 400),\n            ),\n            scrollController: pageController.scrollController,\n            controller: pageController.easyRefreshController,\n            firstRefresh: firstRefresh,\n            onLoad: pageController.loadData,\n            onRefresh: pageController.refreshData,\n            child: ListView.separated(\n              padding: padding,\n              itemCount: pageController.list.length,\n              itemBuilder: itemBuilder,\n              separatorBuilder:\n                  separatorBuilder ?? (context, i) => const SizedBox(),\n            ),\n          ),\n          Positioned(\n            bottom: 0,\n            left: 0,\n            right: 0,\n            child: // 加载更多按钮\n                Visibility(\n              visible: (Platform.isWindows ||\n                      Platform.isLinux ||\n                      Platform.isMacOS) &&\n                  pageController.canLoadMore.value &&\n                  !pageController.pageLoadding.value &&\n                  !pageController.pageEmpty.value,\n              child: Center(\n                child: TextButton(\n                  onPressed: pageController.loadData,\n                  child: const Text(\"加载更多\"),\n                ),\n              ),\n            ),\n          ),\n          Positioned(\n            bottom: 12,\n            right: 12,\n            child: // 加载更多按钮\n                Visibility(\n              visible: (Platform.isWindows ||\n                      Platform.isLinux ||\n                      Platform.isMacOS) &&\n                  pageController.canLoadMore.value &&\n                  !pageController.pageLoadding.value &&\n                  !pageController.pageEmpty.value &&\n                  showPCRefreshButton,\n              child: Center(\n                child: IconButton(\n                  style: IconButton.styleFrom(\n                    backgroundColor: Get.theme.cardColor.withAlpha(200),\n                    elevation: 4,\n                  ),\n                  onPressed: () {\n                    pageController.refreshData();\n                  },\n                  icon: const Icon(Icons.refresh),\n                ),\n              ),\n            ),\n          ),\n          Offstage(\n            offstage: !pageController.pageEmpty.value,\n            child: AppEmptyWidget(\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n          Offstage(\n            offstage: !(showPageLoadding && pageController.pageLoadding.value),\n            child: const AppLoaddingWidget(),\n          ),\n          Offstage(\n            offstage: !pageController.pageError.value,\n            child: AppErrorWidget(\n              errorMsg: pageController.errorMsg.value,\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/rectangular_indicator.dart",
    "content": "import 'package:flutter/material.dart';\n\n/// 来自 https://github.com/adar2378/tab_indicator_styler\n\nclass RectangularIndicator extends Decoration {\n  /// topRight radius of the indicator, default to 5.\n  final double topRightRadius;\n\n  /// topLeft radius of the indicator, default to 5.\n  final double topLeftRadius;\n\n  /// bottomRight radius of the indicator, default to 0.\n  final double bottomRightRadius;\n\n  /// bottomLeft radius of the indicator, default to 0\n  final double bottomLeftRadius;\n\n  /// Color of the indicator, default set to [Colors.black]\n  final Color color;\n\n  /// Horizontal padding of the indicator, default set to 0\n  final double horizontalPadding;\n\n  /// Vertical padding of the indicator, default set to 0\n  final double verticalPadding;\n\n  /// [PagingStyle] determines if the indicator should be fill or stroke, default to fill\n  final PaintingStyle paintingStyle;\n\n  /// StrokeWidth, used for [PaintingStyle.stroke], default set to 0\n  final double strokeWidth;\n\n  const RectangularIndicator({\n    this.topRightRadius = 5,\n    this.topLeftRadius = 5,\n    this.bottomRightRadius = 0,\n    this.bottomLeftRadius = 0,\n    this.color = Colors.black,\n    this.horizontalPadding = 0,\n    this.verticalPadding = 0,\n    this.paintingStyle = PaintingStyle.fill,\n    this.strokeWidth = 2,\n  });\n  @override\n  MyCustomPainter createBoxPainter([VoidCallback? onChanged]) {\n    return MyCustomPainter(\n      this,\n      onChanged,\n      bottomLeftRadius: bottomLeftRadius,\n      bottomRightRadius: bottomRightRadius,\n      color: color,\n      horizontalPadding: horizontalPadding,\n      topLeftRadius: topLeftRadius,\n      topRightRadius: topRightRadius,\n      verticalPadding: verticalPadding,\n      paintingStyle: paintingStyle,\n      strokeWidth: strokeWidth,\n    );\n  }\n}\n\nclass MyCustomPainter extends BoxPainter {\n  final RectangularIndicator decoration;\n  final double topRightRadius;\n  final double topLeftRadius;\n  final double bottomRightRadius;\n  final double bottomLeftRadius;\n  final Color color;\n  final double horizontalPadding;\n  final double verticalPadding;\n  final PaintingStyle paintingStyle;\n  final double strokeWidth;\n\n  MyCustomPainter(\n    this.decoration,\n    VoidCallback? onChanged, {\n    required this.topRightRadius,\n    required this.topLeftRadius,\n    required this.bottomRightRadius,\n    required this.bottomLeftRadius,\n    required this.color,\n    required this.horizontalPadding,\n    required this.verticalPadding,\n    required this.paintingStyle,\n    required this.strokeWidth,\n  }) : super(onChanged);\n\n  @override\n  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {\n    assert(horizontalPadding >= 0);\n    assert(horizontalPadding < configuration.size!.width / 2,\n        \"Padding must be less than half of the size of the tab\");\n    assert(verticalPadding < configuration.size!.height / 2 &&\n        verticalPadding >= 0);\n    assert(strokeWidth >= 0 &&\n        strokeWidth < configuration.size!.width / 2 &&\n        strokeWidth < configuration.size!.height / 2);\n\n    //offset is the position from where the decoration should be drawn.\n    //configuration.size tells us about the height and width of the tab.\n    Size mysize = Size(configuration.size!.width - (horizontalPadding * 2),\n        configuration.size!.height - (2 * verticalPadding));\n\n    Offset myoffset =\n        Offset(offset.dx + (horizontalPadding), offset.dy + verticalPadding);\n    final Rect rect = myoffset & mysize;\n    final Paint paint = Paint();\n    paint.color = color;\n    paint.style = paintingStyle;\n    paint.strokeWidth = 3;\n    canvas.drawRRect(\n        RRect.fromRectAndCorners(\n          rect,\n          bottomRight: Radius.circular(bottomRightRadius),\n          bottomLeft: Radius.circular(bottomLeftRadius),\n          topLeft: Radius.circular(topLeftRadius),\n          topRight: Radius.circular(topRightRadius),\n        ),\n        paint);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_action.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass SettingsAction extends StatelessWidget {\n  final String title;\n  final String? subtitle;\n  final Function()? onTap;\n  final String? value;\n  final Widget? leading;\n\n  const SettingsAction({\n    required this.title,\n    this.value,\n    this.onTap,\n    this.subtitle,\n    this.leading,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return ListTile(\n      // visualDensity: VisualDensity.compact,\n      leading: leading,\n      title: Text(\n        title,\n        style: Theme.of(context).textTheme.bodyLarge,\n      ),\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n      ),\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8),\n      subtitle: subtitle == null\n          ? null\n          : Text(\n              subtitle!,\n              style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey),\n            ),\n      trailing: Row(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          if (value != null)\n            Text(\n              value!,\n              style: Theme.of(context)\n                  .textTheme\n                  .bodyMedium!\n                  .copyWith(color: Colors.grey),\n            ),\n          AppStyle.hGap4,\n          const Icon(\n            Icons.chevron_right,\n            color: Colors.grey,\n          ),\n        ],\n      ),\n      onTap: onTap,\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_card.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass SettingsCard extends StatelessWidget {\n  final Widget child;\n  const SettingsCard({required this.child, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Material(\n      color: Theme.of(context).brightness == Brightness.dark\n          ? Colors.grey.withAlpha(50)\n          : Colors.white70,\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n        side: BorderSide(\n          color: Colors.grey.withAlpha(25),\n        ),\n      ),\n      child: Container(\n        decoration: BoxDecoration(\n          borderRadius: AppStyle.radius8,\n        ),\n        child: child,\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_menu.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass SettingsMenu<T> extends StatelessWidget {\n  final String title;\n  final String? subtitle;\n  final Map<T, String> valueMap;\n  final T value;\n  final Widget? trailing;\n\n  final Function(T)? onChanged;\n  const SettingsMenu({\n    required this.title,\n    required this.value,\n    required this.valueMap,\n    this.subtitle,\n    this.onChanged,\n    this.trailing,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return ListTile(\n      visualDensity: VisualDensity.compact,\n      title: Text(\n        title,\n        style: Theme.of(context).textTheme.bodyLarge,\n      ),\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n      ),\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8),\n      subtitle: subtitle == null\n          ? null\n          : Text(\n              subtitle!,\n              style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey),\n            ),\n      trailing: trailing ?? Row(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          Text(\n            valueMap[value]!.tr,\n            style: Theme.of(context)\n                .textTheme\n                .bodyMedium!\n                .copyWith(color: Colors.grey),\n          ),\n          AppStyle.hGap4,\n          const Icon(\n            Icons.chevron_right,\n            color: Colors.grey,\n          ),\n        ],\n      ),\n      onTap: () => openMenu(context),\n    );\n  }\n\n  void openMenu(BuildContext context) {\n    showModalBottomSheet(\n      context: context,\n      showDragHandle: true,\n      useSafeArea: true, //useSafeArea似乎无效\n      builder: (_) => SafeArea(\n        top: false,\n        child: SingleChildScrollView(\n          child: RadioGroup(\n            groupValue: value,\n            onChanged: (e) {\n              Get.back();\n              onChanged?.call(e as T);\n            },\n            child: Column(\n              mainAxisSize: MainAxisSize.min,\n              children: valueMap.keys\n                  .map(\n                    (e) => RadioListTile(\n                      value: e,\n                      title: Text(\n                        (valueMap[e]?.tr) ?? \"???\",\n                        style: Get.textTheme.bodyMedium,\n                      ),\n                    ),\n                  )\n                  .toList(),\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_menu_check.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass _MenuCheckController<T> extends GetxController {\n  final RxList<T> selectedItems;\n\n  _MenuCheckController(List<T> initial)\n      : selectedItems = RxList<T>.from(initial);\n\n  void toggle(T item) {\n    if (selectedItems.contains(item)) {\n      selectedItems.remove(item);\n    } else {\n      selectedItems.add(item);\n    }\n  }\n}\n\nclass SettingsMenuCheck<T> extends StatelessWidget {\n  final String title;\n  final String? subtitle;\n  final List<T> items;\n  final List<T> initialSelection;\n  final Future<List<T>> Function()? itemsProvider;\n  final List<T> Function(List<T> providedItems)? initialSelectionProvider;\n\n  final String Function(T item) itemToString;\n  final Function(List<T> selectedItems)? onConfirm;\n  final String? confirmText;\n  final String? modalTitle;\n\n  const SettingsMenuCheck({\n    required this.title,\n    required this.itemToString,\n    this.items = const [],\n    this.initialSelection = const [],\n    this.itemsProvider,\n    this.initialSelectionProvider,\n    this.subtitle,\n    this.onConfirm,\n    this.confirmText,\n    this.modalTitle,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    // 这里需要状态管理，暂时不实现\n    final displayItemsCount = items.length;\n    final displaySelectedCount = initialSelection.length;\n\n    return ListTile(\n      visualDensity: VisualDensity.compact,\n      title: Text(\n        title,\n        style: Theme.of(context).textTheme.bodyLarge,\n      ),\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n      ),\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8),\n      subtitle: subtitle == null\n          ? null\n          : Text(\n              subtitle!,\n              style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey),\n            ),\n      trailing: Row(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          Text(\n            '$displaySelectedCount/$displayItemsCount',\n            style: Theme.of(context)\n                .textTheme\n                .bodyMedium!\n                .copyWith(color: Colors.grey),\n          ),\n          AppStyle.hGap4,\n          const Icon(\n            Icons.chevron_right,\n            color: Colors.grey,\n          ),\n        ],\n      ),\n      onTap: _handleTap,\n    );\n  }\n\n  Future<void> _handleTap() async {\n    List<T> menuItems;\n    List<T> menuInitialSelection;\n    if (itemsProvider != null) {\n      SmartDialog.showLoading(msg: \"\");\n      try {\n        menuItems = await itemsProvider!();\n        if (initialSelectionProvider != null) {\n          menuInitialSelection = initialSelectionProvider!(menuItems);\n        } else {\n          menuInitialSelection = menuItems.toList();\n        }\n      } finally {\n        SmartDialog.dismiss();\n      }\n    } else {\n      menuItems = items;\n      menuInitialSelection = initialSelection;\n    }\n\n    if (menuItems.isEmpty) {\n      return;\n    }\n\n    _openMenu(Get.context!, menuItems, menuInitialSelection);\n  }\n\n  void _openMenu(\n      BuildContext context, List<T> items, List<T> initialSelection) {\n    final controller = _MenuCheckController<T>(initialSelection);\n\n    showModalBottomSheet(\n      context: context,\n      isScrollControlled: true,\n      showDragHandle: false,\n      useSafeArea: true,\n      constraints: BoxConstraints(\n        maxWidth: 600,\n      ),\n      shape: const RoundedRectangleBorder(\n        borderRadius: BorderRadius.only(\n          topLeft: Radius.circular(12),\n          topRight: Radius.circular(12),\n        ),\n      ),\n      builder: (_) {\n        return SafeArea(\n          top: false,\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              ListTile(\n                contentPadding: const EdgeInsets.only(\n                  left: 12,\n                ),\n                title: Text(\n                  modalTitle?.tr ?? title.tr,\n                ),\n                trailing: IconButton(\n                  onPressed: () {\n                    Get.back();\n                    onConfirm?.call(controller.selectedItems.toList());\n                  },\n                  icon: const Icon(Remix.delete_bin_line),\n                ),\n              ),\n              Flexible(\n                child: SingleChildScrollView(\n                  child: Column(\n                    mainAxisSize: MainAxisSize.min,\n                    children: items.map((item) {\n                      return Obx(() => CheckboxListTile(\n                            value: controller.selectedItems.contains(item),\n                            controlAffinity: ListTileControlAffinity.leading,\n                            title: Text(\n                              itemToString(item),\n                              style: Get.textTheme.bodyMedium,\n                            ),\n                            onChanged: (bool? selected) {\n                              controller.toggle(item);\n                            },\n                          ));\n                    }).toList(),\n                  ),\n                ),\n              ),\n            ],\n          ),\n        );\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_number.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass SettingsNumber extends StatelessWidget {\n  final String title;\n  final String? subtitle;\n  final String unit;\n  final int value;\n  final int step;\n  final int min;\n  final int max;\n  final String? displayValue;\n  final Function(int)? onChanged;\n  const SettingsNumber(\n      {required this.title,\n      required this.value,\n      required this.max,\n      this.subtitle,\n      this.onChanged,\n      this.step = 1,\n      this.min = 0,\n      this.unit = '',\n      this.displayValue,\n      super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return ListTile(\n      visualDensity: VisualDensity.compact,\n      title: Text(\n        title,\n        style: Get.textTheme.bodyLarge,\n      ),\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n      ),\n      subtitle: subtitle == null\n          ? null\n          : Text(\n              subtitle!,\n              style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey),\n            ),\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 12),\n      trailing: Container(\n        decoration: BoxDecoration(\n          color: Colors.grey.withAlpha(25),\n          borderRadius: AppStyle.radius24,\n        ),\n        height: 36,\n        child: Row(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            IconButton(\n              padding: AppStyle.edgeInsetsA4,\n              constraints: const BoxConstraints(\n                minHeight: 32,\n              ),\n              onPressed: () {\n                int newValue = value - step;\n                if (newValue < min) {\n                  newValue = min;\n                }\n                onChanged?.call(newValue);\n              },\n              icon: Icon(\n                Icons.remove,\n                color: Get.textTheme.bodyMedium!.color!.withAlpha(150),\n              ),\n            ),\n            Text(\n              displayValue ?? \"$value$unit\",\n              textAlign: TextAlign.center,\n              style: Theme.of(context)\n                  .textTheme\n                  .bodyMedium!\n                  .copyWith(color: Colors.grey),\n            ),\n            IconButton(\n              padding: AppStyle.edgeInsetsA4,\n              constraints: const BoxConstraints(\n                minHeight: 32,\n              ),\n              onPressed: () {\n                int newValue = value + step;\n                if (newValue > max) {\n                  newValue = max;\n                }\n                onChanged?.call(newValue);\n              },\n              icon: Icon(\n                Icons.add,\n                color: Get.textTheme.bodyMedium!.color!.withAlpha(150),\n              ),\n            ),\n          ],\n        ),\n      ),\n      onTap: () => openSilder(context),\n    );\n  }\n\n  void openSilder(BuildContext context) {\n    var newValue = value.obs;\n    showModalBottomSheet(\n      context: context,\n      showDragHandle: true,\n      useSafeArea: true, //useSafeArea似乎无效\n      builder: (_) => SafeArea(\n        top: false,\n        child: Column(\n          mainAxisSize: MainAxisSize.min,\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: [\n            Padding(\n              padding: AppStyle.edgeInsetsH16,\n              child: Row(\n                mainAxisAlignment: MainAxisAlignment.spaceBetween,\n                children: [\n                  Text(\n                    title,\n                    style: Get.textTheme.titleMedium,\n                  ),\n                  Obx(\n                    () => Text(\n                      \"${newValue.value}$unit\",\n                      style: Get.textTheme.titleMedium,\n                    ),\n                  ),\n                ],\n              ),\n            ),\n            Obx(\n              () => Slider(\n                value: newValue.value.toDouble(),\n                min: min.toDouble(),\n                max: max.toDouble(),\n                onChanged: (e) {\n                  newValue.value = e.toInt();\n                },\n              ),\n            ),\n            Padding(\n              padding: AppStyle.edgeInsetsH16,\n              child: TextButton(\n                onPressed: () {\n                  onChanged?.call(newValue.value);\n                  Get.back();\n                },\n                child: const Text(\"确定\"),\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/settings/settings_switch.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass SettingsSwitch extends StatelessWidget {\n  final bool value;\n  final String title;\n  final String? subtitle;\n  final Function(bool) onChanged;\n  const SettingsSwitch({\n    required this.value,\n    required this.title,\n    this.subtitle,\n    required this.onChanged,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return SwitchListTile(\n      title: Text(\n        title,\n        style: Theme.of(context).textTheme.bodyLarge,\n      ),\n      shape: RoundedRectangleBorder(\n        borderRadius: AppStyle.radius8,\n      ),\n      trackOutlineColor: const WidgetStatePropertyAll(Colors.transparent),\n      //visualDensity: VisualDensity.compact,\n      contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8),\n      subtitle: subtitle != null\n          ? Text(\n              subtitle!,\n              style: Theme.of(context)\n                  .textTheme\n                  .bodySmall!\n                  .copyWith(color: Colors.grey),\n            )\n          : null,\n      value: value,\n      onChanged: onChanged,\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/shadow_card.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass ShadowCard extends StatelessWidget {\n  final Widget child;\n  final double radius;\n  final Function()? onTap;\n  final Function()? onLongPress;\n  const ShadowCard({\n    required this.child,\n    this.radius = 8.0,\n    this.onTap,\n    this.onLongPress,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      decoration: BoxDecoration(\n        borderRadius: BorderRadius.circular(radius),\n        boxShadow: Get.isDarkMode\n            ? []\n            : [\n                BoxShadow(\n                  blurRadius: 4,\n                  color: Colors.grey.withAlpha(50),\n                )\n              ],\n      ),\n      child: Material(\n        color: Theme.of(context).cardColor,\n        borderRadius: BorderRadius.circular(radius),\n        child: InkWell(\n          borderRadius: BorderRadius.circular(radius),\n          onLongPress: onLongPress,\n          onTap: onTap,\n          child: Container(\n            decoration: BoxDecoration(\n              borderRadius: AppStyle.radius8,\n            ),\n            child: child,\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/status/app_empty_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:lottie/lottie.dart';\n\nclass AppEmptyWidget extends StatelessWidget {\n  final Function()? onRefresh;\n  const AppEmptyWidget({this.onRefresh, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: GestureDetector(\n        onTap: () {\n          onRefresh?.call();\n        },\n        child: Padding(\n          padding: AppStyle.edgeInsetsA12,\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              LottieBuilder.asset(\n                'assets/lotties/empty.json',\n                width: 200,\n                height: 200,\n                repeat: false,\n              ),\n              const Text(\n                \"这里什么都没有\",\n                textAlign: TextAlign.center,\n                style: TextStyle(fontSize: 12, color: Colors.grey),\n              ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/status/app_error_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:lottie/lottie.dart';\n\nclass AppErrorWidget extends StatelessWidget {\n  final Function()? onRefresh;\n  final String errorMsg;\n  const AppErrorWidget({this.errorMsg = \"\", this.onRefresh, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: GestureDetector(\n        onTap: () {\n          onRefresh?.call();\n        },\n        child: Padding(\n          padding: AppStyle.edgeInsetsA12,\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              LottieBuilder.asset(\n                'assets/lotties/error.json',\n                width: 260,\n                repeat: false,\n              ),\n              Text(\n                \"$errorMsg\\r\\n点击刷新\",\n                textAlign: TextAlign.center,\n                style: const TextStyle(fontSize: 12, color: Colors.grey),\n              ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/status/app_loadding_widget.dart",
    "content": "import 'package:flutter/cupertino.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_app/app/app_style.dart';\n\nclass AppLoaddingWidget extends StatelessWidget {\n  const AppLoaddingWidget({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: Container(\n        padding: AppStyle.edgeInsetsA12,\n        decoration: BoxDecoration(\n          shape: BoxShape.circle,\n          color: Theme.of(context).cardColor,\n          boxShadow: Get.isDarkMode\n              ? []\n              : [\n                  BoxShadow(\n                    blurRadius: 4,\n                    color: Colors.grey.withAlpha(50),\n                  )\n                ],\n        ),\n        child: const CupertinoActivityIndicator(\n          radius: 10,\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/superchat_card.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:simple_live_app/app/app_style.dart';\nimport 'package:simple_live_app/app/utils.dart';\nimport 'package:simple_live_app/widgets/net_image.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass SuperChatCard extends StatefulWidget {\n  final LiveSuperChatMessage message;\n  final Function()? onExpire;\n  const SuperChatCard(\n    this.message, {\n    required this.onExpire,\n    super.key,\n  });\n\n  @override\n  State<SuperChatCard> createState() => _SuperChatCardState();\n}\n\nclass _SuperChatCardState extends State<SuperChatCard> {\n  late Timer timer;\n\n  int countdown = 0;\n\n  @override\n  void initState() {\n    var currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;\n    var endTime = widget.message.endTime.millisecondsSinceEpoch ~/ 1000;\n\n    countdown = endTime - currentTime;\n\n    timer = Timer.periodic(const Duration(seconds: 1), timerCallback);\n\n    super.initState();\n  }\n\n  void timerCallback(Timer e) {\n    if (countdown <= 0) {\n      widget.onExpire?.call();\n      timer.cancel();\n      return;\n    }\n\n    setState(() {\n      countdown -= 1;\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return ClipRRect(\n      borderRadius: AppStyle.radius8,\n      child: Container(\n        decoration: BoxDecoration(\n          color: Utils.convertHexColor(widget.message.backgroundColor),\n        ),\n        child: Column(\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: [\n            Padding(\n              padding: AppStyle.edgeInsetsA8,\n              child: Row(\n                children: [\n                  NetImage(\n                    widget.message.face,\n                    width: 48,\n                    height: 48,\n                    borderRadius: 36,\n                  ),\n                  AppStyle.hGap12,\n                  Expanded(\n                    child: Column(\n                      crossAxisAlignment: CrossAxisAlignment.start,\n                      mainAxisAlignment: MainAxisAlignment.center,\n                      children: [\n                        Text(\n                          widget.message.userName,\n                          style: const TextStyle(\n                            color: AppColors.black333,\n                          ),\n                        ),\n                        Text(\n                          \"￥${widget.message.price}\",\n                          style: const TextStyle(\n                            fontSize: 12,\n                            color: Colors.grey,\n                          ),\n                        ),\n                      ],\n                    ),\n                  ),\n                  Text(\n                    \"$countdown\",\n                    style: const TextStyle(\n                      fontSize: 14,\n                      color: Colors.grey,\n                    ),\n                  ),\n                ],\n              ),\n            ),\n            Container(\n              decoration: BoxDecoration(\n                color:\n                    Utils.convertHexColor(widget.message.backgroundBottomColor),\n              ),\n              padding: AppStyle.edgeInsetsA8,\n              child: SelectableText(\n                widget.message.message,\n                style: const TextStyle(color: Colors.white),\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n\n  @override\n  void dispose() {\n    timer.cancel();\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "simple_live_app/lib/widgets/ui/after_post_frame.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nmixin AfterFirstFrameMixin<T extends StatefulWidget> on State<T> {\n  bool _afterFirstFrame = false;\n\n  @override\n  void initState() {\n    super.initState();\n\n    WidgetsBinding.instance.addPostFrameCallback((_) {\n      _afterFirstFrame = true;\n    });\n  }\n\n  void afterFirstFrame(void Function() callback) {\n    if (_afterFirstFrame) {\n      callback();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/linux/.gitignore",
    "content": "flutter/ephemeral\n"
  },
  {
    "path": "simple_live_app/linux/CMakeLists.txt",
    "content": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.13)\nproject(runner LANGUAGES CXX)\n\n# The name of the executable created for the application. Change this to change\n# the on-disk name of your application.\nset(BINARY_NAME \"io.github.SlotSun.Slive\")\n# The unique GTK application identifier for this application. See:\n# https://wiki.gnome.org/HowDoI/ChooseApplicationID\nset(APPLICATION_ID \"io.github.SlotSun.Slive\")\n\n# Explicitly opt in to modern CMake behaviors to avoid warnings with recent\n# versions of CMake.\ncmake_policy(SET CMP0063 NEW)\n\n# Load bundled libraries from the lib/ directory relative to the binary.\nset(CMAKE_INSTALL_RPATH \"$ORIGIN/lib\")\n\n# Root filesystem for cross-building.\nif(FLUTTER_TARGET_PLATFORM_SYSROOT)\n  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nendif()\n\n# Define build configuration options.\nif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n  set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n    STRING \"Flutter build mode\" FORCE)\n  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n    \"Debug\" \"Profile\" \"Release\")\nendif()\n\n# Compilation settings that should be applied to most targets.\n#\n# Be cautious about adding new options here, as plugins use this function by\n# default. In most cases, you should add new options to specific targets instead\n# of modifying this function.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_17)\n  target_compile_options(${TARGET} PRIVATE -Wall -Werror)\n  target_compile_options(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:-O3>\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:NDEBUG>\")\nendfunction()\n\n# Flutter library and tool build rules.\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\n\n# Application build; see runner/CMakeLists.txt.\nadd_subdirectory(\"runner\")\n\n# Run the Flutter tool portions of the build. This must not be removed.\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n\n# Only the install-generated bundle's copy of the executable will launch\n# correctly, since the resources must in the right relative locations. To avoid\n# people trying to run the unbundled copy, put it in a subdirectory instead of\n# the default top-level location.\nset_target_properties(${BINARY_NAME}\n  PROPERTIES\n  RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/intermediates_do_not_run\"\n)\n\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# By default, \"installing\" just makes a relocatable bundle in the build\n# directory.\nset(BUILD_BUNDLE_DIR \"${PROJECT_BINARY_DIR}/bundle\")\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\n# Start with a clean build bundle directory every time.\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${BUILD_BUNDLE_DIR}/\\\")\n  \" COMPONENT Runtime)\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}/lib\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nforeach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})\n  install(FILES \"${bundled_library}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendforeach(bundled_library)\n\n# Copy the native assets provided by the build.dart from all packages.\nset(NATIVE_ASSETS_DIR \"${PROJECT_BUILD_DIR}native_assets/linux/\")\ninstall(DIRECTORY \"${NATIVE_ASSETS_DIR}\"\n   DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n   COMPONENT Runtime)\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\nif(NOT CMAKE_BUILD_TYPE MATCHES \"Debug\")\n  install(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n"
  },
  {
    "path": "simple_live_app/linux/flutter/CMakeLists.txt",
    "content": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.10)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\n\n# Serves the same purpose as list(TRANSFORM ... PREPEND ...),\n# which isn't available in 3.10.\nfunction(list_prepend LIST_NAME PREFIX)\n    set(NEW_LIST \"\")\n    foreach(element ${${LIST_NAME}})\n        list(APPEND NEW_LIST \"${PREFIX}${element}\")\n    endforeach(element)\n    set(${LIST_NAME} \"${NEW_LIST}\" PARENT_SCOPE)\nendfunction()\n\n# === Flutter Library ===\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\npkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)\npkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)\n\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/libflutter_linux_gtk.so\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/lib/libapp.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"fl_basic_message_channel.h\"\n  \"fl_binary_codec.h\"\n  \"fl_binary_messenger.h\"\n  \"fl_dart_project.h\"\n  \"fl_engine.h\"\n  \"fl_json_message_codec.h\"\n  \"fl_json_method_codec.h\"\n  \"fl_message_codec.h\"\n  \"fl_method_call.h\"\n  \"fl_method_channel.h\"\n  \"fl_method_codec.h\"\n  \"fl_method_response.h\"\n  \"fl_plugin_registrar.h\"\n  \"fl_plugin_registry.h\"\n  \"fl_standard_message_codec.h\"\n  \"fl_standard_method_codec.h\"\n  \"fl_string_codec.h\"\n  \"fl_value.h\"\n  \"fl_view.h\"\n  \"flutter_linux.h\"\n)\nlist_prepend(FLUTTER_LIBRARY_HEADERS \"${EPHEMERAL_DIR}/flutter_linux/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}\")\ntarget_link_libraries(flutter INTERFACE\n  PkgConfig::GTK\n  PkgConfig::GLIB\n  PkgConfig::GIO\n)\nadd_dependencies(flutter flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CMAKE_CURRENT_BINARY_DIR}/_phony_\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh\"\n      ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n)\n"
  },
  {
    "path": "simple_live_app/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n#include <dynamic_color/dynamic_color_plugin.h>\n#include <flutter_qjs/flutter_qjs_plugin.h>\n#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>\n#include <media_kit_video/media_kit_video_plugin.h>\n#include <screen_retriever_linux/screen_retriever_linux_plugin.h>\n#include <url_launcher_linux/url_launcher_plugin.h>\n#include <volume_controller/volume_controller_plugin.h>\n#include <window_manager/window_manager_plugin.h>\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n  g_autoptr(FlPluginRegistrar) dynamic_color_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"DynamicColorPlugin\");\n  dynamic_color_plugin_register_with_registrar(dynamic_color_registrar);\n  g_autoptr(FlPluginRegistrar) flutter_qjs_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"FlutterQjsPlugin\");\n  flutter_qjs_plugin_register_with_registrar(flutter_qjs_registrar);\n  g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"MediaKitLibsLinuxPlugin\");\n  media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);\n  g_autoptr(FlPluginRegistrar) media_kit_video_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"MediaKitVideoPlugin\");\n  media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);\n  g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"ScreenRetrieverLinuxPlugin\");\n  screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);\n  g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"UrlLauncherPlugin\");\n  url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);\n  g_autoptr(FlPluginRegistrar) volume_controller_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"VolumeControllerPlugin\");\n  volume_controller_plugin_register_with_registrar(volume_controller_registrar);\n  g_autoptr(FlPluginRegistrar) window_manager_registrar =\n      fl_plugin_registry_get_registrar_for_plugin(registry, \"WindowManagerPlugin\");\n  window_manager_plugin_register_with_registrar(window_manager_registrar);\n}\n"
  },
  {
    "path": "simple_live_app/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter_linux/flutter_linux.h>\n\n// Registers Flutter plugins.\nvoid fl_register_plugins(FlPluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "simple_live_app/linux/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n  dynamic_color\n  flutter_qjs\n  media_kit_libs_linux\n  media_kit_video\n  screen_retriever_linux\n  url_launcher_linux\n  volume_controller\n  window_manager\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n  rust_lib_simple_live_app\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "simple_live_app/linux/packaging/aur/slive.desktop",
    "content": "[Desktop Entry]\nName=Slive\nExec=io.github.SlotSun.Slive\nIcon=io.github.SlotSun.Slive\nComment=Slive is a lightweight and user-friendly application for watching live streams across multiple platforms, offering a seamless watching experience with support for popular streaming services.\nComment[zh_CN]=Slive 是一个轻量且用户友好的应用程序，可跨多个平台观看直播流，提供无缝的观看体验，并支持流行的流媒体服务。\nType=Application\nTerminal=false\nCategories=Video;AudioVideo;Player;\n"
  },
  {
    "path": "simple_live_app/linux/packaging/deb/make_config.yaml",
    "content": "display_name: Slive\npackage_name: Slive\nmaintainer:\n  name: slotsun\n  email: slot_sun@outlook.com\npriority: optional\nsection: x11\ninstalled_size: 24400\nessential: false\nicon: assets/images/logo.png\n\ngeneric_name: Livestream Player\n\nkeywords:\n  - Livestream\n  - Video\n\ncategories:\n  - AudioVideo\n  - Audio\n  - Video\n  - Network\n\nstartup_notify: true\n\nmetainfo: assets/io.github.SlotSun.Slive.metainfo.xml\n"
  },
  {
    "path": "simple_live_app/linux/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name, change BINARY_NAME in the\n# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer\n# work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add preprocessor definitions for the application ID.\nadd_definitions(-DAPPLICATION_ID=\"${APPLICATION_ID}\")\n\n# Add dependency libraries. Add any application-specific dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter)\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\ntarget_link_libraries(${BINARY_NAME} PRIVATE ${MIMALLOC_LIB})\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\n"
  },
  {
    "path": "simple_live_app/linux/runner/main.cc",
    "content": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n  g_autoptr(MyApplication) app = my_application_new();\n  return g_application_run(G_APPLICATION(app), argc, argv);\n}\n"
  },
  {
    "path": "simple_live_app/linux/runner/my_application.cc",
    "content": "#include <filesystem> \nusing namespace std;\nusing namespace std::filesystem;\n\n#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#endif\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nstruct _MyApplication {\n  GtkApplication parent_instance;\n  char** dart_entrypoint_arguments;\n};\n\nG_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)\n\n// Called when first Flutter frame received.\nstatic void first_frame_cb(MyApplication* self, FlView *view)\n{\n  gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));\n}\n\n// Implements GApplication::activate.\nstatic void my_application_activate(GApplication* application) {\n  MyApplication* self = MY_APPLICATION(application);\n\n  GList* list = gtk_application_get_windows(GTK_APPLICATION(application));\n\n  GtkWindow* existing_window = list ? GTK_WINDOW(list->data) : NULL;\n\n  if (existing_window) {\n    gtk_window_present(existing_window);\n    return;\n  }\n\n  GtkWindow* window =\n      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));\n\n  const string iconFilename = \"assets/images/logo.png\";\n  path execDir = canonical(read_symlink(\"/proc/self/exe\")).parent_path();\n  path iconPath = execDir / \"data/flutter_assets\" / iconFilename;\n  gtk_window_set_icon_from_file(GTK_WINDOW(window), iconPath.c_str(), NULL);\n\n  // Use a header bar when running in GNOME as this is the common style used\n  // by applications and is the setup most users will be using (e.g. Ubuntu\n  // desktop).\n  // If running on X and not using GNOME then just use a traditional title bar\n  // in case the window manager does more exotic layout, e.g. tiling.\n  // If running on Wayland assume the header bar will work (may need changing\n  // if future cases occur).\n  gboolean use_header_bar = FALSE;\n#ifdef GDK_WINDOWING_X11\n  GdkScreen* screen = gtk_window_get_screen(window);\n  if (GDK_IS_X11_SCREEN(screen)) {\n    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);\n    if (g_strcmp0(wm_name, \"GNOME Shell\") != 0) {\n      use_header_bar = FALSE;\n    }\n  }\n#endif\n  if (use_header_bar) {\n    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());\n    gtk_widget_show(GTK_WIDGET(header_bar));\n    gtk_header_bar_set_title(header_bar, \"Slive\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  } else {\n    gtk_window_set_title(window, \"Slive\");\n  }\n\n  gtk_window_set_default_size(window, 1280, 720);\n\n  g_autoptr(FlDartProject) project = fl_dart_project_new();\n  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);\n\n  FlView* view = fl_view_new(project);\n  GdkRGBA background_color;\n  // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent.\n  gdk_rgba_parse(&background_color, \"#000000\");\n  fl_view_set_background_color(view, &background_color);\n  gtk_widget_show(GTK_WIDGET(view));\n  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));\n\n  // Show the window when Flutter renders.\n  // Requires the view to be realized so we can start rendering.\n  g_signal_connect_swapped(view, \"first-frame\", G_CALLBACK(first_frame_cb), self);\n  gtk_widget_realize(GTK_WIDGET(view));\n\n  fl_register_plugins(FL_PLUGIN_REGISTRY(view));\n\n  gtk_widget_grab_focus(GTK_WIDGET(view));\n}\n\n// Implements GApplication::local_command_line.\nstatic gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {\n  MyApplication* self = MY_APPLICATION(application);\n  // Strip out the first argument as it is the binary name.\n  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);\n\n  g_autoptr(GError) error = nullptr;\n  if (!g_application_register(application, nullptr, &error)) {\n     g_warning(\"Failed to register: %s\", error->message);\n     *exit_status = 1;\n     return TRUE;\n  }\n\n  g_application_activate(application);\n  *exit_status = 0;\n\n  return TRUE;\n}\n\n// Implements GApplication::startup.\nstatic void my_application_startup(GApplication* application) {\n  //MyApplication* self = MY_APPLICATION(object);\n\n  // Perform any actions required at application startup.\n\n  G_APPLICATION_CLASS(my_application_parent_class)->startup(application);\n}\n\n// Implements GApplication::shutdown.\nstatic void my_application_shutdown(GApplication* application) {\n  //MyApplication* self = MY_APPLICATION(object);\n\n  // Perform any actions required at application shutdown.\n\n  G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);\n}\n\n// Implements GObject::dispose.\nstatic void my_application_dispose(GObject* object) {\n  MyApplication* self = MY_APPLICATION(object);\n  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);\n  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);\n}\n\nstatic void my_application_class_init(MyApplicationClass* klass) {\n  G_APPLICATION_CLASS(klass)->activate = my_application_activate;\n  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;\n  G_APPLICATION_CLASS(klass)->startup = my_application_startup;\n  G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;\n  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;\n}\n\nstatic void my_application_init(MyApplication* self) {}\n\nMyApplication* my_application_new() {\n  // Set the program name to the application ID, which helps various systems\n  // like GTK and desktop environments map this running application to its\n  // corresponding .desktop file. This ensures better integration by allowing\n  // the application to be recognized beyond its binary name.\n  g_set_prgname(APPLICATION_ID);\n\n  return MY_APPLICATION(g_object_new(my_application_get_type(),\n                                     \"application-id\", APPLICATION_ID,\n                                    //  \"flags\", G_APPLICATION_FLAGS_NONE,\n                                     nullptr));\n}\n"
  },
  {
    "path": "simple_live_app/linux/runner/my_application.h",
    "content": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,\n                     GtkApplication)\n\n/**\n * my_application_new:\n *\n * Creates a new Flutter-based application.\n *\n * Returns: a new #MyApplication.\n */\nMyApplication* my_application_new();\n\n#endif  // FLUTTER_MY_APPLICATION_H_\n"
  },
  {
    "path": "simple_live_app/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/dgph\n**/xcuserdata/\n"
  },
  {
    "path": "simple_live_app/macos/Flutter/Flutter-Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/macos/Flutter/Flutter-Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/macos/Flutter/GeneratedPluginRegistrant.swift",
    "content": "//\n//  Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\nimport connectivity_plus\nimport device_info_plus\nimport dynamic_color\nimport file_picker\nimport firebase_analytics\nimport firebase_core\nimport firebase_crashlytics\nimport flutter_inappwebview_macos\nimport media_kit_libs_macos_video\nimport media_kit_video\nimport network_info_plus\nimport package_info_plus\nimport screen_brightness_macos\nimport screen_retriever_macos\nimport share_plus\nimport url_launcher_macos\nimport volume_controller\nimport wakelock_plus\nimport window_manager\n\nfunc RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {\n  ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: \"ConnectivityPlusPlugin\"))\n  DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: \"DeviceInfoPlusMacosPlugin\"))\n  DynamicColorPlugin.register(with: registry.registrar(forPlugin: \"DynamicColorPlugin\"))\n  FilePickerPlugin.register(with: registry.registrar(forPlugin: \"FilePickerPlugin\"))\n  FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: \"FirebaseAnalyticsPlugin\"))\n  FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: \"FLTFirebaseCorePlugin\"))\n  FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: \"FLTFirebaseCrashlyticsPlugin\"))\n  InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: \"InAppWebViewFlutterPlugin\"))\n  MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: \"MediaKitLibsMacosVideoPlugin\"))\n  MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: \"MediaKitVideoPlugin\"))\n  NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: \"NetworkInfoPlusPlugin\"))\n  FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: \"FPPPackageInfoPlusPlugin\"))\n  ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: \"ScreenBrightnessMacosPlugin\"))\n  ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: \"ScreenRetrieverMacosPlugin\"))\n  SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: \"SharePlusMacosPlugin\"))\n  UrlLauncherPlugin.register(with: registry.registrar(forPlugin: \"UrlLauncherPlugin\"))\n  VolumeControllerPlugin.register(with: registry.registrar(forPlugin: \"VolumeControllerPlugin\"))\n  WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: \"WakelockPlusMacosPlugin\"))\n  WindowManagerPlugin.register(with: registry.registrar(forPlugin: \"WindowManagerPlugin\"))\n}\n"
  },
  {
    "path": "simple_live_app/macos/Podfile",
    "content": "platform :osx, '10.15'\n\n# CocoaPods analytics sends network stats synchronously affecting flutter build latency.\nENV['COCOAPODS_DISABLE_STATS'] = 'true'\n\nproject 'Runner', {\n  'Debug' => :debug,\n  'Profile' => :release,\n  'Release' => :release,\n}\n\ndef flutter_root\n  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)\n  unless File.exist?(generated_xcode_build_settings_path)\n    raise \"#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \\\"flutter pub get\\\" is executed first\"\n  end\n\n  File.foreach(generated_xcode_build_settings_path) do |line|\n    matches = line.match(/FLUTTER_ROOT\\=(.*)/)\n    return matches[1].strip if matches\n  end\n  raise \"FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \\\"flutter pub get\\\"\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_macos_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))\n  target 'RunnerTests' do\n    inherit! :search_paths\n  end\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_macos_build_settings(target)\n  end\nend\n"
  },
  {
    "path": "simple_live_app/macos/Runner/AppDelegate.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\n@NSApplicationMain\nclass AppDelegate: FlutterAppDelegate {\n  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n    \"images\": [\n        {\n            \"size\": \"16x16\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-16.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"16x16\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-16@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"32x32\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-32.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"32x32\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-32@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"128x128\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-128.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"128x128\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-128@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"256x256\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-256.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"256x256\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-256@2x.png\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"size\": \"512x512\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-512.png\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"size\": \"512x512\",\n            \"idiom\": \"mac\",\n            \"filename\": \"icon-512@2x.png\",\n            \"scale\": \"2x\"\n        }\n    ],\n    \"info\": {\n        \"version\": 1,\n        \"author\": \"icon.wuruihong.com\"\n    }\n}"
  },
  {
    "path": "simple_live_app/macos/Runner/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"14490.70\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"14490.70\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"applicationMenu\" destination=\"uQy-DD-JDr\" id=\"XBo-yE-nKs\"/>\n                <outlet property=\"mainFlutterWindow\" destination=\"QvC-M9-y7g\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"APP_NAME\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"APP_NAME\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About APP_NAME\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"orderFrontStandardAboutPanel:\" target=\"-1\" id=\"Exp-CZ-Vem\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide APP_NAME\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit APP_NAME\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"pasteAsPlainText:\" target=\"-1\" id=\"cEh-KX-wJQ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cD7-Qs-BN4\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"NDo-RZ-v9R\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"HOh-sY-3ay\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"vFj-Ks-hy3\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"fz7-VC-reM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"7w6-Qz-0kB\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"muD-Qn-j4w\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"2lM-Qi-WAP\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"oku-mr-iSq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"3IJ-Se-DZD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"ptq-xd-QOA\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"oCt-pO-9gS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"Gip-E3-Fov\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"R1I-Nq-Kbl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"DvP-Fe-Py6\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"sPh-Tk-edu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"iUZ-b5-hil\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"26H-TL-nsh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"654-Ng-kyl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"dX8-6p-jy9\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                        <items>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"dU3-MA-1Rq\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"EPT-qC-fAb\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"rJ0-wn-3NY\"/>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"142\" y=\"-258\"/>\n        </menu>\n        <window title=\"APP_NAME\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"MainFlutterWindow\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"335\" y=\"390\" width=\"800\" height=\"600\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"600\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Configs/AppInfo.xcconfig",
    "content": "// Application-level settings for the Runner target.\n//\n// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the\n// future. If not, the values below would default to using the project name when this becomes a\n// 'flutter create' template.\n\n// The application's name. By default this is also the title of the Flutter window.\nPRODUCT_NAME = Simple Live\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2023 com.xycz. All rights reserved.\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Configs/Warnings.xcconfig",
    "content": "WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings\nGCC_WARN_UNDECLARED_SELECTOR = YES\nCLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES\nCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nCLANG_WARN_PRAGMA_PACK = YES\nCLANG_WARN_STRICT_PROTOTYPES = YES\nCLANG_WARN_COMMA = YES\nGCC_WARN_STRICT_SELECTOR_MATCH = YES\nCLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES\nCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES\nGCC_WARN_SHADOW = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\n"
  },
  {
    "path": "simple_live_app/macos/Runner/DebugProfile.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.cs.allow-jit</key>\n\t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n    <true/>\n\t<key>com.apple.security.files.user-selected.read-write</key>\n  \t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(FLUTTER_BUILD_NAME)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>$(PRODUCT_COPYRIGHT)</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/macos/Runner/MainFlutterWindow.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n  override func awakeFromNib() {\n    let flutterViewController = FlutterViewController()\n    let windowFrame = self.frame\n    self.contentViewController = flutterViewController\n    self.setFrame(windowFrame, display: true)\n\n    RegisterGeneratedPlugins(registry: flutterViewController)\n\n    super.awakeFromNib()\n  }\n}\n"
  },
  {
    "path": "simple_live_app/macos/Runner/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n    <true/>\n\t<key>com.apple.security.files.user-selected.read-write</key>\n  \t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/macos/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t33CC111E2044C6BF0003C045 /* ShellScript */,\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Flutter Assemble\";\n\t\t\tproductName = FLX;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };\n\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };\n\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };\n\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };\n\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };\n\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };\n\t\t33E8CA35C15B26E48DA4EBD7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C1377411379D99120C8F83 /* Pods_Runner.framework */; };\n\t\t9E6C57AAF7AD9FA590476061 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 33CC10E52044A3C60003C045 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 33CC10EC2044A3C60003C045;\n\t\t\tremoteInfo = Runner;\n\t\t};\n\t\t33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 33CC10E52044A3C60003C045 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 33CC111A2044C6BA0003C045;\n\t\t\tremoteInfo = FLX;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t33CC110E2044A8840003C045 /* Bundle Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Bundle Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t22F821424EC724046ABB4672 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.debug.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = \"<group>\"; };\n\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = \"<group>\"; };\n\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = \"<group>\"; };\n\t\t33CC10ED2044A3C60003C045 /* simple_live_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = simple_live_app.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\t33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = \"<group>\"; };\n\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = \"<group>\"; };\n\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = \"Flutter-Generated.xcconfig\"; path = \"ephemeral/Flutter-Generated.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = \"<group>\"; };\n\t\t33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = \"<group>\"; };\n\t\t63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-RunnerTests.debug.xcconfig\"; path = \"Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-RunnerTests.profile.xcconfig\"; path = \"Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\tAEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB51A5741C0A7E288C9368C1A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.profile.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tC7907028FBA71F2E559043FF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.release.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tD4C1377411379D99120C8F83 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-RunnerTests.release.xcconfig\"; path = \"Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t331C80D2294CF70F00263BE5 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9E6C57AAF7AD9FA590476061 /* Pods_RunnerTests.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t33CC10EA2044A3C60003C045 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33E8CA35C15B26E48DA4EBD7 /* Pods_Runner.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t24357D9109B54496E939BAD5 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t22F821424EC724046ABB4672 /* Pods-Runner.debug.xcconfig */,\n\t\t\t\tC7907028FBA71F2E559043FF /* Pods-Runner.release.xcconfig */,\n\t\t\t\tB51A5741C0A7E288C9368C1A /* Pods-Runner.profile.xcconfig */,\n\t\t\t\t63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */,\n\t\t\t\tD9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */,\n\t\t\t\t7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t331C80D6294CF71000263BE5 /* RunnerTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t331C80D7294CF71000263BE5 /* RunnerTests.swift */,\n\t\t\t);\n\t\t\tpath = RunnerTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33BA886A226E78AF003329D5 /* Configs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */,\n\t\t\t);\n\t\t\tpath = Configs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10E42044A3C60003C045 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33FAB671232836740065AC1E /* Runner */,\n\t\t\t\t33CEB47122A05771004F2AC0 /* Flutter */,\n\t\t\t\t331C80D6294CF71000263BE5 /* RunnerTests */,\n\t\t\t\t33CC10EE2044A3C60003C045 /* Products */,\n\t\t\t\tD73912EC22F37F3D000D13A0 /* Frameworks */,\n\t\t\t\t24357D9109B54496E939BAD5 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10EE2044A3C60003C045 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10ED2044A3C60003C045 /* simple_live_app.app */,\n\t\t\t\t331C80D5294CF71000263BE5 /* RunnerTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC11242044D66E0003C045 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */,\n\t\t\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */,\n\t\t\t\t33CC10F72044A3C60003C045 /* Info.plist */,\n\t\t\t);\n\t\t\tname = Resources;\n\t\t\tpath = ..;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CEB47122A05771004F2AC0 /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,\n\t\t\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,\n\t\t\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,\n\t\t\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,\n\t\t\t);\n\t\t\tpath = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33FAB671232836740065AC1E /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */,\n\t\t\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,\n\t\t\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */,\n\t\t\t\t33E51914231749380026EE4D /* Release.entitlements */,\n\t\t\t\t33CC11242044D66E0003C045 /* Resources */,\n\t\t\t\t33BA886A226E78AF003329D5 /* Configs */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD73912EC22F37F3D000D13A0 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD4C1377411379D99120C8F83 /* Pods_Runner.framework */,\n\t\t\t\tAEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t331C80D4294CF70F00263BE5 /* RunnerTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget \"RunnerTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t1C0ABA43D8228815BB859BFE /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t331C80D1294CF70F00263BE5 /* Sources */,\n\t\t\t\t331C80D2294CF70F00263BE5 /* Frameworks */,\n\t\t\t\t331C80D3294CF70F00263BE5 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t331C80DA294CF71000263BE5 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = RunnerTests;\n\t\t\tproductName = RunnerTests;\n\t\t\tproductReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t33CC10EC2044A3C60003C045 /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t671FAACF9F58D03A0C709E83 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t33CC10E92044A3C60003C045 /* Sources */,\n\t\t\t\t33CC10EA2044A3C60003C045 /* Frameworks */,\n\t\t\t\t33CC10EB2044A3C60003C045 /* Resources */,\n\t\t\t\t33CC110E2044A8840003C045 /* Bundle Framework */,\n\t\t\t\t3399D490228B24CF009A79C7 /* ShellScript */,\n\t\t\t\tA261E453836422CA4D990339 /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 33CC10ED2044A3C60003C045 /* simple_live_app.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t33CC10E52044A3C60003C045 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0920;\n\t\t\t\tLastUpgradeCheck = 1300;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t331C80D4294CF70F00263BE5 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 14.0;\n\t\t\t\t\t\tTestTargetID = 33CC10EC2044A3C60003C045;\n\t\t\t\t\t};\n\t\t\t\t\t33CC10EC2044A3C60003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.Sandbox = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t33CC111A2044C6BA0003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 33CC10E42044A3C60003C045;\n\t\t\tproductRefGroup = 33CC10EE2044A3C60003C045 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t33CC10EC2044A3C60003C045 /* Runner */,\n\t\t\t\t331C80D4294CF70F00263BE5 /* RunnerTests */,\n\t\t\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t331C80D3294CF70F00263BE5 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t33CC10EB2044A3C60003C045 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,\n\t\t\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t1C0ABA43D8228815BB859BFE /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t3399D490228B24CF009A79C7 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"echo \\\"$PRODUCT_NAME.app\\\" > \\\"$PROJECT_DIR\\\"/Flutter/ephemeral/.app_filename && \\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh embed\\n\";\n\t\t};\n\t\t33CC111E2044C6BF0003C045 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterInputs.xcfilelist,\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\tFlutter/ephemeral/tripwire,\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterOutputs.xcfilelist,\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire\";\n\t\t};\n\t\t671FAACF9F58D03A0C709E83 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tA261E453836422CA4D990339 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t331C80D1294CF70F00263BE5 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t33CC10E92044A3C60003C045 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,\n\t\t\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,\n\t\t\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 33CC10EC2044A3C60003C045 /* Runner */;\n\t\t\ttargetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;\n\t\t\ttargetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F52044A3C60003C045 /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t331C80DB294CF71000263BE5 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t331C80DC294CF71000263BE5 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = D9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t331C80DD294CF71000263BE5 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CE9231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEA231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEB231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t33CC10F92044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FA2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC10FC2044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FD2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC111C2044C6BA0003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC111D2044C6BA0003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget \"RunnerTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t331C80DB294CF71000263BE5 /* Debug */,\n\t\t\t\t331C80DC294CF71000263BE5 /* Release */,\n\t\t\t\t331C80DD294CF71000263BE5 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10F92044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FA2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CE9231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10FC2044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FD2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CEA231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC111C2044C6BA0003C045 /* Debug */,\n\t\t\t\t33CC111D2044C6BA0003C045 /* Release */,\n\t\t\t\t338D0CEB231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 33CC10E52044A3C60003C045 /* Project object */;\n}\n"
  },
  {
    "path": "simple_live_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1300\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n               BuildableName = \"simple_live_app.app\"\n               BlueprintName = \"Runner\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"simple_live_app.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            parallelizable = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"331C80D4294CF70F00263BE5\"\n               BuildableName = \"RunnerTests.xctest\"\n               BlueprintName = \"RunnerTests\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"simple_live_app.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"simple_live_app.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "simple_live_app/macos/Runner.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Runner.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "simple_live_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "simple_live_app/macos/RunnerTests/RunnerTests.swift",
    "content": "import FlutterMacOS\nimport Cocoa\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n  func testExample() {\n    // If you add code to the Runner application, consider adding tests here.\n    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.\n  }\n\n}\n"
  },
  {
    "path": "simple_live_app/macos/packaging/dmg/make_config.yaml",
    "content": "title: Simple Live\ncontents:\n  - x: 448\n    y: 344\n    type: link\n    path: \"/Applications\"\n  - x: 192\n    y: 344\n    type: file\n    path: Simple Live.app\n"
  },
  {
    "path": "simple_live_app/pubspec.yaml",
    "content": "name: simple_live_app\nversion: 1.8.7+10807\npublish_to: none\ndescription: \"Slive APP\"\nenvironment: \n  sdk: '>=3.0.5 <4.0.0'\n  flutter: 3.38.6\n\ndependencies: \n  flutter: \n    sdk: flutter\n  flutter_localizations: \n    sdk: flutter\n\n  simple_live_core:\n    path: ../simple_live_core\n  # 图标\n  cupertino_icons: ^1.0.8\n  remixicon: ^1.4.1 # Remix 图标\n\n  # 框架、工具\n  archive: ^4.0.7 # 文件压缩\n  get: ^4.7.2 # 状态管理、路由管理、国际化\n  dio: ^5.4.3+1 # 网络请求\n  hive: 2.2.3 # 持久化存储\n  hive_flutter: 1.1.0 # 持久化存储\n  logger: ^2.0.2 # 日志\n  firebase_analytics: ^12.1.0\n  firebase_crashlytics: ^5.0.6 # firebase\n  firebase_core: ^4.3.0\n  intl: ^0.20.2 # 国际化\n  pinyin: ^3.3.0\n  qr_flutter: ^4.1.0 # 二维码生成\n  dynamic_color: ^1.8.1 # 动态颜色\n  path: any\n  udp: ^5.0.3 # UDP\n  fractional_indexing_dart: ^1.0.7\n  synchronized: ^3.3.1 # 线程安全\n  collection: ^1.18.0\n  pool: ^1.5.2 #并发控制器\n\n  # ffi\n  rust_lib_simple_live_app:\n    path: rust_builder\n  flutter_rust_bridge: 2.11.1\n\n  # Widget\n  flutter_staggered_grid_view: ^0.7.0 # 瀑布流 / GridView\n  flutter_easyrefresh: 2.2.2 # 下拉刷新、上拉加载\n  extended_image: ^10.0.1 # 拓展 Image ，支持缓存\n  flutter_smart_dialog: ^4.9.8+9 # 各种弹窗 Toast / Dialog / Popup\n  sticky_headers: ^0.3.0+2 # 吸顶\n  lottie: ^3.3.2 # Lottie 动画\n  canvas_danmaku: ^0.3.1 # 弹幕库\n\n  # 系统交互\n  package_info_plus: ^8.3.1 # 包信息\n  device_info_plus: ^12.2.0 # 设备信息\n  url_launcher: ^6.3.1 # 打开链接\n  share_plus: ^12.0.1 # 分享\n  path_provider: ^2.1.5 # 常用路径\n  cross_file: ^0.3.5+1 # 跨平台文件\n  # permission_handler: ^12.0.1 # 权限处理\n  permission_handler_apple: ^9.4.7\n  permission_handler_android: ^13.0.1\n  permission_handler_platform_interface: ^4.3.0\n  flutter_image_gallery_saver: ^1.1.3 # 图片保存到相册\n  screen_brightness: ^2.1.7 # 亮度控制\n  auto_orientation_v2: ^2.3.7 # 屏幕方向\n  wakelock_plus: ^1.3.3 # 屏幕常亮\n  file_picker: ^10.3.8 # 文件选择\n  window_manager: ^0.5.0 # 窗口管理\n  floating: ^6.0.0 # PIP 画中画\n  flutter_inappwebview:\n    git:\n      url: https://github.com/guide-inc-org/guide-flutter_inappwebview.git\n      path: flutter_inappwebview\n      ref: sbi_fx_pc/v6.2.0-beta.3\n  connectivity_plus: ^7.0.0 # 网络状态\n  qr_code_scanner_plus: ^2.0.14 # 二维码扫描\n\n  # 网络相关\n  webdav_client: ^1.2.2 # WebDAV\n  shelf: ^1.4.2\n  shelf_router: ^1.1.4\n  network_info_plus: ^7.0.0\n  signalr_netcore: ^1.4.4 # SignalR\n\n  # 视频播放\n  volume_controller: any\n  media_kit:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./media_kit\n  media_kit_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./media_kit_video\n  media_kit_libs_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/universal/media_kit_libs_video\n\ndependency_overrides:\n  media_kit_libs_linux:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/linux/media_kit_libs_linux\n  media_kit_libs_ios_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/ios/media_kit_libs_ios_video\n  media_kit_libs_android_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/android/media_kit_libs_android_video\n  media_kit_libs_windows_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/windows/media_kit_libs_windows_video\n  media_kit_libs_macos_video:\n    git:\n      url: https://github.com/Predidit/media-kit.git\n      ref: 7b248251fc274f986635876946130f2afc78c959\n      path: ./libs/macos/media_kit_libs_macos_video\n\ndev_dependencies:\n  flutter_lints: ^6.0.0\n  build_runner: ^2.3.3\n  hive_generator: ^2.0.0\n  flutter_launcher_icons: ^0.14.4\n  flutter_test: \n    sdk: flutter\n  integration_test:\n    sdk: flutter\n\nflutter_launcher_icons:\n  android: \"ic_launcher\"\n  ios: true\n  image_path: \"assets/logo.png\"\n  min_sdk_android: 21\n  windows:\n    generate: true\n    image_path: \"assets/logo.png\"\n    icon_size: 256\n  macos:\n    generate: true\n    image_path: \"assets/logo.png\"\n\nflutter: \n  fonts:\n    - family: iconfont\n      fonts:\n        - asset: assets/iconfont/live_icons.ttf\n  uses-material-design: true\n  assets:\n    - assets/statement.txt\n    - assets/images/\n    - assets/icons/\n    - assets/lotties/\n    - assets/fonts/fonts-manifest.json\n    - shorebird.yaml\n"
  },
  {
    "path": "simple_live_app/rust/.gitignore",
    "content": "/target\n"
  },
  {
    "path": "simple_live_app/rust/Cargo.toml",
    "content": "[package]\nname = \"rust_lib_simple_live_app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\"]\n\n[dependencies]\nflutter_rust_bridge = \"=2.11.1\"\nregex = \"1.12.2\"\nxxhash-rust = { version = \"0.8.5\", features = [\"xxh3\"] }\nlazy_static = \"1.4.0\"\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = ['cfg(frb_expand)'] }\n"
  },
  {
    "path": "simple_live_app/rust/src/api/danmaku_mask.rs",
    "content": "use regex::Regex;\nuse std::collections::{HashMap, HashSet};\nuse xxhash_rust::xxh3::xxh3_64;\n\n/// DanmakuMask: 滑动窗口 + 分桶 + 频控\n#[flutter_rust_bridge::frb(opaque)]\npub struct DanmakuMask {\n    base_window_ms: u32,     // 基础窗口（ms）\n    bucket_count: u16,       // 桶数量\n    max_frequency: u16,      // 最大允许频次\n\n    use_normalization: bool,\n    use_frequency_control: bool,\n    adaptive_window: bool,\n\n    // 运行时状态\n    window_ms: u32,\n    bucket_size_ms: u32,\n\n    current_bucket: usize,  // Vec 索引\n    last_shift_ms: u64,     // 上次滑动的时间戳（ms）\n\n    buckets: Vec<HashSet<u64>>,  // 每个桶存 hash\n    freq_map: HashMap<u64, u16>, // hash -> 频次\n\n    norm_re_space: Option<Regex>,\n    norm_re_punct: Option<Regex>,\n}\n\n#[flutter_rust_bridge::frb(sync)]\nimpl DanmakuMask {\n    /// 构造函数（会生成 Dart 构造器）\n    pub fn new(\n        base_window_ms: u32,\n        bucket_count: u16,\n        use_normalization: bool,\n        use_frequency_control: bool,\n        max_frequency: u16,\n        adaptive_window: bool,\n    ) -> Self {\n        let bucket_count_usize = bucket_count.max(1) as usize;\n        let bucket_size_ms = base_window_ms / bucket_count.max(1) as u32;\n\n        let norm_re_space = use_normalization\n            .then(|| Regex::new(r\"\\s+\").unwrap());\n        let norm_re_punct = use_normalization\n            .then(|| Regex::new(r\"[~!！?？,.，。]\").unwrap());\n\n        Self {\n            base_window_ms,\n            bucket_count,\n            max_frequency,\n            use_normalization,\n            use_frequency_control,\n            adaptive_window,\n            window_ms: base_window_ms,\n            bucket_size_ms,\n            current_bucket: 0,\n            last_shift_ms: 0,\n            buckets: (0..bucket_count_usize)\n                .map(|_| HashSet::with_capacity(128))\n                .collect(),\n            freq_map: HashMap::with_capacity(1024),\n            norm_re_space,\n            norm_re_punct,\n        }\n    }\n\n    /// 文本归一化\n    fn normalize(&self, text: &str) -> String {\n        if !self.use_normalization {\n            return text.to_owned();\n        }\n\n        let mut s = text.trim().to_lowercase();\n        if let Some(re) = &self.norm_re_space {\n            s = re.replace_all(&s, \"\").to_string();\n        }\n        if let Some(re) = &self.norm_re_punct {\n            s = re.replace_all(&s, \"\").to_string();\n        }\n        s\n    }\n\n    fn shift_if_needed(&mut self, now_ms: u64) {\n        if self.last_shift_ms == 0 {\n            self.last_shift_ms = now_ms;\n            return;\n        }\n\n        while now_ms.saturating_sub(self.last_shift_ms)\n            >= self.bucket_size_ms as u64\n        {\n            self.last_shift_ms += self.bucket_size_ms as u64;\n\n            self.current_bucket =\n                (self.current_bucket + 1) % self.bucket_count as usize;\n\n            let expired = &mut self.buckets[self.current_bucket];\n            for &hash in expired.iter() {\n                if let Some(v) = self.freq_map.get_mut(&hash) {\n                    if *v <= 1 {\n                        self.freq_map.remove(&hash);\n                    } else {\n                        *v -= 1;\n                    }\n                }\n            }\n            expired.clear();\n        }\n    }\n\n    /// 根据压力自适应窗口\n    fn adapt_window(&mut self) {\n        if !self.adaptive_window {\n            return;\n        }\n\n        let total_items: usize =\n            self.buckets.iter().map(|b| b.len()).sum();\n\n        if total_items > 300 {\n            self.window_ms = (self.base_window_ms / 2).max(1500);\n        } else if total_items < 50 {\n            self.window_ms = self.base_window_ms;\n        }\n\n        self.bucket_size_ms =\n            self.window_ms / self.bucket_count.max(1) as u32;\n    }\n\n\n\n    /// 重置状态\n    pub fn reset(&mut self) {\n        for bucket in &mut self.buckets {\n            bucket.clear();\n        }\n        self.freq_map.clear();\n        self.current_bucket = 0;\n        self.last_shift_ms = 0;\n        self.window_ms = self.base_window_ms;\n        self.bucket_size_ms =\n            self.window_ms / self.bucket_count.max(1) as u32;\n    }\n\n    pub fn dispose(self){\n        // 消费所有权\n    }\n}\n\n#[flutter_rust_bridge::frb]\nimpl DanmakuMask {\n    /// 批量判断是否允许\n    /// 返回 Vec<u8>：1 = 允许，0 = 屏蔽\n    pub fn allow_list_batch(\n        &mut self,\n        texts: Vec<String>,\n        now_ms: u64,\n    ) -> Vec<u8> {\n        self.shift_if_needed(now_ms);\n        self.adapt_window();\n\n        let mut results = Vec::with_capacity(texts.len());\n\n        for text in texts {\n            let normalized = self.normalize(&text);\n            let hash = xxh3_64(normalized.as_bytes());\n\n            let mut allowed = true;\n\n            if self.freq_map.contains_key(&hash) {\n                allowed = false;\n            }\n\n            if allowed && self.use_frequency_control {\n                let freq = *self.freq_map.get(&hash).unwrap_or(&0u16);\n                if freq >= self.max_frequency {\n                    allowed = false;\n                }\n            }\n\n            if allowed {\n                self.buckets[self.current_bucket].insert(hash);\n                *self.freq_map.entry(hash).or_insert(0) += 1;\n            }\n\n            results.push(if allowed { 1 } else { 0 });\n        }\n\n        results\n    }\n}"
  },
  {
    "path": "simple_live_app/rust/src/api/mod.rs",
    "content": "pub mod simple;\npub mod danmaku_mask;\n"
  },
  {
    "path": "simple_live_app/rust/src/api/simple.rs",
    "content": "#[flutter_rust_bridge::frb(init)]\npub fn init_app() {\n    // Default utilities - feel free to customize\n    flutter_rust_bridge::setup_default_user_utils();\n}"
  },
  {
    "path": "simple_live_app/rust/src/frb_generated.rs",
    "content": "// This file is automatically generated, so please do not edit it.\n// @generated by `flutter_rust_bridge`@ 2.11.1.\n\n#![allow(\n    non_camel_case_types,\n    unused,\n    non_snake_case,\n    clippy::needless_return,\n    clippy::redundant_closure_call,\n    clippy::redundant_closure,\n    clippy::useless_conversion,\n    clippy::unit_arg,\n    clippy::unused_unit,\n    clippy::double_parens,\n    clippy::let_and_return,\n    clippy::too_many_arguments,\n    clippy::match_single_binding,\n    clippy::clone_on_copy,\n    clippy::let_unit_value,\n    clippy::deref_addrof,\n    clippy::explicit_auto_deref,\n    clippy::borrow_deref_ref,\n    clippy::needless_borrow\n)]\n\n// Section: imports\n\nuse crate::api::danmaku_mask::*;\nuse flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};\nuse flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};\nuse flutter_rust_bridge::{Handler, IntoIntoDart};\n\n// Section: boilerplate\n\nflutter_rust_bridge::frb_generated_boilerplate!(\n    default_stream_sink_codec = SseCodec,\n    default_rust_opaque = RustOpaqueMoi,\n    default_rust_auto_opaque = RustAutoOpaqueMoi,\n);\npub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = \"2.11.1\";\npub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1540820557;\n\n// Section: executor\n\nflutter_rust_bridge::frb_generated_default_handler!();\n\n// Section: wire_funcs\n\nfn wire__crate__api__danmaku_mask__DanmakuMask_allow_list_batch_impl(\n    port_: flutter_rust_bridge::for_generated::MessagePort,\n    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len_: i32,\n    data_len_: i32,\n) {\n    FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(\n        flutter_rust_bridge::for_generated::TaskInfo {\n            debug_name: \"DanmakuMask_allow_list_batch\",\n            port: Some(port_),\n            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,\n        },\n        move || {\n            let message = unsafe {\n                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(\n                    ptr_,\n                    rust_vec_len_,\n                    data_len_,\n                )\n            };\n            let mut deserializer =\n                flutter_rust_bridge::for_generated::SseDeserializer::new(message);\n            let api_that = <RustOpaqueMoi<\n                flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>,\n            >>::sse_decode(&mut deserializer);\n            let api_texts = <Vec<String>>::sse_decode(&mut deserializer);\n            let api_now_ms = <u64>::sse_decode(&mut deserializer);\n            deserializer.end();\n            move |context| {\n                transform_result_sse::<_, ()>((move || {\n                    let mut api_that_guard = None;\n                    let decode_indices_ =\n                        flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![\n                            flutter_rust_bridge::for_generated::LockableOrderInfo::new(\n                                &api_that, 0, true,\n                            ),\n                        ]);\n                    for i in decode_indices_ {\n                        match i {\n                            0 => api_that_guard = Some(api_that.lockable_decode_sync_ref_mut()),\n                            _ => unreachable!(),\n                        }\n                    }\n                    let mut api_that_guard = api_that_guard.unwrap();\n                    let output_ok = Result::<_, ()>::Ok(\n                        crate::api::danmaku_mask::DanmakuMask::allow_list_batch(\n                            &mut *api_that_guard,\n                            api_texts,\n                            api_now_ms,\n                        ),\n                    )?;\n                    Ok(output_ok)\n                })())\n            }\n        },\n    )\n}\nfn wire__crate__api__danmaku_mask__DanmakuMask_dispose_impl(\n    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len_: i32,\n    data_len_: i32,\n) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {\n    FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(\n        flutter_rust_bridge::for_generated::TaskInfo {\n            debug_name: \"DanmakuMask_dispose\",\n            port: None,\n            mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,\n        },\n        move || {\n            let message = unsafe {\n                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(\n                    ptr_,\n                    rust_vec_len_,\n                    data_len_,\n                )\n            };\n            let mut deserializer =\n                flutter_rust_bridge::for_generated::SseDeserializer::new(message);\n            let api_that = <DanmakuMask>::sse_decode(&mut deserializer);\n            deserializer.end();\n            transform_result_sse::<_, ()>((move || {\n                let output_ok = Result::<_, ()>::Ok({\n                    crate::api::danmaku_mask::DanmakuMask::dispose(api_that);\n                })?;\n                Ok(output_ok)\n            })())\n        },\n    )\n}\nfn wire__crate__api__danmaku_mask__DanmakuMask_new_impl(\n    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len_: i32,\n    data_len_: i32,\n) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {\n    FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(\n        flutter_rust_bridge::for_generated::TaskInfo {\n            debug_name: \"DanmakuMask_new\",\n            port: None,\n            mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,\n        },\n        move || {\n            let message = unsafe {\n                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(\n                    ptr_,\n                    rust_vec_len_,\n                    data_len_,\n                )\n            };\n            let mut deserializer =\n                flutter_rust_bridge::for_generated::SseDeserializer::new(message);\n            let api_base_window_ms = <u32>::sse_decode(&mut deserializer);\n            let api_bucket_count = <u16>::sse_decode(&mut deserializer);\n            let api_use_normalization = <bool>::sse_decode(&mut deserializer);\n            let api_use_frequency_control = <bool>::sse_decode(&mut deserializer);\n            let api_max_frequency = <u16>::sse_decode(&mut deserializer);\n            let api_adaptive_window = <bool>::sse_decode(&mut deserializer);\n            deserializer.end();\n            transform_result_sse::<_, ()>((move || {\n                let output_ok = Result::<_, ()>::Ok(crate::api::danmaku_mask::DanmakuMask::new(\n                    api_base_window_ms,\n                    api_bucket_count,\n                    api_use_normalization,\n                    api_use_frequency_control,\n                    api_max_frequency,\n                    api_adaptive_window,\n                ))?;\n                Ok(output_ok)\n            })())\n        },\n    )\n}\nfn wire__crate__api__danmaku_mask__DanmakuMask_reset_impl(\n    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len_: i32,\n    data_len_: i32,\n) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {\n    FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(\n        flutter_rust_bridge::for_generated::TaskInfo {\n            debug_name: \"DanmakuMask_reset\",\n            port: None,\n            mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,\n        },\n        move || {\n            let message = unsafe {\n                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(\n                    ptr_,\n                    rust_vec_len_,\n                    data_len_,\n                )\n            };\n            let mut deserializer =\n                flutter_rust_bridge::for_generated::SseDeserializer::new(message);\n            let api_that = <RustOpaqueMoi<\n                flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>,\n            >>::sse_decode(&mut deserializer);\n            deserializer.end();\n            transform_result_sse::<_, ()>((move || {\n                let mut api_that_guard = None;\n                let decode_indices_ =\n                    flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![\n                        flutter_rust_bridge::for_generated::LockableOrderInfo::new(\n                            &api_that, 0, true,\n                        ),\n                    ]);\n                for i in decode_indices_ {\n                    match i {\n                        0 => api_that_guard = Some(api_that.lockable_decode_sync_ref_mut()),\n                        _ => unreachable!(),\n                    }\n                }\n                let mut api_that_guard = api_that_guard.unwrap();\n                let output_ok = Result::<_, ()>::Ok({\n                    crate::api::danmaku_mask::DanmakuMask::reset(&mut *api_that_guard);\n                })?;\n                Ok(output_ok)\n            })())\n        },\n    )\n}\nfn wire__crate__api__simple__init_app_impl(\n    port_: flutter_rust_bridge::for_generated::MessagePort,\n    ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len_: i32,\n    data_len_: i32,\n) {\n    FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(\n        flutter_rust_bridge::for_generated::TaskInfo {\n            debug_name: \"init_app\",\n            port: Some(port_),\n            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,\n        },\n        move || {\n            let message = unsafe {\n                flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(\n                    ptr_,\n                    rust_vec_len_,\n                    data_len_,\n                )\n            };\n            let mut deserializer =\n                flutter_rust_bridge::for_generated::SseDeserializer::new(message);\n            deserializer.end();\n            move |context| {\n                transform_result_sse::<_, ()>((move || {\n                    let output_ok = Result::<_, ()>::Ok({\n                        crate::api::simple::init_app();\n                    })?;\n                    Ok(output_ok)\n                })())\n            }\n        },\n    )\n}\n\n// Section: related_funcs\n\nflutter_rust_bridge::frb_generated_moi_arc_impl_value!(\n    flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>\n);\n\n// Section: dart2rust\n\nimpl SseDecode for DanmakuMask {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        let mut inner = <RustOpaqueMoi<\n            flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>,\n        >>::sse_decode(deserializer);\n        return flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(inner);\n    }\n}\n\nimpl SseDecode\n    for RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>\n{\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        let mut inner = <usize>::sse_decode(deserializer);\n        return decode_rust_opaque_moi(inner);\n    }\n}\n\nimpl SseDecode for String {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        let mut inner = <Vec<u8>>::sse_decode(deserializer);\n        return String::from_utf8(inner).unwrap();\n    }\n}\n\nimpl SseDecode for bool {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u8().unwrap() != 0\n    }\n}\n\nimpl SseDecode for Vec<String> {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        let mut len_ = <i32>::sse_decode(deserializer);\n        let mut ans_ = vec![];\n        for idx_ in 0..len_ {\n            ans_.push(<String>::sse_decode(deserializer));\n        }\n        return ans_;\n    }\n}\n\nimpl SseDecode for Vec<u8> {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        let mut len_ = <i32>::sse_decode(deserializer);\n        let mut ans_ = vec![];\n        for idx_ in 0..len_ {\n            ans_.push(<u8>::sse_decode(deserializer));\n        }\n        return ans_;\n    }\n}\n\nimpl SseDecode for u16 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u16::<NativeEndian>().unwrap()\n    }\n}\n\nimpl SseDecode for u32 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u32::<NativeEndian>().unwrap()\n    }\n}\n\nimpl SseDecode for u64 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u64::<NativeEndian>().unwrap()\n    }\n}\n\nimpl SseDecode for u8 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u8().unwrap()\n    }\n}\n\nimpl SseDecode for () {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}\n}\n\nimpl SseDecode for usize {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_u64::<NativeEndian>().unwrap() as _\n    }\n}\n\nimpl SseDecode for i32 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {\n        deserializer.cursor.read_i32::<NativeEndian>().unwrap()\n    }\n}\n\nfn pde_ffi_dispatcher_primary_impl(\n    func_id: i32,\n    port: flutter_rust_bridge::for_generated::MessagePort,\n    ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len: i32,\n    data_len: i32,\n) {\n    // Codec=Pde (Serialization + dispatch), see doc to use other codecs\n    match func_id {\n        1 => wire__crate__api__danmaku_mask__DanmakuMask_allow_list_batch_impl(\n            port,\n            ptr,\n            rust_vec_len,\n            data_len,\n        ),\n        5 => wire__crate__api__simple__init_app_impl(port, ptr, rust_vec_len, data_len),\n        _ => unreachable!(),\n    }\n}\n\nfn pde_ffi_dispatcher_sync_impl(\n    func_id: i32,\n    ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,\n    rust_vec_len: i32,\n    data_len: i32,\n) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {\n    // Codec=Pde (Serialization + dispatch), see doc to use other codecs\n    match func_id {\n        2 => wire__crate__api__danmaku_mask__DanmakuMask_dispose_impl(ptr, rust_vec_len, data_len),\n        3 => wire__crate__api__danmaku_mask__DanmakuMask_new_impl(ptr, rust_vec_len, data_len),\n        4 => wire__crate__api__danmaku_mask__DanmakuMask_reset_impl(ptr, rust_vec_len, data_len),\n        _ => unreachable!(),\n    }\n}\n\n// Section: rust2dart\n\n// Codec=Dco (DartCObject based), see doc to use other codecs\nimpl flutter_rust_bridge::IntoDart for FrbWrapper<DanmakuMask> {\n    fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {\n        flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self.0)\n            .into_dart()\n    }\n}\nimpl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for FrbWrapper<DanmakuMask> {}\n\nimpl flutter_rust_bridge::IntoIntoDart<FrbWrapper<DanmakuMask>> for DanmakuMask {\n    fn into_into_dart(self) -> FrbWrapper<DanmakuMask> {\n        self.into()\n    }\n}\n\nimpl SseEncode for DanmakuMask {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        <RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>>::sse_encode(flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, MoiArc<_>>(self), serializer);\n    }\n}\n\nimpl SseEncode\n    for RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>\n{\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        let (ptr, size) = self.sse_encode_raw();\n        <usize>::sse_encode(ptr, serializer);\n        <i32>::sse_encode(size, serializer);\n    }\n}\n\nimpl SseEncode for String {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        <Vec<u8>>::sse_encode(self.into_bytes(), serializer);\n    }\n}\n\nimpl SseEncode for bool {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_u8(self as _).unwrap();\n    }\n}\n\nimpl SseEncode for Vec<String> {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        <i32>::sse_encode(self.len() as _, serializer);\n        for item in self {\n            <String>::sse_encode(item, serializer);\n        }\n    }\n}\n\nimpl SseEncode for Vec<u8> {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        <i32>::sse_encode(self.len() as _, serializer);\n        for item in self {\n            <u8>::sse_encode(item, serializer);\n        }\n    }\n}\n\nimpl SseEncode for u16 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_u16::<NativeEndian>(self).unwrap();\n    }\n}\n\nimpl SseEncode for u32 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_u32::<NativeEndian>(self).unwrap();\n    }\n}\n\nimpl SseEncode for u64 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_u64::<NativeEndian>(self).unwrap();\n    }\n}\n\nimpl SseEncode for u8 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_u8(self).unwrap();\n    }\n}\n\nimpl SseEncode for () {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}\n}\n\nimpl SseEncode for usize {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer\n            .cursor\n            .write_u64::<NativeEndian>(self as _)\n            .unwrap();\n    }\n}\n\nimpl SseEncode for i32 {\n    // Codec=Sse (Serialization based), see doc to use other codecs\n    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {\n        serializer.cursor.write_i32::<NativeEndian>(self).unwrap();\n    }\n}\n\n#[cfg(not(target_family = \"wasm\"))]\nmod io {\n    // This file is automatically generated, so please do not edit it.\n    // @generated by `flutter_rust_bridge`@ 2.11.1.\n\n    // Section: imports\n\n    use super::*;\n    use crate::api::danmaku_mask::*;\n    use flutter_rust_bridge::for_generated::byteorder::{\n        NativeEndian, ReadBytesExt, WriteBytesExt,\n    };\n    use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};\n    use flutter_rust_bridge::{Handler, IntoIntoDart};\n\n    // Section: boilerplate\n\n    flutter_rust_bridge::frb_generated_boilerplate_io!();\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn frbgen_simple_live_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n        ptr: *const std::ffi::c_void,\n    ) {\n        MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>::increment_strong_count(ptr as _);\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn frbgen_simple_live_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n        ptr: *const std::ffi::c_void,\n    ) {\n        MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>::decrement_strong_count(ptr as _);\n    }\n}\n#[cfg(not(target_family = \"wasm\"))]\npub use io::*;\n\n/// cbindgen:ignore\n#[cfg(target_family = \"wasm\")]\nmod web {\n    // This file is automatically generated, so please do not edit it.\n    // @generated by `flutter_rust_bridge`@ 2.11.1.\n\n    // Section: imports\n\n    use super::*;\n    use crate::api::danmaku_mask::*;\n    use flutter_rust_bridge::for_generated::byteorder::{\n        NativeEndian, ReadBytesExt, WriteBytesExt,\n    };\n    use flutter_rust_bridge::for_generated::wasm_bindgen;\n    use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;\n    use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};\n    use flutter_rust_bridge::{Handler, IntoIntoDart};\n\n    // Section: boilerplate\n\n    flutter_rust_bridge::frb_generated_boilerplate_web!();\n\n    #[wasm_bindgen]\n    pub fn rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n        ptr: *const std::ffi::c_void,\n    ) {\n        MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>::increment_strong_count(ptr as _);\n    }\n\n    #[wasm_bindgen]\n    pub fn rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDanmakuMask(\n        ptr: *const std::ffi::c_void,\n    ) {\n        MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<DanmakuMask>>::decrement_strong_count(ptr as _);\n    }\n}\n#[cfg(target_family = \"wasm\")]\npub use web::*;\n"
  },
  {
    "path": "simple_live_app/rust/src/lib.rs",
    "content": "pub mod api;\nmod frb_generated;\n"
  },
  {
    "path": "simple_live_app/rust_builder/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\nmigrate_working_dir/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.\n/pubspec.lock\n**/doc/api/\n.dart_tool/\nbuild/\n"
  },
  {
    "path": "simple_live_app/rust_builder/README.md",
    "content": "Please ignore this folder, which is just glue to build Rust with Flutter."
  },
  {
    "path": "simple_live_app/rust_builder/android/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.cxx\n"
  },
  {
    "path": "simple_live_app/rust_builder/android/build.gradle",
    "content": "// The Android Gradle Plugin builds the native code with the Android NDK.\n\ngroup 'com.flutter_rust_bridge.rust_lib_simple_live_app'\nversion '1.0'\n\nbuildscript {\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        // The Android Gradle Plugin knows how to build native code with the NDK.\n        classpath 'com.android.tools.build:gradle:7.3.0'\n    }\n}\n\nrootProject.allprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\napply plugin: 'com.android.library'\n\nandroid {\n    if (project.android.hasProperty(\"namespace\")) {\n        namespace 'com.flutter_rust_bridge.rust_lib_simple_live_app'\n    }\n\n    // Bumping the plugin compileSdkVersion requires all clients of this plugin\n    // to bump the version in their app.\n    compileSdkVersion 33\n\n    // Use the NDK version\n    // declared in /android/app/build.gradle file of the Flutter project.\n    // Replace it with a version number if this plugin requires a specfic NDK version.\n    // (e.g. ndkVersion \"23.1.7779620\")\n    ndkVersion android.ndkVersion\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    defaultConfig {\n        minSdkVersion 19\n    }\n}\n\napply from: \"../cargokit/gradle/plugin.gradle\"\ncargokit {\n    manifestDir = \"../../rust\"\n    libname = \"rust_lib_simple_live_app\"\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/android/settings.gradle",
    "content": "rootProject.name = 'rust_lib_simple_live_app'\n"
  },
  {
    "path": "simple_live_app/rust_builder/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.flutter_rust_bridge.rust_lib_simple_live_app\">\n</manifest>\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/.gitignore",
    "content": "target\n.dart_tool\n*.iml\n!pubspec.lock\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/LICENSE",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nCopyright 2022 Matej Knopp\n\n================================================================================\n\nMIT LICENSE\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 copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\nOR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n================================================================================\n\nAPACHE LICENSE, VERSION 2.0\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/README",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nExperimental repository to provide glue for seamlessly integrating cargo build\nwith flutter plugins and packages.\n\nSee https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/\nfor a tutorial on how to use Cargokit.\n\nExample plugin available at https://github.com/irondash/hello_rust_ffi_plugin.\n\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_pod.sh",
    "content": "#!/bin/sh\nset -e\n\nBASEDIR=$(dirname \"$0\")\n\n# Workaround for https://github.com/dart-lang/pub/issues/4010\nBASEDIR=$(cd \"$BASEDIR\" ; pwd -P)\n\n# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project\nNEW_PATH=`echo $PATH | tr \":\" \"\\n\" | grep -v \"Contents/Developer/\" | tr \"\\n\" \":\"`\n\nexport PATH=${NEW_PATH%?} # remove trailing :\n\nenv\n\n# Platform name (macosx, iphoneos, iphonesimulator)\nexport CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME\n\n# Arctive architectures (arm64, armv7, x86_64), space separated.\nexport CARGOKIT_DARWIN_ARCHS=$ARCHS\n\n# Current build configuration (Debug, Release)\nexport CARGOKIT_CONFIGURATION=$CONFIGURATION\n\n# Path to directory containing Cargo.toml.\nexport CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1\n\n# Temporary directory for build artifacts.\nexport CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR\n\n# Output directory for final artifacts.\nexport CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\n\n# Directory to store built tool artifacts.\nexport CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool\n\n# Directory inside root project. Not necessarily the top level directory of root project.\nexport CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT\n\nFLUTTER_EXPORT_BUILD_ENVIRONMENT=(\n  \"$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh\" # macOS\n  \"$PODS_ROOT/../Flutter/flutter_export_environment.sh\" # iOS\n)\n\nfor path in \"${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}\"\ndo\n  if [[ -f \"$path\" ]]; then\n    source \"$path\"\n  fi\ndone\n\nsh \"$BASEDIR/run_build_tool.sh\" build-pod \"$@\"\n\n# Make a symlink from built framework to phony file, which will be used as input to\n# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate\n# attribute on custom build phase)\nln -fs \"$OBJROOT/XCBuildData/build.db\" \"${BUILT_PRODUCTS_DIR}/cargokit_phony\"\nln -fs \"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}\" \"${BUILT_PRODUCTS_DIR}/cargokit_phony_out\"\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/README.md",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nA sample command-line application with an entrypoint in `bin/`, library code\nin `lib/`, and example unit test in `test/`.\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/analysis_options.yaml",
    "content": "# This is copied from Cargokit (which is the official way to use it currently)\n# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\n# This file configures the static analysis results for your project (errors,\n# warnings, and lints).\n#\n# This enables the 'recommended' set of lints from `package:lints`.\n# This set helps identify many issues that may lead to problems when running\n# or consuming Dart code, and enforces writing Dart using a single, idiomatic\n# style and format.\n#\n# If you want a smaller set of lints you can change this to specify\n# 'package:lints/core.yaml'. These are just the most critical lints\n# (the recommended set includes the core lints).\n# The core lints are also what is used by pub.dev for scoring packages.\n\ninclude: package:lints/recommended.yaml\n\n# Uncomment the following section to specify additional rules.\n\nlinter:\n  rules:\n    - prefer_relative_imports\n    - directives_ordering\n\n# analyzer:\n#   exclude:\n#     - path/to/excluded/files/**\n\n# For more information about the core and recommended set of lints, see\n# https://dart.dev/go/core-lints\n\n# For additional information about configuring this file, see\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/bin/build_tool.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'package:build_tool/build_tool.dart' as build_tool;\n\nvoid main(List<String> arguments) {\n  build_tool.runMain(arguments);\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/build_tool.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'src/build_tool.dart' as build_tool;\n\nFuture<void> runMain(List<String> args) async {\n  return build_tool.runMain(args);\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/android_environment.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\nimport 'dart:isolate';\nimport 'dart:math' as math;\n\nimport 'package:collection/collection.dart';\nimport 'package:path/path.dart' as path;\nimport 'package:version/version.dart';\n\nimport 'target.dart';\nimport 'util.dart';\n\nclass AndroidEnvironment {\n  AndroidEnvironment({\n    required this.sdkPath,\n    required this.ndkVersion,\n    required this.minSdkVersion,\n    required this.targetTempDir,\n    required this.target,\n  });\n\n  static void clangLinkerWrapper(List<String> args) {\n    final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG'];\n    if (clang == null) {\n      throw Exception(\n          \"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var\");\n    }\n    final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET'];\n    if (target == null) {\n      throw Exception(\n          \"cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var\");\n    }\n\n    runCommand(clang, [\n      target,\n      ...args,\n    ]);\n  }\n\n  /// Full path to Android SDK.\n  final String sdkPath;\n\n  /// Full version of Android NDK.\n  final String ndkVersion;\n\n  /// Minimum supported SDK version.\n  final int minSdkVersion;\n\n  /// Target directory for build artifacts.\n  final String targetTempDir;\n\n  /// Target being built.\n  final Target target;\n\n  bool ndkIsInstalled() {\n    final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);\n    final ndkPackageXml = File(path.join(ndkPath, 'package.xml'));\n    return ndkPackageXml.existsSync();\n  }\n\n  void installNdk({\n    required String javaHome,\n  }) {\n    final sdkManagerExtension = Platform.isWindows ? '.bat' : '';\n    final sdkManager = path.join(\n      sdkPath,\n      'cmdline-tools',\n      'latest',\n      'bin',\n      'sdkmanager$sdkManagerExtension',\n    );\n\n    log.info('Installing NDK $ndkVersion');\n    runCommand(sdkManager, [\n      '--install',\n      'ndk;$ndkVersion',\n    ], environment: {\n      'JAVA_HOME': javaHome,\n    });\n  }\n\n  Future<Map<String, String>> buildEnvironment() async {\n    final hostArch = Platform.isMacOS\n        ? \"darwin-x86_64\"\n        : (Platform.isLinux ? \"linux-x86_64\" : \"windows-x86_64\");\n\n    final ndkPath = path.join(sdkPath, 'ndk', ndkVersion);\n    final toolchainPath = path.join(\n      ndkPath,\n      'toolchains',\n      'llvm',\n      'prebuilt',\n      hostArch,\n      'bin',\n    );\n\n    final minSdkVersion =\n        math.max(target.androidMinSdkVersion!, this.minSdkVersion);\n\n    final exe = Platform.isWindows ? '.exe' : '';\n\n    final arKey = 'AR_${target.rust}';\n    final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe']\n        .map((e) => path.join(toolchainPath, e))\n        .firstWhereOrNull((element) => File(element).existsSync());\n    if (arValue == null) {\n      throw Exception('Failed to find ar for $target in $toolchainPath');\n    }\n\n    final targetArg = '--target=${target.rust}$minSdkVersion';\n\n    final ccKey = 'CC_${target.rust}';\n    final ccValue = path.join(toolchainPath, 'clang$exe');\n    final cfFlagsKey = 'CFLAGS_${target.rust}';\n    final cFlagsValue = targetArg;\n\n    final cxxKey = 'CXX_${target.rust}';\n    final cxxValue = path.join(toolchainPath, 'clang++$exe');\n    final cxxFlagsKey = 'CXXFLAGS_${target.rust}';\n    final cxxFlagsValue = targetArg;\n\n    final linkerKey =\n        'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase();\n\n    final ranlibKey = 'RANLIB_${target.rust}';\n    final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe');\n\n    final ndkVersionParsed = Version.parse(ndkVersion);\n    final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS';\n    final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed);\n\n    final runRustTool =\n        Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh';\n\n    final packagePath = (await Isolate.resolvePackageUri(\n            Uri.parse('package:build_tool/buildtool.dart')))!\n        .toFilePath();\n    final selfPath = path.canonicalize(path.join(\n      packagePath,\n      '..',\n      '..',\n      '..',\n      runRustTool,\n    ));\n\n    // Make sure that run_build_tool is working properly even initially launched directly\n    // through dart run.\n    final toolTempDir =\n        Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir;\n\n    return {\n      arKey: arValue,\n      ccKey: ccValue,\n      cfFlagsKey: cFlagsValue,\n      cxxKey: cxxValue,\n      cxxFlagsKey: cxxFlagsValue,\n      ranlibKey: ranlibValue,\n      rustFlagsKey: rustFlagsValue,\n      linkerKey: selfPath,\n      // Recognized by main() so we know when we're acting as a wrapper\n      '_CARGOKIT_NDK_LINK_TARGET': targetArg,\n      '_CARGOKIT_NDK_LINK_CLANG': ccValue,\n      'CARGOKIT_TOOL_TEMP_DIR': toolTempDir,\n    };\n  }\n\n  // Workaround for libgcc missing in NDK23, inspired by cargo-ndk\n  String _libGccWorkaround(String buildDir, Version ndkVersion) {\n    final workaroundDir = path.join(\n      buildDir,\n      'cargokit',\n      'libgcc_workaround',\n      '${ndkVersion.major}',\n    );\n    Directory(workaroundDir).createSync(recursive: true);\n    if (ndkVersion.major >= 23) {\n      File(path.join(workaroundDir, 'libgcc.a'))\n          .writeAsStringSync('INPUT(-lunwind)');\n    } else {\n      // Other way around, untested, forward libgcc.a from libunwind once Rust\n      // gets updated for NDK23+.\n      File(path.join(workaroundDir, 'libunwind.a'))\n          .writeAsStringSync('INPUT(-lgcc)');\n    }\n\n    var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? '';\n    if (rustFlags.isNotEmpty) {\n      rustFlags = '$rustFlags\\x1f';\n    }\n    rustFlags = '$rustFlags-L\\x1f$workaroundDir';\n    return rustFlags;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/artifacts_provider.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:ed25519_edwards/ed25519_edwards.dart';\nimport 'package:http/http.dart';\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'builder.dart';\nimport 'crate_hash.dart';\nimport 'options.dart';\nimport 'precompile_binaries.dart';\nimport 'rustup.dart';\nimport 'target.dart';\n\nclass Artifact {\n  /// File system location of the artifact.\n  final String path;\n\n  /// Actual file name that the artifact should have in destination folder.\n  final String finalFileName;\n\n  AritifactType get type {\n    if (finalFileName.endsWith('.dll') ||\n        finalFileName.endsWith('.dll.lib') ||\n        finalFileName.endsWith('.pdb') ||\n        finalFileName.endsWith('.so') ||\n        finalFileName.endsWith('.dylib')) {\n      return AritifactType.dylib;\n    } else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) {\n      return AritifactType.staticlib;\n    } else {\n      throw Exception('Unknown artifact type for $finalFileName');\n    }\n  }\n\n  Artifact({\n    required this.path,\n    required this.finalFileName,\n  });\n}\n\nfinal _log = Logger('artifacts_provider');\n\nclass ArtifactProvider {\n  ArtifactProvider({\n    required this.environment,\n    required this.userOptions,\n  });\n\n  final BuildEnvironment environment;\n  final CargokitUserOptions userOptions;\n\n  Future<Map<Target, List<Artifact>>> getArtifacts(List<Target> targets) async {\n    final result = await _getPrecompiledArtifacts(targets);\n\n    final pendingTargets = List.of(targets);\n    pendingTargets.removeWhere((element) => result.containsKey(element));\n\n    if (pendingTargets.isEmpty) {\n      return result;\n    }\n\n    final rustup = Rustup();\n    for (final target in targets) {\n      final builder = RustBuilder(target: target, environment: environment);\n      builder.prepare(rustup);\n      _log.info('Building ${environment.crateInfo.packageName} for $target');\n      final targetDir = await builder.build();\n      // For local build accept both static and dynamic libraries.\n      final artifactNames = <String>{\n        ...getArtifactNames(\n          target: target,\n          libraryName: environment.crateInfo.packageName,\n          aritifactType: AritifactType.dylib,\n          remote: false,\n        ),\n        ...getArtifactNames(\n          target: target,\n          libraryName: environment.crateInfo.packageName,\n          aritifactType: AritifactType.staticlib,\n          remote: false,\n        )\n      };\n      final artifacts = artifactNames\n          .map((artifactName) => Artifact(\n                path: path.join(targetDir, artifactName),\n                finalFileName: artifactName,\n              ))\n          .where((element) => File(element.path).existsSync())\n          .toList();\n      result[target] = artifacts;\n    }\n    return result;\n  }\n\n  Future<Map<Target, List<Artifact>>> _getPrecompiledArtifacts(\n      List<Target> targets) async {\n    if (userOptions.usePrecompiledBinaries == false) {\n      _log.info('Precompiled binaries are disabled');\n      return {};\n    }\n    if (environment.crateOptions.precompiledBinaries == null) {\n      _log.fine('Precompiled binaries not enabled for this crate');\n      return {};\n    }\n\n    final start = Stopwatch()..start();\n    final crateHash = CrateHash.compute(environment.manifestDir,\n        tempStorage: environment.targetTempDir);\n    _log.fine(\n        'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms');\n\n    final downloadedArtifactsDir =\n        path.join(environment.targetTempDir, 'precompiled', crateHash);\n    Directory(downloadedArtifactsDir).createSync(recursive: true);\n\n    final res = <Target, List<Artifact>>{};\n\n    for (final target in targets) {\n      final requiredArtifacts = getArtifactNames(\n        target: target,\n        libraryName: environment.crateInfo.packageName,\n        remote: true,\n      );\n      final artifactsForTarget = <Artifact>[];\n\n      for (final artifact in requiredArtifacts) {\n        final fileName = PrecompileBinaries.fileName(target, artifact);\n        final downloadedPath = path.join(downloadedArtifactsDir, fileName);\n        if (!File(downloadedPath).existsSync()) {\n          final signatureFileName =\n              PrecompileBinaries.signatureFileName(target, artifact);\n          await _tryDownloadArtifacts(\n            crateHash: crateHash,\n            fileName: fileName,\n            signatureFileName: signatureFileName,\n            finalPath: downloadedPath,\n          );\n        }\n        if (File(downloadedPath).existsSync()) {\n          artifactsForTarget.add(Artifact(\n            path: downloadedPath,\n            finalFileName: artifact,\n          ));\n        } else {\n          break;\n        }\n      }\n\n      // Only provide complete set of artifacts.\n      if (artifactsForTarget.length == requiredArtifacts.length) {\n        _log.fine('Found precompiled artifacts for $target');\n        res[target] = artifactsForTarget;\n      }\n    }\n\n    return res;\n  }\n\n  static Future<Response> _get(Uri url, {Map<String, String>? headers}) async {\n    int attempt = 0;\n    const maxAttempts = 10;\n    while (true) {\n      try {\n        return await get(url, headers: headers);\n      } on SocketException catch (e) {\n        // Try to detect reset by peer error and retry.\n        if (attempt++ < maxAttempts &&\n            (e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) {\n          _log.severe(\n              'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...');\n          await Future.delayed(Duration(seconds: 1));\n          continue;\n        } else {\n          rethrow;\n        }\n      }\n    }\n  }\n\n  Future<void> _tryDownloadArtifacts({\n    required String crateHash,\n    required String fileName,\n    required String signatureFileName,\n    required String finalPath,\n  }) async {\n    final precompiledBinaries = environment.crateOptions.precompiledBinaries!;\n    final prefix = precompiledBinaries.uriPrefix;\n    final url = Uri.parse('$prefix$crateHash/$fileName');\n    final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName');\n    _log.fine('Downloading signature from $signatureUrl');\n    final signature = await _get(signatureUrl);\n    if (signature.statusCode == 404) {\n      _log.warning(\n          'Precompiled binaries not available for crate hash $crateHash ($fileName)');\n      return;\n    }\n    if (signature.statusCode != 200) {\n      _log.severe(\n          'Failed to download signature $signatureUrl: status ${signature.statusCode}');\n      return;\n    }\n    _log.fine('Downloading binary from $url');\n    final res = await _get(url);\n    if (res.statusCode != 200) {\n      _log.severe('Failed to download binary $url: status ${res.statusCode}');\n      return;\n    }\n    if (verify(\n        precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) {\n      File(finalPath).writeAsBytesSync(res.bodyBytes);\n    } else {\n      _log.shout('Signature verification failed! Ignoring binary.');\n    }\n  }\n}\n\nenum AritifactType {\n  staticlib,\n  dylib,\n}\n\nAritifactType artifactTypeForTarget(Target target) {\n  if (target.darwinPlatform != null) {\n    return AritifactType.staticlib;\n  } else {\n    return AritifactType.dylib;\n  }\n}\n\nList<String> getArtifactNames({\n  required Target target,\n  required String libraryName,\n  required bool remote,\n  AritifactType? aritifactType,\n}) {\n  aritifactType ??= artifactTypeForTarget(target);\n  if (target.darwinArch != null) {\n    if (aritifactType == AritifactType.staticlib) {\n      return ['lib$libraryName.a'];\n    } else {\n      return ['lib$libraryName.dylib'];\n    }\n  } else if (target.rust.contains('-windows-')) {\n    if (aritifactType == AritifactType.staticlib) {\n      return ['$libraryName.lib'];\n    } else {\n      return [\n        '$libraryName.dll',\n        '$libraryName.dll.lib',\n        if (!remote) '$libraryName.pdb'\n      ];\n    }\n  } else if (target.rust.contains('-linux-')) {\n    if (aritifactType == AritifactType.staticlib) {\n      return ['lib$libraryName.a'];\n    } else {\n      return ['lib$libraryName.so'];\n    }\n  } else {\n    throw Exception(\"Unsupported target: ${target.rust}\");\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/build_cmake.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:path/path.dart' as path;\n\nimport 'artifacts_provider.dart';\nimport 'builder.dart';\nimport 'environment.dart';\nimport 'options.dart';\nimport 'target.dart';\n\nclass BuildCMake {\n  final CargokitUserOptions userOptions;\n\n  BuildCMake({required this.userOptions});\n\n  Future<void> build() async {\n    final targetPlatform = Environment.targetPlatform;\n    final target = Target.forFlutterName(Environment.targetPlatform);\n    if (target == null) {\n      throw Exception(\"Unknown target platform: $targetPlatform\");\n    }\n\n    final environment = BuildEnvironment.fromEnvironment(isAndroid: false);\n    final provider =\n        ArtifactProvider(environment: environment, userOptions: userOptions);\n    final artifacts = await provider.getArtifacts([target]);\n\n    final libs = artifacts[target]!;\n\n    for (final lib in libs) {\n      if (lib.type == AritifactType.dylib) {\n        File(lib.path)\n            .copySync(path.join(Environment.outputDir, lib.finalFileName));\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/build_gradle.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'artifacts_provider.dart';\nimport 'builder.dart';\nimport 'environment.dart';\nimport 'options.dart';\nimport 'target.dart';\n\nfinal log = Logger('build_gradle');\n\nclass BuildGradle {\n  BuildGradle({required this.userOptions});\n\n  final CargokitUserOptions userOptions;\n\n  Future<void> build() async {\n    final targets = Environment.targetPlatforms.map((arch) {\n      final target = Target.forFlutterName(arch);\n      if (target == null) {\n        throw Exception(\n            \"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}\");\n      }\n      return target;\n    }).toList();\n\n    final environment = BuildEnvironment.fromEnvironment(isAndroid: true);\n    final provider =\n        ArtifactProvider(environment: environment, userOptions: userOptions);\n    final artifacts = await provider.getArtifacts(targets);\n\n    for (final target in targets) {\n      final libs = artifacts[target]!;\n      final outputDir = path.join(Environment.outputDir, target.android!);\n      Directory(outputDir).createSync(recursive: true);\n\n      for (final lib in libs) {\n        if (lib.type == AritifactType.dylib) {\n          File(lib.path).copySync(path.join(outputDir, lib.finalFileName));\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/build_pod.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:path/path.dart' as path;\n\nimport 'artifacts_provider.dart';\nimport 'builder.dart';\nimport 'environment.dart';\nimport 'options.dart';\nimport 'target.dart';\nimport 'util.dart';\n\nclass BuildPod {\n  BuildPod({required this.userOptions});\n\n  final CargokitUserOptions userOptions;\n\n  Future<void> build() async {\n    final targets = Environment.darwinArchs.map((arch) {\n      final target = Target.forDarwin(\n          platformName: Environment.darwinPlatformName, darwinAarch: arch);\n      if (target == null) {\n        throw Exception(\n            \"Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}\");\n      }\n      return target;\n    }).toList();\n\n    final environment = BuildEnvironment.fromEnvironment(isAndroid: false);\n    final provider =\n        ArtifactProvider(environment: environment, userOptions: userOptions);\n    final artifacts = await provider.getArtifacts(targets);\n\n    void performLipo(String targetFile, Iterable<String> sourceFiles) {\n      runCommand(\"lipo\", [\n        '-create',\n        ...sourceFiles,\n        '-output',\n        targetFile,\n      ]);\n    }\n\n    final outputDir = Environment.outputDir;\n\n    Directory(outputDir).createSync(recursive: true);\n\n    final staticLibs = artifacts.values\n        .expand((element) => element)\n        .where((element) => element.type == AritifactType.staticlib)\n        .toList();\n    final dynamicLibs = artifacts.values\n        .expand((element) => element)\n        .where((element) => element.type == AritifactType.dylib)\n        .toList();\n\n    final libName = environment.crateInfo.packageName;\n\n    // If there is static lib, use it and link it with pod\n    if (staticLibs.isNotEmpty) {\n      final finalTargetFile = path.join(outputDir, \"lib$libName.a\");\n      performLipo(finalTargetFile, staticLibs.map((e) => e.path));\n    } else {\n      // Otherwise try to replace bundle dylib with our dylib\n      final bundlePaths = [\n        '$libName.framework/Versions/A/$libName',\n        '$libName.framework/$libName',\n      ];\n\n      for (final bundlePath in bundlePaths) {\n        final targetFile = path.join(outputDir, bundlePath);\n        if (File(targetFile).existsSync()) {\n          performLipo(targetFile, dynamicLibs.map((e) => e.path));\n\n          // Replace absolute id with @rpath one so that it works properly\n          // when moved to Frameworks.\n          runCommand(\"install_name_tool\", [\n            '-id',\n            '@rpath/$bundlePath',\n            targetFile,\n          ]);\n          return;\n        }\n      }\n      throw Exception('Unable to find bundle for dynamic library');\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/build_tool.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:args/command_runner.dart';\nimport 'package:ed25519_edwards/ed25519_edwards.dart';\nimport 'package:github/github.dart';\nimport 'package:hex/hex.dart';\nimport 'package:logging/logging.dart';\n\nimport 'android_environment.dart';\nimport 'build_cmake.dart';\nimport 'build_gradle.dart';\nimport 'build_pod.dart';\nimport 'logging.dart';\nimport 'options.dart';\nimport 'precompile_binaries.dart';\nimport 'target.dart';\nimport 'util.dart';\nimport 'verify_binaries.dart';\n\nfinal log = Logger('build_tool');\n\nabstract class BuildCommand extends Command {\n  Future<void> runBuildCommand(CargokitUserOptions options);\n\n  @override\n  Future<void> run() async {\n    final options = CargokitUserOptions.load();\n\n    if (options.verboseLogging ||\n        Platform.environment['CARGOKIT_VERBOSE'] == '1') {\n      enableVerboseLogging();\n    }\n\n    await runBuildCommand(options);\n  }\n}\n\nclass BuildPodCommand extends BuildCommand {\n  @override\n  final name = 'build-pod';\n\n  @override\n  final description = 'Build cocoa pod library';\n\n  @override\n  Future<void> runBuildCommand(CargokitUserOptions options) async {\n    final build = BuildPod(userOptions: options);\n    await build.build();\n  }\n}\n\nclass BuildGradleCommand extends BuildCommand {\n  @override\n  final name = 'build-gradle';\n\n  @override\n  final description = 'Build android library';\n\n  @override\n  Future<void> runBuildCommand(CargokitUserOptions options) async {\n    final build = BuildGradle(userOptions: options);\n    await build.build();\n  }\n}\n\nclass BuildCMakeCommand extends BuildCommand {\n  @override\n  final name = 'build-cmake';\n\n  @override\n  final description = 'Build CMake library';\n\n  @override\n  Future<void> runBuildCommand(CargokitUserOptions options) async {\n    final build = BuildCMake(userOptions: options);\n    await build.build();\n  }\n}\n\nclass GenKeyCommand extends Command {\n  @override\n  final name = 'gen-key';\n\n  @override\n  final description = 'Generate key pair for signing precompiled binaries';\n\n  @override\n  void run() {\n    final kp = generateKey();\n    final private = HEX.encode(kp.privateKey.bytes);\n    final public = HEX.encode(kp.publicKey.bytes);\n    print(\"Private Key: $private\");\n    print(\"Public Key: $public\");\n  }\n}\n\nclass PrecompileBinariesCommand extends Command {\n  PrecompileBinariesCommand() {\n    argParser\n      ..addOption(\n        'repository',\n        mandatory: true,\n        help: 'Github repository slug in format owner/name',\n      )\n      ..addOption(\n        'manifest-dir',\n        mandatory: true,\n        help: 'Directory containing Cargo.toml',\n      )\n      ..addMultiOption('target',\n          help: 'Rust target triple of artifact to build.\\n'\n              'Can be specified multiple times or omitted in which case\\n'\n              'all targets for current platform will be built.')\n      ..addOption(\n        'android-sdk-location',\n        help: 'Location of Android SDK (if available)',\n      )\n      ..addOption(\n        'android-ndk-version',\n        help: 'Android NDK version (if available)',\n      )\n      ..addOption(\n        'android-min-sdk-version',\n        help: 'Android minimum rquired version (if available)',\n      )\n      ..addOption(\n        'temp-dir',\n        help: 'Directory to store temporary build artifacts',\n      )\n      ..addFlag(\n        \"verbose\",\n        abbr: \"v\",\n        defaultsTo: false,\n        help: \"Enable verbose logging\",\n      );\n  }\n\n  @override\n  final name = 'precompile-binaries';\n\n  @override\n  final description = 'Prebuild and upload binaries\\n'\n      'Private key must be passed through PRIVATE_KEY environment variable. '\n      'Use gen_key through generate priave key.\\n'\n      'Github token must be passed as GITHUB_TOKEN environment variable.\\n';\n\n  @override\n  Future<void> run() async {\n    final verbose = argResults!['verbose'] as bool;\n    if (verbose) {\n      enableVerboseLogging();\n    }\n\n    final privateKeyString = Platform.environment['PRIVATE_KEY'];\n    if (privateKeyString == null) {\n      throw ArgumentError('Missing PRIVATE_KEY environment variable');\n    }\n    final githubToken = Platform.environment['GITHUB_TOKEN'];\n    if (githubToken == null) {\n      throw ArgumentError('Missing GITHUB_TOKEN environment variable');\n    }\n    final privateKey = HEX.decode(privateKeyString);\n    if (privateKey.length != 64) {\n      throw ArgumentError('Private key must be 64 bytes long');\n    }\n    final manifestDir = argResults!['manifest-dir'] as String;\n    if (!Directory(manifestDir).existsSync()) {\n      throw ArgumentError('Manifest directory does not exist: $manifestDir');\n    }\n    String? androidMinSdkVersionString =\n        argResults!['android-min-sdk-version'] as String?;\n    int? androidMinSdkVersion;\n    if (androidMinSdkVersionString != null) {\n      androidMinSdkVersion = int.tryParse(androidMinSdkVersionString);\n      if (androidMinSdkVersion == null) {\n        throw ArgumentError(\n            'Invalid android-min-sdk-version: $androidMinSdkVersionString');\n      }\n    }\n    final targetStrigns = argResults!['target'] as List<String>;\n    final targets = targetStrigns.map((target) {\n      final res = Target.forRustTriple(target);\n      if (res == null) {\n        throw ArgumentError('Invalid target: $target');\n      }\n      return res;\n    }).toList(growable: false);\n    final precompileBinaries = PrecompileBinaries(\n      privateKey: PrivateKey(privateKey),\n      githubToken: githubToken,\n      manifestDir: manifestDir,\n      repositorySlug: RepositorySlug.full(argResults!['repository'] as String),\n      targets: targets,\n      androidSdkLocation: argResults!['android-sdk-location'] as String?,\n      androidNdkVersion: argResults!['android-ndk-version'] as String?,\n      androidMinSdkVersion: androidMinSdkVersion,\n      tempDir: argResults!['temp-dir'] as String?,\n    );\n\n    await precompileBinaries.run();\n  }\n}\n\nclass VerifyBinariesCommand extends Command {\n  VerifyBinariesCommand() {\n    argParser.addOption(\n      'manifest-dir',\n      mandatory: true,\n      help: 'Directory containing Cargo.toml',\n    );\n  }\n\n  @override\n  final name = \"verify-binaries\";\n\n  @override\n  final description = 'Verifies published binaries\\n'\n      'Checks whether there is a binary published for each targets\\n'\n      'and checks the signature.';\n\n  @override\n  Future<void> run() async {\n    final manifestDir = argResults!['manifest-dir'] as String;\n    final verifyBinaries = VerifyBinaries(\n      manifestDir: manifestDir,\n    );\n    await verifyBinaries.run();\n  }\n}\n\nFuture<void> runMain(List<String> args) async {\n  try {\n    // Init logging before options are loaded\n    initLogging();\n\n    if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) {\n      return AndroidEnvironment.clangLinkerWrapper(args);\n    }\n\n    final runner = CommandRunner('build_tool', 'Cargokit built_tool')\n      ..addCommand(BuildPodCommand())\n      ..addCommand(BuildGradleCommand())\n      ..addCommand(BuildCMakeCommand())\n      ..addCommand(GenKeyCommand())\n      ..addCommand(PrecompileBinariesCommand())\n      ..addCommand(VerifyBinariesCommand());\n\n    await runner.run(args);\n  } on ArgumentError catch (e) {\n    stderr.writeln(e.toString());\n    exit(1);\n  } catch (e, s) {\n    log.severe(kDoubleSeparator);\n    log.severe('Cargokit BuildTool failed with error:');\n    log.severe(kSeparator);\n    log.severe(e);\n    // This tells user to install Rust, there's no need to pollute the log with\n    // stack trace.\n    if (e is! RustupNotFoundException) {\n      log.severe(kSeparator);\n      log.severe(s);\n      log.severe(kSeparator);\n      log.severe('BuildTool arguments: $args');\n    }\n    log.severe(kDoubleSeparator);\n    exit(1);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/builder.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'package:collection/collection.dart';\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'android_environment.dart';\nimport 'cargo.dart';\nimport 'environment.dart';\nimport 'options.dart';\nimport 'rustup.dart';\nimport 'target.dart';\nimport 'util.dart';\n\nfinal _log = Logger('builder');\n\nenum BuildConfiguration {\n  debug,\n  release,\n  profile,\n}\n\nextension on BuildConfiguration {\n  bool get isDebug => this == BuildConfiguration.debug;\n  String get rustName => switch (this) {\n        BuildConfiguration.debug => 'debug',\n        BuildConfiguration.release => 'release',\n        BuildConfiguration.profile => 'release',\n      };\n}\n\nclass BuildException implements Exception {\n  final String message;\n\n  BuildException(this.message);\n\n  @override\n  String toString() {\n    return 'BuildException: $message';\n  }\n}\n\nclass BuildEnvironment {\n  final BuildConfiguration configuration;\n  final CargokitCrateOptions crateOptions;\n  final String targetTempDir;\n  final String manifestDir;\n  final CrateInfo crateInfo;\n\n  final bool isAndroid;\n  final String? androidSdkPath;\n  final String? androidNdkVersion;\n  final int? androidMinSdkVersion;\n  final String? javaHome;\n\n  BuildEnvironment({\n    required this.configuration,\n    required this.crateOptions,\n    required this.targetTempDir,\n    required this.manifestDir,\n    required this.crateInfo,\n    required this.isAndroid,\n    this.androidSdkPath,\n    this.androidNdkVersion,\n    this.androidMinSdkVersion,\n    this.javaHome,\n  });\n\n  static BuildConfiguration parseBuildConfiguration(String value) {\n    // XCode configuration adds the flavor to configuration name.\n    final firstSegment = value.split('-').first;\n    final buildConfiguration = BuildConfiguration.values.firstWhereOrNull(\n      (e) => e.name == firstSegment,\n    );\n    if (buildConfiguration == null) {\n      _log.warning('Unknown build configuraiton $value, will assume release');\n      return BuildConfiguration.release;\n    }\n    return buildConfiguration;\n  }\n\n  static BuildEnvironment fromEnvironment({\n    required bool isAndroid,\n  }) {\n    final buildConfiguration =\n        parseBuildConfiguration(Environment.configuration);\n    final manifestDir = Environment.manifestDir;\n    final crateOptions = CargokitCrateOptions.load(\n      manifestDir: manifestDir,\n    );\n    final crateInfo = CrateInfo.load(manifestDir);\n    return BuildEnvironment(\n      configuration: buildConfiguration,\n      crateOptions: crateOptions,\n      targetTempDir: Environment.targetTempDir,\n      manifestDir: manifestDir,\n      crateInfo: crateInfo,\n      isAndroid: isAndroid,\n      androidSdkPath: isAndroid ? Environment.sdkPath : null,\n      androidNdkVersion: isAndroid ? Environment.ndkVersion : null,\n      androidMinSdkVersion:\n          isAndroid ? int.parse(Environment.minSdkVersion) : null,\n      javaHome: isAndroid ? Environment.javaHome : null,\n    );\n  }\n}\n\nclass RustBuilder {\n  final Target target;\n  final BuildEnvironment environment;\n\n  RustBuilder({\n    required this.target,\n    required this.environment,\n  });\n\n  void prepare(\n    Rustup rustup,\n  ) {\n    final toolchain = _toolchain;\n    if (rustup.installedTargets(toolchain) == null) {\n      rustup.installToolchain(toolchain);\n    }\n    if (toolchain == 'nightly') {\n      rustup.installRustSrcForNightly();\n    }\n    if (!rustup.installedTargets(toolchain)!.contains(target.rust)) {\n      rustup.installTarget(target.rust, toolchain: toolchain);\n    }\n  }\n\n  CargoBuildOptions? get _buildOptions =>\n      environment.crateOptions.cargo[environment.configuration];\n\n  String get _toolchain => _buildOptions?.toolchain.name ?? 'stable';\n\n  /// Returns the path of directory containing build artifacts.\n  Future<String> build() async {\n    final extraArgs = _buildOptions?.flags ?? [];\n    final manifestPath = path.join(environment.manifestDir, 'Cargo.toml');\n    runCommand(\n      'rustup',\n      [\n        'run',\n        _toolchain,\n        'cargo',\n        'build',\n        ...extraArgs,\n        '--manifest-path',\n        manifestPath,\n        '-p',\n        environment.crateInfo.packageName,\n        if (!environment.configuration.isDebug) '--release',\n        '--target',\n        target.rust,\n        '--target-dir',\n        environment.targetTempDir,\n      ],\n      environment: await _buildEnvironment(),\n    );\n    return path.join(\n      environment.targetTempDir,\n      target.rust,\n      environment.configuration.rustName,\n    );\n  }\n\n  Future<Map<String, String>> _buildEnvironment() async {\n    if (target.android == null) {\n      return {};\n    } else {\n      final sdkPath = environment.androidSdkPath;\n      final ndkVersion = environment.androidNdkVersion;\n      final minSdkVersion = environment.androidMinSdkVersion;\n      if (sdkPath == null) {\n        throw BuildException('androidSdkPath is not set');\n      }\n      if (ndkVersion == null) {\n        throw BuildException('androidNdkVersion is not set');\n      }\n      if (minSdkVersion == null) {\n        throw BuildException('androidMinSdkVersion is not set');\n      }\n      final env = AndroidEnvironment(\n        sdkPath: sdkPath,\n        ndkVersion: ndkVersion,\n        minSdkVersion: minSdkVersion,\n        targetTempDir: environment.targetTempDir,\n        target: target,\n      );\n      if (!env.ndkIsInstalled() && environment.javaHome != null) {\n        env.installNdk(javaHome: environment.javaHome!);\n      }\n      return env.buildEnvironment();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/cargo.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:path/path.dart' as path;\nimport 'package:toml/toml.dart';\n\nclass ManifestException {\n  ManifestException(this.message, {required this.fileName});\n\n  final String? fileName;\n  final String message;\n\n  @override\n  String toString() {\n    if (fileName != null) {\n      return 'Failed to parse package manifest at $fileName: $message';\n    } else {\n      return 'Failed to parse package manifest: $message';\n    }\n  }\n}\n\nclass CrateInfo {\n  CrateInfo({required this.packageName});\n\n  final String packageName;\n\n  static CrateInfo parseManifest(String manifest, {final String? fileName}) {\n    final toml = TomlDocument.parse(manifest);\n    final package = toml.toMap()['package'];\n    if (package == null) {\n      throw ManifestException('Missing package section', fileName: fileName);\n    }\n    final name = package['name'];\n    if (name == null) {\n      throw ManifestException('Missing package name', fileName: fileName);\n    }\n    return CrateInfo(packageName: name);\n  }\n\n  static CrateInfo load(String manifestDir) {\n    final manifestFile = File(path.join(manifestDir, 'Cargo.toml'));\n    final manifest = manifestFile.readAsStringSync();\n    return parseManifest(manifest, fileName: manifestFile.path);\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/crate_hash.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:convert';\nimport 'dart:io';\nimport 'dart:typed_data';\n\nimport 'package:collection/collection.dart';\nimport 'package:convert/convert.dart';\nimport 'package:crypto/crypto.dart';\nimport 'package:path/path.dart' as path;\n\nclass CrateHash {\n  /// Computes a hash uniquely identifying crate content. This takes into account\n  /// content all all .rs files inside the src directory, as well as Cargo.toml,\n  /// Cargo.lock, build.rs and cargokit.yaml.\n  ///\n  /// If [tempStorage] is provided, computed hash is stored in a file in that directory\n  /// and reused on subsequent calls if the crate content hasn't changed.\n  static String compute(String manifestDir, {String? tempStorage}) {\n    return CrateHash._(\n      manifestDir: manifestDir,\n      tempStorage: tempStorage,\n    )._compute();\n  }\n\n  CrateHash._({\n    required this.manifestDir,\n    required this.tempStorage,\n  });\n\n  String _compute() {\n    final files = getFiles();\n    final tempStorage = this.tempStorage;\n    if (tempStorage != null) {\n      final quickHash = _computeQuickHash(files);\n      final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash'));\n      quickHashFolder.createSync(recursive: true);\n      final quickHashFile = File(path.join(quickHashFolder.path, quickHash));\n      if (quickHashFile.existsSync()) {\n        return quickHashFile.readAsStringSync();\n      }\n      final hash = _computeHash(files);\n      quickHashFile.writeAsStringSync(hash);\n      return hash;\n    } else {\n      return _computeHash(files);\n    }\n  }\n\n  /// Computes a quick hash based on files stat (without reading contents). This\n  /// is used to cache the real hash, which is slower to compute since it involves\n  /// reading every single file.\n  String _computeQuickHash(List<File> files) {\n    final output = AccumulatorSink<Digest>();\n    final input = sha256.startChunkedConversion(output);\n\n    final data = ByteData(8);\n    for (final file in files) {\n      input.add(utf8.encode(file.path));\n      final stat = file.statSync();\n      data.setUint64(0, stat.size);\n      input.add(data.buffer.asUint8List());\n      data.setUint64(0, stat.modified.millisecondsSinceEpoch);\n      input.add(data.buffer.asUint8List());\n    }\n\n    input.close();\n    return base64Url.encode(output.events.single.bytes);\n  }\n\n  String _computeHash(List<File> files) {\n    final output = AccumulatorSink<Digest>();\n    final input = sha256.startChunkedConversion(output);\n\n    void addTextFile(File file) {\n      // text Files are hashed by lines in case we're dealing with github checkout\n      // that auto-converts line endings.\n      final splitter = LineSplitter();\n      if (file.existsSync()) {\n        final data = file.readAsStringSync();\n        final lines = splitter.convert(data);\n        for (final line in lines) {\n          input.add(utf8.encode(line));\n        }\n      }\n    }\n\n    for (final file in files) {\n      addTextFile(file);\n    }\n\n    input.close();\n    final res = output.events.single;\n\n    // Truncate to 128bits.\n    final hash = res.bytes.sublist(0, 16);\n    return hex.encode(hash);\n  }\n\n  List<File> getFiles() {\n    final src = Directory(path.join(manifestDir, 'src'));\n    final files = src\n        .listSync(recursive: true, followLinks: false)\n        .whereType<File>()\n        .toList();\n    files.sortBy((element) => element.path);\n    void addFile(String relative) {\n      final file = File(path.join(manifestDir, relative));\n      if (file.existsSync()) {\n        files.add(file);\n      }\n    }\n\n    addFile('Cargo.toml');\n    addFile('Cargo.lock');\n    addFile('build.rs');\n    addFile('cargokit.yaml');\n    return files;\n  }\n\n  final String manifestDir;\n  final String? tempStorage;\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/environment.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nextension on String {\n  String resolveSymlink() => File(this).resolveSymbolicLinksSync();\n}\n\nclass Environment {\n  /// Current build configuration (debug or release).\n  static String get configuration =>\n      _getEnv(\"CARGOKIT_CONFIGURATION\").toLowerCase();\n\n  static bool get isDebug => configuration == 'debug';\n  static bool get isRelease => configuration == 'release';\n\n  /// Temporary directory where Rust build artifacts are placed.\n  static String get targetTempDir => _getEnv(\"CARGOKIT_TARGET_TEMP_DIR\");\n\n  /// Final output directory where the build artifacts are placed.\n  static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR');\n\n  /// Path to the crate manifest (containing Cargo.toml).\n  static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR');\n\n  /// Directory inside root project. Not necessarily root folder. Symlinks are\n  /// not resolved on purpose.\n  static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR');\n\n  // Pod\n\n  /// Platform name (macosx, iphoneos, iphonesimulator).\n  static String get darwinPlatformName =>\n      _getEnv(\"CARGOKIT_DARWIN_PLATFORM_NAME\");\n\n  /// List of architectures to build for (arm64, armv7, x86_64).\n  static List<String> get darwinArchs =>\n      _getEnv(\"CARGOKIT_DARWIN_ARCHS\").split(' ');\n\n  // Gradle\n  static String get minSdkVersion => _getEnv(\"CARGOKIT_MIN_SDK_VERSION\");\n  static String get ndkVersion => _getEnv(\"CARGOKIT_NDK_VERSION\");\n  static String get sdkPath => _getEnvPath(\"CARGOKIT_SDK_DIR\");\n  static String get javaHome => _getEnvPath(\"CARGOKIT_JAVA_HOME\");\n  static List<String> get targetPlatforms =>\n      _getEnv(\"CARGOKIT_TARGET_PLATFORMS\").split(',');\n\n  // CMAKE\n  static String get targetPlatform => _getEnv(\"CARGOKIT_TARGET_PLATFORM\");\n\n  static String _getEnv(String key) {\n    final res = Platform.environment[key];\n    if (res == null) {\n      throw Exception(\"Missing environment variable $key\");\n    }\n    return res;\n  }\n\n  static String _getEnvPath(String key) {\n    final res = _getEnv(key);\n    if (Directory(res).existsSync()) {\n      return res.resolveSymlink();\n    } else {\n      return res;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/logging.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:logging/logging.dart';\n\nconst String kSeparator = \"--\";\nconst String kDoubleSeparator = \"==\";\n\nbool _lastMessageWasSeparator = false;\n\nvoid _log(LogRecord rec) {\n  final prefix = '${rec.level.name}: ';\n  final out = rec.level == Level.SEVERE ? stderr : stdout;\n  if (rec.message == kSeparator) {\n    if (!_lastMessageWasSeparator) {\n      out.write(prefix);\n      out.writeln('-' * 80);\n      _lastMessageWasSeparator = true;\n    }\n    return;\n  } else if (rec.message == kDoubleSeparator) {\n    out.write(prefix);\n    out.writeln('=' * 80);\n    _lastMessageWasSeparator = true;\n    return;\n  }\n  out.write(prefix);\n  out.writeln(rec.message);\n  _lastMessageWasSeparator = false;\n}\n\nvoid initLogging() {\n  Logger.root.level = Level.INFO;\n  Logger.root.onRecord.listen((LogRecord rec) {\n    final lines = rec.message.split('\\n');\n    for (final line in lines) {\n      if (line.isNotEmpty || lines.length == 1 || line != lines.last) {\n        _log(LogRecord(\n          rec.level,\n          line,\n          rec.loggerName,\n        ));\n      }\n    }\n  });\n}\n\nvoid enableVerboseLogging() {\n  Logger.root.level = Level.ALL;\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/options.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:collection/collection.dart';\nimport 'package:ed25519_edwards/ed25519_edwards.dart';\nimport 'package:hex/hex.dart';\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\nimport 'package:source_span/source_span.dart';\nimport 'package:yaml/yaml.dart';\n\nimport 'builder.dart';\nimport 'environment.dart';\nimport 'rustup.dart';\n\nfinal _log = Logger('options');\n\n/// A class for exceptions that have source span information attached.\nclass SourceSpanException implements Exception {\n  // This is a getter so that subclasses can override it.\n  /// A message describing the exception.\n  String get message => _message;\n  final String _message;\n\n  // This is a getter so that subclasses can override it.\n  /// The span associated with this exception.\n  ///\n  /// This may be `null` if the source location can't be determined.\n  SourceSpan? get span => _span;\n  final SourceSpan? _span;\n\n  SourceSpanException(this._message, this._span);\n\n  /// Returns a string representation of `this`.\n  ///\n  /// [color] may either be a [String], a [bool], or `null`. If it's a string,\n  /// it indicates an ANSI terminal color escape that should be used to\n  /// highlight the span's text. If it's `true`, it indicates that the text\n  /// should be highlighted using the default color. If it's `false` or `null`,\n  /// it indicates that the text shouldn't be highlighted.\n  @override\n  String toString({Object? color}) {\n    if (span == null) return message;\n    return 'Error on ${span!.message(message, color: color)}';\n  }\n}\n\nenum Toolchain {\n  stable,\n  beta,\n  nightly,\n}\n\nclass CargoBuildOptions {\n  final Toolchain toolchain;\n  final List<String> flags;\n\n  CargoBuildOptions({\n    required this.toolchain,\n    required this.flags,\n  });\n\n  static Toolchain _toolchainFromNode(YamlNode node) {\n    if (node case YamlScalar(value: String name)) {\n      final toolchain =\n          Toolchain.values.firstWhereOrNull((element) => element.name == name);\n      if (toolchain != null) {\n        return toolchain;\n      }\n    }\n    throw SourceSpanException(\n        'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.',\n        node.span);\n  }\n\n  static CargoBuildOptions parse(YamlNode node) {\n    if (node is! YamlMap) {\n      throw SourceSpanException('Cargo options must be a map', node.span);\n    }\n    Toolchain toolchain = Toolchain.stable;\n    List<String> flags = [];\n    for (final MapEntry(:key, :value) in node.nodes.entries) {\n      if (key case YamlScalar(value: 'toolchain')) {\n        toolchain = _toolchainFromNode(value);\n      } else if (key case YamlScalar(value: 'extra_flags')) {\n        if (value case YamlList(nodes: List<YamlNode> list)) {\n          if (list.every((element) {\n            if (element case YamlScalar(value: String _)) {\n              return true;\n            }\n            return false;\n          })) {\n            flags = list.map((e) => e.value as String).toList();\n            continue;\n          }\n        }\n        throw SourceSpanException(\n            'Extra flags must be a list of strings', value.span);\n      } else {\n        throw SourceSpanException(\n            'Unknown cargo option type. Must be \"toolchain\" or \"extra_flags\".',\n            key.span);\n      }\n    }\n    return CargoBuildOptions(toolchain: toolchain, flags: flags);\n  }\n}\n\nextension on YamlMap {\n  /// Map that extracts keys so that we can do map case check on them.\n  Map<dynamic, YamlNode> get valueMap =>\n      nodes.map((key, value) => MapEntry(key.value, value));\n}\n\nclass PrecompiledBinaries {\n  final String uriPrefix;\n  final PublicKey publicKey;\n\n  PrecompiledBinaries({\n    required this.uriPrefix,\n    required this.publicKey,\n  });\n\n  static PublicKey _publicKeyFromHex(String key, SourceSpan? span) {\n    final bytes = HEX.decode(key);\n    if (bytes.length != 32) {\n      throw SourceSpanException(\n          'Invalid public key. Must be 32 bytes long.', span);\n    }\n    return PublicKey(bytes);\n  }\n\n  static PrecompiledBinaries parse(YamlNode node) {\n    if (node case YamlMap(valueMap: Map<dynamic, YamlNode> map)) {\n      if (map\n          case {\n            'url_prefix': YamlNode urlPrefixNode,\n            'public_key': YamlNode publicKeyNode,\n          }) {\n        final urlPrefix = switch (urlPrefixNode) {\n          YamlScalar(value: String urlPrefix) => urlPrefix,\n          _ => throw SourceSpanException(\n              'Invalid URL prefix value.', urlPrefixNode.span),\n        };\n        final publicKey = switch (publicKeyNode) {\n          YamlScalar(value: String publicKey) =>\n            _publicKeyFromHex(publicKey, publicKeyNode.span),\n          _ => throw SourceSpanException(\n              'Invalid public key value.', publicKeyNode.span),\n        };\n        return PrecompiledBinaries(\n          uriPrefix: urlPrefix,\n          publicKey: publicKey,\n        );\n      }\n    }\n    throw SourceSpanException(\n        'Invalid precompiled binaries value. '\n        'Expected Map with \"url_prefix\" and \"public_key\".',\n        node.span);\n  }\n}\n\n/// Cargokit options specified for Rust crate.\nclass CargokitCrateOptions {\n  CargokitCrateOptions({\n    this.cargo = const {},\n    this.precompiledBinaries,\n  });\n\n  final Map<BuildConfiguration, CargoBuildOptions> cargo;\n  final PrecompiledBinaries? precompiledBinaries;\n\n  static CargokitCrateOptions parse(YamlNode node) {\n    if (node is! YamlMap) {\n      throw SourceSpanException('Cargokit options must be a map', node.span);\n    }\n    final options = <BuildConfiguration, CargoBuildOptions>{};\n    PrecompiledBinaries? precompiledBinaries;\n\n    for (final entry in node.nodes.entries) {\n      if (entry\n          case MapEntry(\n            key: YamlScalar(value: 'cargo'),\n            value: YamlNode node,\n          )) {\n        if (node is! YamlMap) {\n          throw SourceSpanException('Cargo options must be a map', node.span);\n        }\n        for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) {\n          if (key case YamlScalar(value: String name)) {\n            final configuration = BuildConfiguration.values\n                .firstWhereOrNull((element) => element.name == name);\n            if (configuration != null) {\n              options[configuration] = CargoBuildOptions.parse(value);\n              continue;\n            }\n          }\n          throw SourceSpanException(\n              'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.',\n              key.span);\n        }\n      } else if (entry.key case YamlScalar(value: 'precompiled_binaries')) {\n        precompiledBinaries = PrecompiledBinaries.parse(entry.value);\n      } else {\n        throw SourceSpanException(\n            'Unknown cargokit option type. Must be \"cargo\" or \"precompiled_binaries\".',\n            entry.key.span);\n      }\n    }\n    return CargokitCrateOptions(\n      cargo: options,\n      precompiledBinaries: precompiledBinaries,\n    );\n  }\n\n  static CargokitCrateOptions load({\n    required String manifestDir,\n  }) {\n    final uri = Uri.file(path.join(manifestDir, \"cargokit.yaml\"));\n    final file = File.fromUri(uri);\n    if (file.existsSync()) {\n      final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri);\n      return parse(contents);\n    } else {\n      return CargokitCrateOptions();\n    }\n  }\n}\n\nclass CargokitUserOptions {\n  // When Rustup is installed always build locally unless user opts into\n  // using precompiled binaries.\n  static bool defaultUsePrecompiledBinaries() {\n    return Rustup.executablePath() == null;\n  }\n\n  CargokitUserOptions({\n    required this.usePrecompiledBinaries,\n    required this.verboseLogging,\n  });\n\n  CargokitUserOptions._()\n      : usePrecompiledBinaries = defaultUsePrecompiledBinaries(),\n        verboseLogging = false;\n\n  static CargokitUserOptions parse(YamlNode node) {\n    if (node is! YamlMap) {\n      throw SourceSpanException('Cargokit options must be a map', node.span);\n    }\n    bool usePrecompiledBinaries = defaultUsePrecompiledBinaries();\n    bool verboseLogging = false;\n\n    for (final entry in node.nodes.entries) {\n      if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) {\n        if (entry.value case YamlScalar(value: bool value)) {\n          usePrecompiledBinaries = value;\n          continue;\n        }\n        throw SourceSpanException(\n            'Invalid value for \"use_precompiled_binaries\". Must be a boolean.',\n            entry.value.span);\n      } else if (entry.key case YamlScalar(value: 'verbose_logging')) {\n        if (entry.value case YamlScalar(value: bool value)) {\n          verboseLogging = value;\n          continue;\n        }\n        throw SourceSpanException(\n            'Invalid value for \"verbose_logging\". Must be a boolean.',\n            entry.value.span);\n      } else {\n        throw SourceSpanException(\n            'Unknown cargokit option type. Must be \"use_precompiled_binaries\" or \"verbose_logging\".',\n            entry.key.span);\n      }\n    }\n    return CargokitUserOptions(\n      usePrecompiledBinaries: usePrecompiledBinaries,\n      verboseLogging: verboseLogging,\n    );\n  }\n\n  static CargokitUserOptions load() {\n    String fileName = \"cargokit_options.yaml\";\n    var userProjectDir = Directory(Environment.rootProjectDir);\n\n    while (userProjectDir.parent.path != userProjectDir.path) {\n      final configFile = File(path.join(userProjectDir.path, fileName));\n      if (configFile.existsSync()) {\n        final contents = loadYamlNode(\n          configFile.readAsStringSync(),\n          sourceUrl: configFile.uri,\n        );\n        final res = parse(contents);\n        if (res.verboseLogging) {\n          _log.info('Found user options file at ${configFile.path}');\n        }\n        return res;\n      }\n      userProjectDir = userProjectDir.parent;\n    }\n    return CargokitUserOptions._();\n  }\n\n  final bool usePrecompiledBinaries;\n  final bool verboseLogging;\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/precompile_binaries.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:ed25519_edwards/ed25519_edwards.dart';\nimport 'package:github/github.dart';\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'artifacts_provider.dart';\nimport 'builder.dart';\nimport 'cargo.dart';\nimport 'crate_hash.dart';\nimport 'options.dart';\nimport 'rustup.dart';\nimport 'target.dart';\n\nfinal _log = Logger('precompile_binaries');\n\nclass PrecompileBinaries {\n  PrecompileBinaries({\n    required this.privateKey,\n    required this.githubToken,\n    required this.repositorySlug,\n    required this.manifestDir,\n    required this.targets,\n    this.androidSdkLocation,\n    this.androidNdkVersion,\n    this.androidMinSdkVersion,\n    this.tempDir,\n  });\n\n  final PrivateKey privateKey;\n  final String githubToken;\n  final RepositorySlug repositorySlug;\n  final String manifestDir;\n  final List<Target> targets;\n  final String? androidSdkLocation;\n  final String? androidNdkVersion;\n  final int? androidMinSdkVersion;\n  final String? tempDir;\n\n  static String fileName(Target target, String name) {\n    return '${target.rust}_$name';\n  }\n\n  static String signatureFileName(Target target, String name) {\n    return '${target.rust}_$name.sig';\n  }\n\n  Future<void> run() async {\n    final crateInfo = CrateInfo.load(manifestDir);\n\n    final targets = List.of(this.targets);\n    if (targets.isEmpty) {\n      targets.addAll([\n        ...Target.buildableTargets(),\n        if (androidSdkLocation != null) ...Target.androidTargets(),\n      ]);\n    }\n\n    _log.info('Precompiling binaries for $targets');\n\n    final hash = CrateHash.compute(manifestDir);\n    _log.info('Computed crate hash: $hash');\n\n    final String tagName = 'precompiled_$hash';\n\n    final github = GitHub(auth: Authentication.withToken(githubToken));\n    final repo = github.repositories;\n    final release = await _getOrCreateRelease(\n      repo: repo,\n      tagName: tagName,\n      packageName: crateInfo.packageName,\n      hash: hash,\n    );\n\n    final tempDir = this.tempDir != null\n        ? Directory(this.tempDir!)\n        : Directory.systemTemp.createTempSync('precompiled_');\n\n    tempDir.createSync(recursive: true);\n\n    final crateOptions = CargokitCrateOptions.load(\n      manifestDir: manifestDir,\n    );\n\n    final buildEnvironment = BuildEnvironment(\n      configuration: BuildConfiguration.release,\n      crateOptions: crateOptions,\n      targetTempDir: tempDir.path,\n      manifestDir: manifestDir,\n      crateInfo: crateInfo,\n      isAndroid: androidSdkLocation != null,\n      androidSdkPath: androidSdkLocation,\n      androidNdkVersion: androidNdkVersion,\n      androidMinSdkVersion: androidMinSdkVersion,\n    );\n\n    final rustup = Rustup();\n\n    for (final target in targets) {\n      final artifactNames = getArtifactNames(\n        target: target,\n        libraryName: crateInfo.packageName,\n        remote: true,\n      );\n\n      if (artifactNames.every((name) {\n        final fileName = PrecompileBinaries.fileName(target, name);\n        return (release.assets ?? []).any((e) => e.name == fileName);\n      })) {\n        _log.info(\"All artifacts for $target already exist - skipping\");\n        continue;\n      }\n\n      _log.info('Building for $target');\n\n      final builder =\n          RustBuilder(target: target, environment: buildEnvironment);\n      builder.prepare(rustup);\n      final res = await builder.build();\n\n      final assets = <CreateReleaseAsset>[];\n      for (final name in artifactNames) {\n        final file = File(path.join(res, name));\n        if (!file.existsSync()) {\n          throw Exception('Missing artifact: ${file.path}');\n        }\n\n        final data = file.readAsBytesSync();\n        final create = CreateReleaseAsset(\n          name: PrecompileBinaries.fileName(target, name),\n          contentType: \"application/octet-stream\",\n          assetData: data,\n        );\n        final signature = sign(privateKey, data);\n        final signatureCreate = CreateReleaseAsset(\n          name: signatureFileName(target, name),\n          contentType: \"application/octet-stream\",\n          assetData: signature,\n        );\n        bool verified = verify(public(privateKey), data, signature);\n        if (!verified) {\n          throw Exception('Signature verification failed');\n        }\n        assets.add(create);\n        assets.add(signatureCreate);\n      }\n      _log.info('Uploading assets: ${assets.map((e) => e.name)}');\n      for (final asset in assets) {\n        // This seems to be failing on CI so do it one by one\n        int retryCount = 0;\n        while (true) {\n          try {\n            await repo.uploadReleaseAssets(release, [asset]);\n            break;\n          } on Exception catch (e) {\n            if (retryCount == 10) {\n              rethrow;\n            }\n            ++retryCount;\n            _log.shout(\n                'Upload failed (attempt $retryCount, will retry): ${e.toString()}');\n            await Future.delayed(Duration(seconds: 2));\n          }\n        }\n      }\n    }\n\n    _log.info('Cleaning up');\n    tempDir.deleteSync(recursive: true);\n  }\n\n  Future<Release> _getOrCreateRelease({\n    required RepositoriesService repo,\n    required String tagName,\n    required String packageName,\n    required String hash,\n  }) async {\n    Release release;\n    try {\n      _log.info('Fetching release $tagName');\n      release = await repo.getReleaseByTagName(repositorySlug, tagName);\n    } on ReleaseNotFound {\n      _log.info('Release not found - creating release $tagName');\n      release = await repo.createRelease(\n          repositorySlug,\n          CreateRelease.from(\n            tagName: tagName,\n            name: 'Precompiled binaries ${hash.substring(0, 8)}',\n            targetCommitish: null,\n            isDraft: false,\n            isPrerelease: false,\n            body: 'Precompiled binaries for crate $packageName, '\n                'crate hash $hash.',\n          ));\n    }\n    return release;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/rustup.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:collection/collection.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'util.dart';\n\nclass _Toolchain {\n  _Toolchain(\n    this.name,\n    this.targets,\n  );\n\n  final String name;\n  final List<String> targets;\n}\n\nclass Rustup {\n  List<String>? installedTargets(String toolchain) {\n    final targets = _installedTargets(toolchain);\n    return targets != null ? List.unmodifiable(targets) : null;\n  }\n\n  void installToolchain(String toolchain) {\n    log.info(\"Installing Rust toolchain: $toolchain\");\n    runCommand(\"rustup\", ['toolchain', 'install', toolchain]);\n    _installedToolchains\n        .add(_Toolchain(toolchain, _getInstalledTargets(toolchain)));\n  }\n\n  void installTarget(\n    String target, {\n    required String toolchain,\n  }) {\n    log.info(\"Installing Rust target: $target\");\n    runCommand(\"rustup\", [\n      'target',\n      'add',\n      '--toolchain',\n      toolchain,\n      target,\n    ]);\n    _installedTargets(toolchain)?.add(target);\n  }\n\n  final List<_Toolchain> _installedToolchains;\n\n  Rustup() : _installedToolchains = _getInstalledToolchains();\n\n  List<String>? _installedTargets(String toolchain) => _installedToolchains\n      .firstWhereOrNull(\n          (e) => e.name == toolchain || e.name.startsWith('$toolchain-'))\n      ?.targets;\n\n  static List<_Toolchain> _getInstalledToolchains() {\n    String extractToolchainName(String line) {\n      // ignore (default) after toolchain name\n      final parts = line.split(' ');\n      return parts[0];\n    }\n\n    final res = runCommand(\"rustup\", ['toolchain', 'list']);\n\n    // To list all non-custom toolchains, we need to filter out lines that\n    // don't start with \"stable\", \"beta\", or \"nightly\".\n    Pattern nonCustom = RegExp(r\"^(stable|beta|nightly)\");\n    final lines = res.stdout\n        .toString()\n        .split('\\n')\n        .where((e) => e.isNotEmpty && e.startsWith(nonCustom))\n        .map(extractToolchainName)\n        .toList(growable: true);\n\n    return lines\n        .map(\n          (name) => _Toolchain(\n            name,\n            _getInstalledTargets(name),\n          ),\n        )\n        .toList(growable: true);\n  }\n\n  static List<String> _getInstalledTargets(String toolchain) {\n    final res = runCommand(\"rustup\", [\n      'target',\n      'list',\n      '--toolchain',\n      toolchain,\n      '--installed',\n    ]);\n    final lines = res.stdout\n        .toString()\n        .split('\\n')\n        .where((e) => e.isNotEmpty)\n        .toList(growable: true);\n    return lines;\n  }\n\n  bool _didInstallRustSrcForNightly = false;\n\n  void installRustSrcForNightly() {\n    if (_didInstallRustSrcForNightly) {\n      return;\n    }\n    // Useful for -Z build-std\n    runCommand(\n      \"rustup\",\n      ['component', 'add', 'rust-src', '--toolchain', 'nightly'],\n    );\n    _didInstallRustSrcForNightly = true;\n  }\n\n  static String? executablePath() {\n    final envPath = Platform.environment['PATH'];\n    final envPathSeparator = Platform.isWindows ? ';' : ':';\n    final home = Platform.isWindows\n        ? Platform.environment['USERPROFILE']\n        : Platform.environment['HOME'];\n    final paths = [\n      if (home != null) path.join(home, '.cargo', 'bin'),\n      if (envPath != null) ...envPath.split(envPathSeparator),\n    ];\n    for (final p in paths) {\n      final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup';\n      final rustupPath = path.join(p, rustup);\n      if (File(rustupPath).existsSync()) {\n        return rustupPath;\n      }\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/target.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:collection/collection.dart';\n\nimport 'util.dart';\n\nclass Target {\n  Target({\n    required this.rust,\n    this.flutter,\n    this.android,\n    this.androidMinSdkVersion,\n    this.darwinPlatform,\n    this.darwinArch,\n  });\n\n  static final all = [\n    Target(\n      rust: 'armv7-linux-androideabi',\n      flutter: 'android-arm',\n      android: 'armeabi-v7a',\n      androidMinSdkVersion: 16,\n    ),\n    Target(\n      rust: 'aarch64-linux-android',\n      flutter: 'android-arm64',\n      android: 'arm64-v8a',\n      androidMinSdkVersion: 21,\n    ),\n    Target(\n      rust: 'i686-linux-android',\n      flutter: 'android-x86',\n      android: 'x86',\n      androidMinSdkVersion: 16,\n    ),\n    Target(\n      rust: 'x86_64-linux-android',\n      flutter: 'android-x64',\n      android: 'x86_64',\n      androidMinSdkVersion: 21,\n    ),\n    Target(\n      rust: 'x86_64-pc-windows-msvc',\n      flutter: 'windows-x64',\n    ),\n    Target(\n      rust: 'x86_64-unknown-linux-gnu',\n      flutter: 'linux-x64',\n    ),\n    Target(\n      rust: 'aarch64-unknown-linux-gnu',\n      flutter: 'linux-arm64',\n    ),\n    Target(\n      rust: 'x86_64-apple-darwin',\n      darwinPlatform: 'macosx',\n      darwinArch: 'x86_64',\n    ),\n    Target(\n      rust: 'aarch64-apple-darwin',\n      darwinPlatform: 'macosx',\n      darwinArch: 'arm64',\n    ),\n    Target(\n      rust: 'aarch64-apple-ios',\n      darwinPlatform: 'iphoneos',\n      darwinArch: 'arm64',\n    ),\n    Target(\n      rust: 'aarch64-apple-ios-sim',\n      darwinPlatform: 'iphonesimulator',\n      darwinArch: 'arm64',\n    ),\n    Target(\n      rust: 'x86_64-apple-ios',\n      darwinPlatform: 'iphonesimulator',\n      darwinArch: 'x86_64',\n    ),\n  ];\n\n  static Target? forFlutterName(String flutterName) {\n    return all.firstWhereOrNull((element) => element.flutter == flutterName);\n  }\n\n  static Target? forDarwin({\n    required String platformName,\n    required String darwinAarch,\n  }) {\n    return all.firstWhereOrNull((element) => //\n        element.darwinPlatform == platformName &&\n        element.darwinArch == darwinAarch);\n  }\n\n  static Target? forRustTriple(String triple) {\n    return all.firstWhereOrNull((element) => element.rust == triple);\n  }\n\n  static List<Target> androidTargets() {\n    return all\n        .where((element) => element.android != null)\n        .toList(growable: false);\n  }\n\n  /// Returns buildable targets on current host platform ignoring Android targets.\n  static List<Target> buildableTargets() {\n    if (Platform.isLinux) {\n      // Right now we don't support cross-compiling on Linux. So we just return\n      // the host target.\n      final arch = runCommand('arch', []).stdout as String;\n      if (arch.trim() == 'aarch64') {\n        return [Target.forRustTriple('aarch64-unknown-linux-gnu')!];\n      } else {\n        return [Target.forRustTriple('x86_64-unknown-linux-gnu')!];\n      }\n    }\n    return all.where((target) {\n      if (Platform.isWindows) {\n        return target.rust.contains('-windows-');\n      } else if (Platform.isMacOS) {\n        return target.darwinPlatform != null;\n      }\n      return false;\n    }).toList(growable: false);\n  }\n\n  @override\n  String toString() {\n    return rust;\n  }\n\n  final String? flutter;\n  final String rust;\n  final String? android;\n  final int? androidMinSdkVersion;\n  final String? darwinPlatform;\n  final String? darwinArch;\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/util.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:convert';\nimport 'dart:io';\n\nimport 'package:logging/logging.dart';\nimport 'package:path/path.dart' as path;\n\nimport 'logging.dart';\nimport 'rustup.dart';\n\nfinal log = Logger(\"process\");\n\nclass CommandFailedException implements Exception {\n  final String executable;\n  final List<String> arguments;\n  final ProcessResult result;\n\n  CommandFailedException({\n    required this.executable,\n    required this.arguments,\n    required this.result,\n  });\n\n  @override\n  String toString() {\n    final stdout = result.stdout.toString().trim();\n    final stderr = result.stderr.toString().trim();\n    return [\n      \"External Command: $executable ${arguments.map((e) => '\"$e\"').join(' ')}\",\n      \"Returned Exit Code: ${result.exitCode}\",\n      kSeparator,\n      \"STDOUT:\",\n      if (stdout.isNotEmpty) stdout,\n      kSeparator,\n      \"STDERR:\",\n      if (stderr.isNotEmpty) stderr,\n    ].join('\\n');\n  }\n}\n\nclass TestRunCommandArgs {\n  final String executable;\n  final List<String> arguments;\n  final String? workingDirectory;\n  final Map<String, String>? environment;\n  final bool includeParentEnvironment;\n  final bool runInShell;\n  final Encoding? stdoutEncoding;\n  final Encoding? stderrEncoding;\n\n  TestRunCommandArgs({\n    required this.executable,\n    required this.arguments,\n    this.workingDirectory,\n    this.environment,\n    this.includeParentEnvironment = true,\n    this.runInShell = false,\n    this.stdoutEncoding,\n    this.stderrEncoding,\n  });\n}\n\nclass TestRunCommandResult {\n  TestRunCommandResult({\n    this.pid = 1,\n    this.exitCode = 0,\n    this.stdout = '',\n    this.stderr = '',\n  });\n\n  final int pid;\n  final int exitCode;\n  final String stdout;\n  final String stderr;\n}\n\nTestRunCommandResult Function(TestRunCommandArgs args)? testRunCommandOverride;\n\nProcessResult runCommand(\n  String executable,\n  List<String> arguments, {\n  String? workingDirectory,\n  Map<String, String>? environment,\n  bool includeParentEnvironment = true,\n  bool runInShell = false,\n  Encoding? stdoutEncoding = systemEncoding,\n  Encoding? stderrEncoding = systemEncoding,\n}) {\n  if (testRunCommandOverride != null) {\n    final result = testRunCommandOverride!(TestRunCommandArgs(\n      executable: executable,\n      arguments: arguments,\n      workingDirectory: workingDirectory,\n      environment: environment,\n      includeParentEnvironment: includeParentEnvironment,\n      runInShell: runInShell,\n      stdoutEncoding: stdoutEncoding,\n      stderrEncoding: stderrEncoding,\n    ));\n    return ProcessResult(\n      result.pid,\n      result.exitCode,\n      result.stdout,\n      result.stderr,\n    );\n  }\n  log.finer('Running command $executable ${arguments.join(' ')}');\n  final res = Process.runSync(\n    _resolveExecutable(executable),\n    arguments,\n    workingDirectory: workingDirectory,\n    environment: environment,\n    includeParentEnvironment: includeParentEnvironment,\n    runInShell: runInShell,\n    stderrEncoding: stderrEncoding,\n    stdoutEncoding: stdoutEncoding,\n  );\n  if (res.exitCode != 0) {\n    throw CommandFailedException(\n      executable: executable,\n      arguments: arguments,\n      result: res,\n    );\n  } else {\n    return res;\n  }\n}\n\nclass RustupNotFoundException implements Exception {\n  @override\n  String toString() {\n    return [\n      ' ',\n      'rustup not found in PATH.',\n      ' ',\n      'Maybe you need to install Rust? It only takes a minute:',\n      ' ',\n      if (Platform.isWindows) 'https://www.rust-lang.org/tools/install',\n      if (hasHomebrewRustInPath()) ...[\n        '\\$ brew unlink rust # Unlink homebrew Rust from PATH',\n      ],\n      if (!Platform.isWindows)\n        \"\\$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\",\n      ' ',\n    ].join('\\n');\n  }\n\n  static bool hasHomebrewRustInPath() {\n    if (!Platform.isMacOS) {\n      return false;\n    }\n    final envPath = Platform.environment['PATH'] ?? '';\n    final paths = envPath.split(':');\n    return paths.any((p) {\n      return p.contains('homebrew') && File(path.join(p, 'rustc')).existsSync();\n    });\n  }\n}\n\nString _resolveExecutable(String executable) {\n  if (executable == 'rustup') {\n    final resolved = Rustup.executablePath();\n    if (resolved != null) {\n      return resolved;\n    }\n    throw RustupNotFoundException();\n  } else {\n    return executable;\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport 'dart:io';\n\nimport 'package:ed25519_edwards/ed25519_edwards.dart';\nimport 'package:http/http.dart';\n\nimport 'artifacts_provider.dart';\nimport 'cargo.dart';\nimport 'crate_hash.dart';\nimport 'options.dart';\nimport 'precompile_binaries.dart';\nimport 'target.dart';\n\nclass VerifyBinaries {\n  VerifyBinaries({\n    required this.manifestDir,\n  });\n\n  final String manifestDir;\n\n  Future<void> run() async {\n    final crateInfo = CrateInfo.load(manifestDir);\n\n    final config = CargokitCrateOptions.load(manifestDir: manifestDir);\n    final precompiledBinaries = config.precompiledBinaries;\n    if (precompiledBinaries == null) {\n      stdout.writeln('Crate does not support precompiled binaries.');\n    } else {\n      final crateHash = CrateHash.compute(manifestDir);\n      stdout.writeln('Crate hash: $crateHash');\n\n      for (final target in Target.all) {\n        final message = 'Checking ${target.rust}...';\n        stdout.write(message.padRight(40));\n        stdout.flush();\n\n        final artifacts = getArtifactNames(\n          target: target,\n          libraryName: crateInfo.packageName,\n          remote: true,\n        );\n\n        final prefix = precompiledBinaries.uriPrefix;\n\n        bool ok = true;\n\n        for (final artifact in artifacts) {\n          final fileName = PrecompileBinaries.fileName(target, artifact);\n          final signatureFileName =\n              PrecompileBinaries.signatureFileName(target, artifact);\n\n          final url = Uri.parse('$prefix$crateHash/$fileName');\n          final signatureUrl =\n              Uri.parse('$prefix$crateHash/$signatureFileName');\n\n          final signature = await get(signatureUrl);\n          if (signature.statusCode != 200) {\n            stdout.writeln('MISSING');\n            ok = false;\n            break;\n          }\n          final asset = await get(url);\n          if (asset.statusCode != 200) {\n            stdout.writeln('MISSING');\n            ok = false;\n            break;\n          }\n\n          if (!verify(precompiledBinaries.publicKey, asset.bodyBytes,\n              signature.bodyBytes)) {\n            stdout.writeln('INVALID SIGNATURE');\n            ok = false;\n          }\n        }\n\n        if (ok) {\n          stdout.writeln('OK');\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/pubspec.lock",
    "content": "# Generated by pub\n# See https://dart.dev/tools/pub/glossary#lockfile\npackages:\n  _fe_analyzer_shared:\n    dependency: transitive\n    description:\n      name: _fe_analyzer_shared\n      sha256: \"0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"67.0.0\"\n  adaptive_number:\n    dependency: transitive\n    description:\n      name: adaptive_number\n      sha256: \"3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.0.0\"\n  analyzer:\n    dependency: transitive\n    description:\n      name: analyzer\n      sha256: \"37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"6.4.1\"\n  args:\n    dependency: \"direct main\"\n    description:\n      name: args\n      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.4.2\"\n  async:\n    dependency: transitive\n    description:\n      name: async\n      sha256: \"758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.13.0\"\n  boolean_selector:\n    dependency: transitive\n    description:\n      name: boolean_selector\n      sha256: \"8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.1.2\"\n  cli_config:\n    dependency: transitive\n    description:\n      name: cli_config\n      sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.2.0\"\n  collection:\n    dependency: \"direct main\"\n    description:\n      name: collection\n      sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.18.0\"\n  convert:\n    dependency: \"direct main\"\n    description:\n      name: convert\n      sha256: \"0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.1.1\"\n  coverage:\n    dependency: transitive\n    description:\n      name: coverage\n      sha256: \"802bd084fb82e55df091ec8ad1553a7331b61c08251eef19a508b6f3f3a9858d\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.13.1\"\n  crypto:\n    dependency: \"direct main\"\n    description:\n      name: crypto\n      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.0.3\"\n  ed25519_edwards:\n    dependency: \"direct main\"\n    description:\n      name: ed25519_edwards\n      sha256: \"6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.3.1\"\n  file:\n    dependency: transitive\n    description:\n      name: file\n      sha256: \"1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"6.1.4\"\n  fixnum:\n    dependency: transitive\n    description:\n      name: fixnum\n      sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.1.1\"\n  frontend_server_client:\n    dependency: transitive\n    description:\n      name: frontend_server_client\n      sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"4.0.0\"\n  github:\n    dependency: \"direct main\"\n    description:\n      name: github\n      sha256: \"9966bc13bf612342e916b0a343e95e5f046c88f602a14476440e9b75d2295411\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"9.17.0\"\n  glob:\n    dependency: transitive\n    description:\n      name: glob\n      sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.1.3\"\n  hex:\n    dependency: \"direct main\"\n    description:\n      name: hex\n      sha256: \"4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.2.0\"\n  http:\n    dependency: \"direct main\"\n    description:\n      name: http\n      sha256: \"759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.1.0\"\n  http_multi_server:\n    dependency: transitive\n    description:\n      name: http_multi_server\n      sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.2.2\"\n  http_parser:\n    dependency: transitive\n    description:\n      name: http_parser\n      sha256: \"2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"4.0.2\"\n  io:\n    dependency: transitive\n    description:\n      name: io\n      sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.0.5\"\n  js:\n    dependency: transitive\n    description:\n      name: js\n      sha256: \"53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.7.2\"\n  json_annotation:\n    dependency: transitive\n    description:\n      name: json_annotation\n      sha256: \"1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"4.9.0\"\n  lints:\n    dependency: \"direct dev\"\n    description:\n      name: lints\n      sha256: \"0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.1.1\"\n  logging:\n    dependency: \"direct main\"\n    description:\n      name: logging\n      sha256: \"623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.2.0\"\n  matcher:\n    dependency: transitive\n    description:\n      name: matcher\n      sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.12.17\"\n  meta:\n    dependency: transitive\n    description:\n      name: meta\n      sha256: \"23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.17.0\"\n  mime:\n    dependency: transitive\n    description:\n      name: mime\n      sha256: \"41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.0.0\"\n  node_preamble:\n    dependency: transitive\n    description:\n      name: node_preamble\n      sha256: \"6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.0.2\"\n  package_config:\n    dependency: transitive\n    description:\n      name: package_config\n      sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.2.0\"\n  path:\n    dependency: \"direct main\"\n    description:\n      name: path\n      sha256: \"2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.8.0\"\n  petitparser:\n    dependency: transitive\n    description:\n      name: petitparser\n      sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"5.4.0\"\n  pool:\n    dependency: transitive\n    description:\n      name: pool\n      sha256: \"978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.5.2\"\n  pub_semver:\n    dependency: transitive\n    description:\n      name: pub_semver\n      sha256: \"5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.2.0\"\n  shelf:\n    dependency: transitive\n    description:\n      name: shelf\n      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.4.1\"\n  shelf_packages_handler:\n    dependency: transitive\n    description:\n      name: shelf_packages_handler\n      sha256: \"89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.0.2\"\n  shelf_static:\n    dependency: transitive\n    description:\n      name: shelf_static\n      sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.1.3\"\n  shelf_web_socket:\n    dependency: transitive\n    description:\n      name: shelf_web_socket\n      sha256: \"3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.0.0\"\n  source_map_stack_trace:\n    dependency: transitive\n    description:\n      name: source_map_stack_trace\n      sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.1.2\"\n  source_maps:\n    dependency: transitive\n    description:\n      name: source_maps\n      sha256: \"190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.10.13\"\n  source_span:\n    dependency: \"direct main\"\n    description:\n      name: source_span\n      sha256: \"53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.10.0\"\n  stack_trace:\n    dependency: transitive\n    description:\n      name: stack_trace\n      sha256: \"8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.12.1\"\n  stream_channel:\n    dependency: transitive\n    description:\n      name: stream_channel\n      sha256: \"969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"2.1.4\"\n  string_scanner:\n    dependency: transitive\n    description:\n      name: string_scanner\n      sha256: \"921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.4.1\"\n  term_glyph:\n    dependency: transitive\n    description:\n      name: term_glyph\n      sha256: \"7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.2.2\"\n  test:\n    dependency: \"direct dev\"\n    description:\n      name: test\n      sha256: \"75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.26.3\"\n  test_api:\n    dependency: transitive\n    description:\n      name: test_api\n      sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.7.7\"\n  test_core:\n    dependency: transitive\n    description:\n      name: test_core\n      sha256: \"0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.6.12\"\n  toml:\n    dependency: \"direct main\"\n    description:\n      name: toml\n      sha256: \"157c5dca5160fced243f3ce984117f729c788bb5e475504f3dbcda881accee44\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"0.14.0\"\n  typed_data:\n    dependency: transitive\n    description:\n      name: typed_data\n      sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.4.0\"\n  version:\n    dependency: \"direct main\"\n    description:\n      name: version\n      sha256: \"2307e23a45b43f96469eeab946208ed63293e8afca9c28cd8b5241ff31c55f55\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.0.0\"\n  vm_service:\n    dependency: transitive\n    description:\n      name: vm_service\n      sha256: \"45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"15.0.2\"\n  watcher:\n    dependency: transitive\n    description:\n      name: watcher\n      sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.2.0\"\n  web:\n    dependency: transitive\n    description:\n      name: web\n      sha256: \"868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.1.1\"\n  web_socket:\n    dependency: transitive\n    description:\n      name: web_socket\n      sha256: \"34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.0.1\"\n  web_socket_channel:\n    dependency: transitive\n    description:\n      name: web_socket_channel\n      sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.0.3\"\n  webkit_inspection_protocol:\n    dependency: transitive\n    description:\n      name: webkit_inspection_protocol\n      sha256: \"87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"1.2.1\"\n  yaml:\n    dependency: \"direct main\"\n    description:\n      name: yaml\n      sha256: \"75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5\"\n      url: \"https://pub.dev\"\n    source: hosted\n    version: \"3.1.2\"\nsdks:\n  dart: \">=3.7.0-0 <4.0.0\"\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/build_tool/pubspec.yaml",
    "content": "# This is copied from Cargokit (which is the official way to use it currently)\n# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nname: build_tool\ndescription: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build.\npublish_to: none\nversion: 1.0.0\n\nenvironment:\n  sdk: \">=3.0.0 <4.0.0\"\n\n# Add regular dependencies here.\ndependencies:\n  # these are pinned on purpose because the bundle_tool_runner doesn't have\n  # pubspec.lock. See run_build_tool.sh\n  logging: 1.2.0\n  path: 1.8.0\n  version: 3.0.0\n  collection: 1.18.0\n  ed25519_edwards: 0.3.1\n  hex: 0.2.0\n  yaml: 3.1.2\n  source_span: 1.10.0\n  github: 9.17.0\n  args: 2.4.2\n  crypto: 3.0.3\n  convert: 3.1.1\n  http: 1.1.0\n  toml: 0.14.0\n\ndev_dependencies:\n  lints: ^2.1.0\n  test: ^1.24.0\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/cmake/cargokit.cmake",
    "content": "SET(cargokit_cmake_root \"${CMAKE_CURRENT_LIST_DIR}/..\")\n\n# Workaround for https://github.com/dart-lang/pub/issues/4010\nget_filename_component(cargokit_cmake_root \"${cargokit_cmake_root}\" REALPATH)\n\nif(WIN32)\n    # REALPATH does not properly resolve symlinks on windows :-/\n    execute_process(COMMAND powershell -ExecutionPolicy Bypass -File \"${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1\" \"${cargokit_cmake_root}\" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE)\nendif()\n\n# Arguments\n# - target: CMAKE target to which rust library is linked\n# - manifest_dir: relative path from current folder to directory containing cargo manifest\n# - lib_name: cargo package name\n# - any_symbol_name: name of any exported symbol from the library.\n#                    used on windows to force linking with library.\nfunction(apply_cargokit target manifest_dir lib_name any_symbol_name)\n\n    set(CARGOKIT_LIB_NAME \"${lib_name}\")\n    set(CARGOKIT_LIB_FULL_NAME \"${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}\")\n    if (CMAKE_CONFIGURATION_TYPES)\n        set(CARGOKIT_OUTPUT_DIR \"${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>\")\n        set(OUTPUT_LIB \"${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${CARGOKIT_LIB_FULL_NAME}\")\n    else()\n        set(CARGOKIT_OUTPUT_DIR \"${CMAKE_CURRENT_BINARY_DIR}\")\n        set(OUTPUT_LIB \"${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}\")\n    endif()\n    set(CARGOKIT_TEMP_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cargokit_build\")\n\n    if (FLUTTER_TARGET_PLATFORM)\n        set(CARGOKIT_TARGET_PLATFORM \"${FLUTTER_TARGET_PLATFORM}\")\n    else()\n        set(CARGOKIT_TARGET_PLATFORM \"windows-x64\")\n    endif()\n\n    set(CARGOKIT_ENV\n        \"CARGOKIT_CMAKE=${CMAKE_COMMAND}\"\n        \"CARGOKIT_CONFIGURATION=$<CONFIG>\"\n        \"CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}\"\n        \"CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}\"\n        \"CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}\"\n        \"CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}\"\n        \"CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool\"\n        \"CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}\"\n    )\n\n    if (WIN32)\n        set(SCRIPT_EXTENSION \".cmd\")\n        set(IMPORT_LIB_EXTENSION \".lib\")\n    else()\n        set(SCRIPT_EXTENSION \".sh\")\n        set(IMPORT_LIB_EXTENSION \"\")\n        execute_process(COMMAND chmod +x \"${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}\")\n    endif()\n\n    # Using generators in custom command is only supported in CMake 3.20+\n    if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS \"3.20.0\")\n        foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES)\n            add_custom_command(\n                OUTPUT\n                \"${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}\"\n                \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\"\n                COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV}\n                \"${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}\" build-cmake\n                VERBATIM\n            )\n        endforeach()\n    else()\n        add_custom_command(\n            OUTPUT\n            ${OUTPUT_LIB}\n            \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\"\n            COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV}\n            \"${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}\" build-cmake\n            VERBATIM\n        )\n    endif()\n\n\n    set_source_files_properties(\"${CMAKE_CURRENT_BINARY_DIR}/_phony_\" PROPERTIES SYMBOLIC TRUE)\n\n    if (TARGET ${target})\n        # If we have actual cmake target provided create target and make existing\n        # target depend on it\n        add_custom_target(\"${target}_cargokit\" DEPENDS ${OUTPUT_LIB})\n        add_dependencies(\"${target}\" \"${target}_cargokit\")\n        target_link_libraries(\"${target}\" PRIVATE \"${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}\")\n        if(WIN32)\n            target_link_options(${target} PRIVATE \"/INCLUDE:${any_symbol_name}\")\n        endif()\n    else()\n        # Otherwise (FFI) just use ALL to force building always\n        add_custom_target(\"${target}_cargokit\" ALL DEPENDS ${OUTPUT_LIB})\n    endif()\n\n    # Allow adding the output library to plugin bundled libraries\n    set(\"${target}_cargokit_lib\" ${OUTPUT_LIB} PARENT_SCOPE)\n\nendfunction()\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/cmake/resolve_symlinks.ps1",
    "content": "﻿function Resolve-Symlinks {\n    [CmdletBinding()]\n    [OutputType([string])]\n    param(\n        [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]\n        [string] $Path\n    )\n\n    [string] $separator = '/'\n    [string[]] $parts = $Path.Split($separator)\n\n    [string] $realPath = ''\n    foreach ($part in $parts) {\n        if ($realPath -and !$realPath.EndsWith($separator)) {\n            $realPath += $separator\n        }\n        $realPath += $part\n        $item = Get-Item $realPath\n        if ($item.Target) {\n            $realPath = $item.Target.Replace('\\', '/')\n        }\n    }\n    $realPath\n}\n\n$path=Resolve-Symlinks -Path $args[0]\nWrite-Host $path"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/gradle/plugin.gradle",
    "content": "/// This is copied from Cargokit (which is the official way to use it currently)\n/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin\n\nimport java.nio.file.Paths\nimport org.apache.tools.ant.taskdefs.condition.Os\n\nCargoKitPlugin.file = buildscript.sourceFile\n\napply plugin: CargoKitPlugin\n\nclass CargoKitExtension {\n    String manifestDir; // Relative path to folder containing Cargo.toml\n    String libname; // Library name within Cargo.toml. Must be a cdylib\n}\n\nabstract class CargoKitBuildTask extends DefaultTask {\n\n    @Input\n    String buildMode\n\n    @Input\n    String buildDir\n\n    @Input\n    String outputDir\n\n    @Input\n    String ndkVersion\n\n    @Input\n    String sdkDirectory\n\n    @Input\n    int compileSdkVersion;\n\n    @Input\n    int minSdkVersion;\n\n    @Input\n    String pluginFile\n\n    @Input\n    List<String> targetPlatforms\n\n    @TaskAction\n    def build() {\n        if (project.cargokit.manifestDir == null) {\n            throw new GradleException(\"Property 'manifestDir' must be set on cargokit extension\");\n        }\n\n        if (project.cargokit.libname == null) {\n            throw new GradleException(\"Property 'libname' must be set on cargokit extension\");\n        }\n\n        def executableName = Os.isFamily(Os.FAMILY_WINDOWS) ? \"run_build_tool.cmd\" : \"run_build_tool.sh\"\n        def path = Paths.get(new File(pluginFile).parent, \"..\", executableName);\n\n        def manifestDir = Paths.get(project.buildscript.sourceFile.parent, project.cargokit.manifestDir)\n\n        def rootProjectDir = project.rootProject.projectDir\n\n        if (!Os.isFamily(Os.FAMILY_WINDOWS)) {\n            project.exec {\n                commandLine 'chmod', '+x', path\n            }\n        }\n\n        project.exec {\n            executable path\n            args \"build-gradle\"\n            environment \"CARGOKIT_ROOT_PROJECT_DIR\", rootProjectDir\n            environment \"CARGOKIT_TOOL_TEMP_DIR\", \"${buildDir}/build_tool\"\n            environment \"CARGOKIT_MANIFEST_DIR\", manifestDir\n            environment \"CARGOKIT_CONFIGURATION\", buildMode\n            environment \"CARGOKIT_TARGET_TEMP_DIR\", buildDir\n            environment \"CARGOKIT_OUTPUT_DIR\", outputDir\n            environment \"CARGOKIT_NDK_VERSION\", ndkVersion\n            environment \"CARGOKIT_SDK_DIR\", sdkDirectory\n            environment \"CARGOKIT_COMPILE_SDK_VERSION\", compileSdkVersion\n            environment \"CARGOKIT_MIN_SDK_VERSION\", minSdkVersion\n            environment \"CARGOKIT_TARGET_PLATFORMS\", targetPlatforms.join(\",\")\n            environment \"CARGOKIT_JAVA_HOME\", System.properties['java.home']\n        }\n    }\n}\n\nclass CargoKitPlugin implements Plugin<Project> {\n\n    static String file;\n\n    private Plugin findFlutterPlugin(Project rootProject) {\n        _findFlutterPlugin(rootProject.childProjects)\n    }\n\n   private Plugin _findFlutterPlugin(Map projects) {\n        for (project in projects) {\n            for (plugin in project.value.getPlugins()) {\n                if (plugin.class.name == \"com.flutter.gradle.FlutterPlugin\") {\n                    return plugin;\n                }\n            }\n            def plugin = _findFlutterPlugin(project.value.childProjects);\n            if (plugin != null) {\n                return plugin;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    void apply(Project project) {\n        def plugin = findFlutterPlugin(project.rootProject);\n\n        project.extensions.create(\"cargokit\", CargoKitExtension)\n\n        if (plugin == null) {\n            print(\"Flutter plugin not found, CargoKit plugin will not be applied.\")\n            return;\n        }\n\n        def cargoBuildDir = \"${project.buildDir}/build\"\n\n        // Determine if the project is an application or library\n        def isApplication = plugin.project.plugins.hasPlugin('com.android.application')\n        def variants = isApplication ? plugin.project.android.applicationVariants : plugin.project.android.libraryVariants\n\n        variants.all { variant ->\n\n            final buildType = variant.buildType.name\n\n            def cargoOutputDir = \"${project.buildDir}/jniLibs/${buildType}\";\n            def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs;\n            jniLibs.srcDir(new File(cargoOutputDir))\n\n            def platforms = com.flutter.gradle.FlutterPluginUtils.getTargetPlatforms(project).collect()\n\n            // Same thing addFlutterDependencies does in flutter.gradle\n            if (buildType == \"debug\") {\n                platforms.add(\"android-x86\")\n                platforms.add(\"android-x64\")\n            }\n\n            // The task name depends on plugin properties, which are not available\n            // at this point\n            project.getGradle().afterProject {\n                def taskName = \"cargokitCargoBuild${project.cargokit.libname.capitalize()}${buildType.capitalize()}\";\n\n                if (project.tasks.findByName(taskName)) {\n                    return\n                }\n\n                if (plugin.project.android.ndkVersion == null) {\n                    throw new GradleException(\"Please set 'android.ndkVersion' in 'app/build.gradle'.\")\n                }\n\n                def task = project.tasks.create(taskName, CargoKitBuildTask.class) {\n                    buildMode = variant.buildType.name\n                    buildDir = cargoBuildDir\n                    outputDir = cargoOutputDir\n                    ndkVersion = plugin.project.android.ndkVersion\n                    sdkDirectory = plugin.project.android.sdkDirectory\n                    minSdkVersion = plugin.project.android.defaultConfig.minSdkVersion.apiLevel as int\n                    compileSdkVersion = plugin.project.android.compileSdkVersion.substring(8) as int\n                    targetPlatforms = platforms\n                    pluginFile = CargoKitPlugin.file\n                }\n                def onTask = { newTask ->\n                    if (newTask.name == \"merge${buildType.capitalize()}NativeLibs\") {\n                        newTask.dependsOn task\n                        // Fix gradle 7.4.2 not picking up JNI library changes\n                        newTask.outputs.upToDateWhen { false }\n                    }\n                }\n                project.tasks.each onTask\n                project.tasks.whenTaskAdded onTask\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/run_build_tool.cmd",
    "content": "@echo off\nsetlocal\n\nsetlocal ENABLEDELAYEDEXPANSION\n\nSET BASEDIR=%~dp0\n\nif not exist \"%CARGOKIT_TOOL_TEMP_DIR%\" (\n    mkdir \"%CARGOKIT_TOOL_TEMP_DIR%\"\n)\ncd /D \"%CARGOKIT_TOOL_TEMP_DIR%\"\n\nSET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool\nSET DART=%FLUTTER_ROOT%\\bin\\cache\\dart-sdk\\bin\\dart\n\nset BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\\=/%\n\n(\n    echo name: build_tool_runner\n    echo version: 1.0.0\n    echo publish_to: none\n    echo.\n    echo environment:\n    echo   sdk: '^>=3.0.0 ^<4.0.0'\n    echo.\n    echo dependencies:\n    echo   build_tool:\n    echo     path: %BUILD_TOOL_PKG_DIR_POSIX%\n) >pubspec.yaml\n\nif not exist bin (\n    mkdir bin\n)\n\n(\n    echo import 'package:build_tool/build_tool.dart' as build_tool;\n    echo void main^(List^<String^> args^) ^{\n    echo    build_tool.runMain^(args^);\n    echo ^}\n) >bin\\build_tool_runner.dart\n\nSET PRECOMPILED=bin\\build_tool_runner.dill\n\nREM To detect changes in package we compare output of DIR /s (recursive)\nset PREV_PACKAGE_INFO=.dart_tool\\package_info.prev\nset CUR_PACKAGE_INFO=.dart_tool\\package_info.cur\n\nDIR \"%BUILD_TOOL_PKG_DIR%\" /s > \"%CUR_PACKAGE_INFO%_orig\"\n\nREM Last line in dir output is free space on harddrive. That is bound to\nREM change between invocation so we need to remove it\n(\n    Set \"Line=\"\n    For /F \"UseBackQ Delims=\" %%A In (\"%CUR_PACKAGE_INFO%_orig\") Do (\n        SetLocal EnableDelayedExpansion\n        If Defined Line Echo !Line!\n        EndLocal\n        Set \"Line=%%A\")\n) >\"%CUR_PACKAGE_INFO%\"\nDEL \"%CUR_PACKAGE_INFO%_orig\"\n\nREM Compare current directory listing with previous\nFC /B \"%CUR_PACKAGE_INFO%\" \"%PREV_PACKAGE_INFO%\" > nul 2>&1\n\nIf %ERRORLEVEL% neq 0 (\n    REM Changed - copy current to previous and remove precompiled kernel\n    if exist \"%PREV_PACKAGE_INFO%\" (\n        DEL \"%PREV_PACKAGE_INFO%\"\n    )\n    MOVE /Y \"%CUR_PACKAGE_INFO%\" \"%PREV_PACKAGE_INFO%\"\n    if exist \"%PRECOMPILED%\" (\n        DEL \"%PRECOMPILED%\"\n    )\n)\n\nREM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO%\nREM which means  we need to do pub get and precompile\nif not exist \"%PRECOMPILED%\" (\n    echo Running pub get in \"%cd%\"\n    \"%DART%\" pub get --no-precompile\n    \"%DART%\" compile kernel bin/build_tool_runner.dart\n)\n\n\"%DART%\" \"%PRECOMPILED%\" %*\n\nREM 253 means invalid snapshot version.\nIf %ERRORLEVEL% equ 253 (\n    \"%DART%\" pub get --no-precompile\n    \"%DART%\" compile kernel bin/build_tool_runner.dart\n    \"%DART%\" \"%PRECOMPILED%\" %*\n)\n"
  },
  {
    "path": "simple_live_app/rust_builder/cargokit/run_build_tool.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\nBASEDIR=$(dirname \"$0\")\n\nmkdir -p \"$CARGOKIT_TOOL_TEMP_DIR\"\n\ncd \"$CARGOKIT_TOOL_TEMP_DIR\"\n\n# Write a very simple bin package in temp folder that depends on build_tool package\n# from Cargokit. This is done to ensure that we don't pollute Cargokit folder\n# with .dart_tool contents.\n\nBUILD_TOOL_PKG_DIR=\"$BASEDIR/build_tool\"\n\nif [[ -z $FLUTTER_ROOT ]]; then # not defined\n  DART=dart\nelse\n  DART=\"$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart\"\nfi\n\ncat << EOF > \"pubspec.yaml\"\nname: build_tool_runner\nversion: 1.0.0\npublish_to: none\n\nenvironment:\n  sdk: '>=3.0.0 <4.0.0'\n\ndependencies:\n  build_tool:\n    path: \"$BUILD_TOOL_PKG_DIR\"\nEOF\n\nmkdir -p \"bin\"\n\ncat << EOF > \"bin/build_tool_runner.dart\"\nimport 'package:build_tool/build_tool.dart' as build_tool;\nvoid main(List<String> args) {\n  build_tool.runMain(args);\n}\nEOF\n\n# Create alias for `shasum` if it does not exist and `sha1sum` exists\nif ! [ -x \"$(command -v shasum)\" ] && [ -x \"$(command -v sha1sum)\" ]; then\n  shopt -s expand_aliases\n  alias shasum=\"sha1sum\"\nfi\n\n# Dart run will not cache any package that has a path dependency, which\n# is the case for our build_tool_runner. So instead we precompile the package\n# ourselves.\n# To invalidate the cached kernel we use the hash of ls -LR of the build_tool\n# package directory. This should be good enough, as the build_tool package\n# itself is not meant to have any path dependencies.\n\nif [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n  PACKAGE_HASH=$(ls -lTR \"$BUILD_TOOL_PKG_DIR\" | shasum)\nelse\n  PACKAGE_HASH=$(ls -lR --full-time \"$BUILD_TOOL_PKG_DIR\" | shasum)\nfi\n\nPACKAGE_HASH_FILE=\".package_hash\"\n\nif [ -f \"$PACKAGE_HASH_FILE\" ]; then\n    EXISTING_HASH=$(cat \"$PACKAGE_HASH_FILE\")\n    if [ \"$PACKAGE_HASH\" != \"$EXISTING_HASH\" ]; then\n        rm \"$PACKAGE_HASH_FILE\"\n    fi\nfi\n\n# Run pub get if needed.\nif [ ! -f \"$PACKAGE_HASH_FILE\" ]; then\n    \"$DART\" pub get --no-precompile\n    \"$DART\" compile kernel bin/build_tool_runner.dart\n    echo \"$PACKAGE_HASH\" > \"$PACKAGE_HASH_FILE\"\nfi\n\n# Rebuild the tool if it was deleted by Android Studio\nif [ ! -f \"bin/build_tool_runner.dill\" ]; then\n  \"$DART\" compile kernel bin/build_tool_runner.dart\nfi\n\nset +e\n\n\"$DART\" bin/build_tool_runner.dill \"$@\"\n\nexit_code=$?\n\n# 253 means invalid snapshot version.\nif [ $exit_code == 253 ]; then\n  \"$DART\" pub get --no-precompile\n  \"$DART\" compile kernel bin/build_tool_runner.dart\n  \"$DART\" bin/build_tool_runner.dill \"$@\"\n  exit_code=$?\nfi\n\nexit $exit_code\n"
  },
  {
    "path": "simple_live_app/rust_builder/ios/Classes/dummy_file.c",
    "content": "// This is an empty file to force CocoaPods to create a framework.\n"
  },
  {
    "path": "simple_live_app/rust_builder/ios/rust_lib_simple_live_app.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint rust_lib_simple_live_app.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'rust_lib_simple_live_app'\n  s.version          = '0.0.1'\n  s.summary          = 'A new Flutter FFI plugin project.'\n  s.description      = <<-DESC\nA new Flutter FFI plugin project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n\n  # This will ensure the source files in Classes/ are included in the native\n  # builds of apps using this FFI plugin. Podspec does not support relative\n  # paths, so Classes contains a forwarder C file that relatively imports\n  # `../src/*` so that the C sources can be shared among all target platforms.\n  s.source           = { :path => '.' }\n  s.source_files = 'Classes/**/*'\n  s.dependency 'Flutter'\n  s.platform = :ios, '11.0'\n\n  # Flutter.framework does not contain a i386 slice.\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }\n  s.swift_version = '5.0'\n\n  s.script_phase = {\n    :name => 'Build Rust library',\n    # First argument is relative path to the `rust` folder, second is name of rust library\n    :script => 'sh \"$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh\" ../../rust rust_lib_simple_live_app',\n    :execution_position => :before_compile,\n    :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],\n    # Let XCode know that the static library referenced in -force_load below is\n    # created by this build step.\n    :output_files => [\"${BUILT_PRODUCTS_DIR}/librust_lib_simple_live_app.a\"],\n  }\n  s.pod_target_xcconfig = {\n    'DEFINES_MODULE' => 'YES',\n    # Flutter.framework does not contain a i386 slice.\n    'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',\n    'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_simple_live_app.a',\n  }\nend"
  },
  {
    "path": "simple_live_app/rust_builder/linux/CMakeLists.txt",
    "content": "# The Flutter tooling requires that developers have CMake 3.10 or later\n# installed. You should not increase this version, as doing so will cause\n# the plugin to fail to compile for some customers of the plugin.\ncmake_minimum_required(VERSION 3.10)\n\n# Project-level configuration.\nset(PROJECT_NAME \"rust_lib_simple_live_app\")\nproject(${PROJECT_NAME} LANGUAGES CXX)\n\ninclude(\"../cargokit/cmake/cargokit.cmake\")\napply_cargokit(${PROJECT_NAME} ../../rust rust_lib_simple_live_app \"\")\n\n# List of absolute paths to libraries that should be bundled with the plugin.\n# This list could contain prebuilt libraries, or libraries created by an\n# external build triggered from this build file.\nset(rust_lib_simple_live_app_bundled_libraries\n  \"${${PROJECT_NAME}_cargokit_lib}\"\n  PARENT_SCOPE\n)\n"
  },
  {
    "path": "simple_live_app/rust_builder/macos/Classes/dummy_file.c",
    "content": "// This is an empty file to force CocoaPods to create a framework.\n"
  },
  {
    "path": "simple_live_app/rust_builder/macos/rust_lib_simple_live_app.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint rust_lib_simple_live_app.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'rust_lib_simple_live_app'\n  s.version          = '0.0.1'\n  s.summary          = 'A new Flutter FFI plugin project.'\n  s.description      = <<-DESC\nA new Flutter FFI plugin project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n\n  # This will ensure the source files in Classes/ are included in the native\n  # builds of apps using this FFI plugin. Podspec does not support relative\n  # paths, so Classes contains a forwarder C file that relatively imports\n  # `../src/*` so that the C sources can be shared among all target platforms.\n  s.source           = { :path => '.' }\n  s.source_files     = 'Classes/**/*'\n  s.dependency 'FlutterMacOS'\n\n  s.platform = :osx, '10.11'\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }\n  s.swift_version = '5.0'\n\n  s.script_phase = {\n    :name => 'Build Rust library',\n    # First argument is relative path to the `rust` folder, second is name of rust library\n    :script => 'sh \"$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh\" ../../rust rust_lib_simple_live_app',\n    :execution_position => :before_compile,\n    :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],\n    # Let XCode know that the static library referenced in -force_load below is\n    # created by this build step.\n    :output_files => [\"${BUILT_PRODUCTS_DIR}/librust_lib_simple_live_app.a\"],\n  }\n  s.pod_target_xcconfig = {\n    'DEFINES_MODULE' => 'YES',\n    # Flutter.framework does not contain a i386 slice.\n    'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',\n    'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_simple_live_app.a',\n  }\nend"
  },
  {
    "path": "simple_live_app/rust_builder/pubspec.yaml",
    "content": "name: rust_lib_simple_live_app\ndescription: \"Utility to build Rust code\"\nversion: 0.0.1\npublish_to: none\n\nenvironment:\n  sdk: '>=3.3.0 <4.0.0'\n  flutter: '>=3.3.0'\n\ndependencies:\n  flutter:\n    sdk: flutter\n  plugin_platform_interface: ^2.0.2\n\ndev_dependencies:\n  ffi: ^2.0.2\n  ffigen: ^11.0.0\n  flutter_test:\n    sdk: flutter\n  flutter_lints: ^2.0.0\n\nflutter:\n  plugin:\n    platforms:\n      android:\n        ffiPlugin: true\n      ios:\n        ffiPlugin: true\n      linux:\n        ffiPlugin: true\n      macos:\n        ffiPlugin: true\n      windows:\n        ffiPlugin: true\n"
  },
  {
    "path": "simple_live_app/rust_builder/windows/.gitignore",
    "content": "flutter/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio build-related files.\nx64/\nx86/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n"
  },
  {
    "path": "simple_live_app/rust_builder/windows/CMakeLists.txt",
    "content": "# The Flutter tooling requires that developers have a version of Visual Studio\n# installed that includes CMake 3.14 or later. You should not increase this\n# version, as doing so will cause the plugin to fail to compile for some\n# customers of the plugin.\ncmake_minimum_required(VERSION 3.14)\n\n# Project-level configuration.\nset(PROJECT_NAME \"rust_lib_simple_live_app\")\nproject(${PROJECT_NAME} LANGUAGES CXX)\n\ninclude(\"../cargokit/cmake/cargokit.cmake\")\napply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib_simple_live_app \"\")\n\n# List of absolute paths to libraries that should be bundled with the plugin.\n# This list could contain prebuilt libraries, or libraries created by an\n# external build triggered from this build file.\nset(rust_lib_simple_live_app_bundled_libraries\n  \"${${PROJECT_NAME}_cargokit_lib}\"\n  PARENT_SCOPE\n)\n"
  },
  {
    "path": "simple_live_app/shorebird.yaml",
    "content": "# This file is used to configure the Shorebird updater used by your app.\n# Learn more at https://docs.shorebird.dev\n# This file does not contain any sensitive information and should be checked into version control.\n\n# Your app_id is the unique identifier assigned to your app.\n# It is used to identify your app when requesting patches from Shorebird's servers.\n# It is not a secret and can be shared publicly.\napp_id: b5d433ae-4762-463d-88b0-b6e18efc5891\n\n# auto_update controls if Shorebird should automatically update in the background on launch.\n# If auto_update: false, you will need to use package:shorebird_code_push to trigger updates.\n# https://pub.dev/packages/shorebird_code_push\n# Uncomment the following line to disable automatic updates.\n# auto_update: false\n"
  },
  {
    "path": "simple_live_app/test/tool_test.dart",
    "content": "﻿import 'package:flutter_test/flutter_test.dart';\nimport 'package:pinyin/pinyin.dart';\n\nvoid testPinyin(){\n  test(\"测试拼音\", (){\n    var str = \"zzz你好啊\";\n    var res = PinyinHelper.getShortPinyin(str);\n    print(res);\n  });\n}\n\nvoid main(){\n  testPinyin();\n}"
  },
  {
    "path": "simple_live_app/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility in the flutter_test package. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'package:simple_live_app/main.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    await tester.pumpWidget(const MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "simple_live_app/test_driver/integration_test.dart",
    "content": "import 'package:integration_test/integration_test_driver.dart';\n\nFuture<void> main() => integrationDriver();\n"
  },
  {
    "path": "simple_live_app/windows/.gitignore",
    "content": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio build-related files.\nx64/\nx86/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n"
  },
  {
    "path": "simple_live_app/windows/CMakeLists.txt",
    "content": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.14)\nproject(simple_live_app LANGUAGES CXX)\n\n# The name of the executable created for the application. Change this to change\n# the on-disk name of your application.\nset(BINARY_NAME \"slive\")\n\n# Explicitly opt in to modern CMake behaviors to avoid warnings with recent\n# versions of CMake.\ncmake_policy(SET CMP0063 NEW)\n\n# Define build configuration option.\nget_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\nif(IS_MULTICONFIG)\n  set(CMAKE_CONFIGURATION_TYPES \"Debug;Profile;Release\"\n    CACHE STRING \"\" FORCE)\nelse()\n  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n    set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n      STRING \"Flutter build mode\" FORCE)\n    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n      \"Debug\" \"Profile\" \"Release\")\n  endif()\nendif()\n# Define settings for the Profile build mode.\nset(CMAKE_POLICY_VERSION_MINIMUM 3.15)\nset(CMAKE_EXE_LINKER_FLAGS_PROFILE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_SHARED_LINKER_FLAGS_PROFILE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_C_FLAGS_PROFILE \"${CMAKE_C_FLAGS_RELEASE}\")\nset(CMAKE_CXX_FLAGS_PROFILE \"${CMAKE_CXX_FLAGS_RELEASE}\")\n\n# Use Unicode for all projects.\nadd_definitions(-DUNICODE -D_UNICODE)\n\n# Compilation settings that should be applied to most targets.\n#\n# Be cautious about adding new options here, as plugins use this function by\n# default. In most cases, you should add new options to specific targets instead\n# of modifying this function.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_17)\n  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd\"4100\")\n  target_compile_options(${TARGET} PRIVATE /EHsc)\n  target_compile_definitions(${TARGET} PRIVATE \"_HAS_EXCEPTIONS=0\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<CONFIG:Debug>:_DEBUG>\")\nendfunction()\n\n# Flutter library and tool build rules.\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# Application build; see runner/CMakeLists.txt.\nadd_subdirectory(\"runner\")\n\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# Support files are copied into place next to the executable, so that it can\n# run in place. This is done instead of making a separate bundle (as on Linux)\n# so that building and running from within Visual Studio will work.\nset(BUILD_BUNDLE_DIR \"$<TARGET_FILE_DIR:${BINARY_NAME}>\")\n# Make the \"install\" step default, as it's required to run.\nset(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\ninstall(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  CONFIGURATIONS Profile;Release\n  COMPONENT Runtime)\n"
  },
  {
    "path": "simple_live_app/windows/flutter/CMakeLists.txt",
    "content": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.14)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\nset(WRAPPER_ROOT \"${EPHEMERAL_DIR}/cpp_client_wrapper\")\n\n# Set fallback configurations for older versions of the flutter tool.\nif (NOT DEFINED FLUTTER_TARGET_PLATFORM)\n  set(FLUTTER_TARGET_PLATFORM \"windows-x64\")\nendif()\n\n# === Flutter Library ===\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/flutter_windows.dll\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/windows/app.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"flutter_export.h\"\n  \"flutter_windows.h\"\n  \"flutter_messenger.h\"\n  \"flutter_plugin_registrar.h\"\n  \"flutter_texture_registrar.h\"\n)\nlist(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND \"${EPHEMERAL_DIR}/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}.lib\")\nadd_dependencies(flutter flutter_assemble)\n\n# === Wrapper ===\nlist(APPEND CPP_WRAPPER_SOURCES_CORE\n  \"core_implementations.cc\"\n  \"standard_codec.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_PLUGIN\n  \"plugin_registrar.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_APP\n  \"flutter_engine.cc\"\n  \"flutter_view_controller.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND \"${WRAPPER_ROOT}/\")\n\n# Wrapper sources needed for a plugin.\nadd_library(flutter_wrapper_plugin STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n)\napply_standard_settings(flutter_wrapper_plugin)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  POSITION_INDEPENDENT_CODE ON)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  CXX_VISIBILITY_PRESET hidden)\ntarget_link_libraries(flutter_wrapper_plugin PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_plugin PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_plugin flutter_assemble)\n\n# Wrapper sources needed for the runner.\nadd_library(flutter_wrapper_app STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\napply_standard_settings(flutter_wrapper_app)\ntarget_link_libraries(flutter_wrapper_app PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_app PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_app flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nset(PHONY_OUTPUT \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\")\nset_source_files_properties(\"${PHONY_OUTPUT}\" PROPERTIES SYMBOLIC TRUE)\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}\n    ${CPP_WRAPPER_SOURCES_APP}\n    ${PHONY_OUTPUT}\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat\"\n      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\n"
  },
  {
    "path": "simple_live_app/windows/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n#include <connectivity_plus/connectivity_plus_windows_plugin.h>\n#include <dynamic_color/dynamic_color_plugin_c_api.h>\n#include <firebase_core/firebase_core_plugin_c_api.h>\n#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>\n#include <flutter_qjs/flutter_qjs_plugin.h>\n#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>\n#include <media_kit_video/media_kit_video_plugin_c_api.h>\n#include <screen_brightness_windows/screen_brightness_windows_plugin.h>\n#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>\n#include <share_plus/share_plus_windows_plugin_c_api.h>\n#include <url_launcher_windows/url_launcher_windows.h>\n#include <volume_controller/volume_controller_plugin_c_api.h>\n#include <window_manager/window_manager_plugin.h>\n\nvoid RegisterPlugins(flutter::PluginRegistry* registry) {\n  ConnectivityPlusWindowsPluginRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"ConnectivityPlusWindowsPlugin\"));\n  DynamicColorPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"DynamicColorPluginCApi\"));\n  FirebaseCorePluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"FirebaseCorePluginCApi\"));\n  FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"FlutterInappwebviewWindowsPluginCApi\"));\n  FlutterQjsPluginRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"FlutterQjsPlugin\"));\n  MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"MediaKitLibsWindowsVideoPluginCApi\"));\n  MediaKitVideoPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"MediaKitVideoPluginCApi\"));\n  ScreenBrightnessWindowsPluginRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"ScreenBrightnessWindowsPlugin\"));\n  ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"ScreenRetrieverWindowsPluginCApi\"));\n  SharePlusWindowsPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"SharePlusWindowsPluginCApi\"));\n  UrlLauncherWindowsRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"UrlLauncherWindows\"));\n  VolumeControllerPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"VolumeControllerPluginCApi\"));\n  WindowManagerPluginRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"WindowManagerPlugin\"));\n}\n"
  },
  {
    "path": "simple_live_app/windows/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter/plugin_registry.h>\n\n// Registers Flutter plugins.\nvoid RegisterPlugins(flutter::PluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "simple_live_app/windows/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n  connectivity_plus\n  dynamic_color\n  firebase_core\n  flutter_inappwebview_windows\n  flutter_qjs\n  media_kit_libs_windows_video\n  media_kit_video\n  screen_brightness_windows\n  screen_retriever_windows\n  share_plus\n  url_launcher_windows\n  volume_controller\n  window_manager\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n  rust_lib_simple_live_app\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "simple_live_app/windows/packaging/exe/ChineseSimplified.isl",
    "content": "﻿; *** Inno Setup version 6.4.0+ Chinese Simplified messages ***\n;\n; To download user-contributed translations of this file, go to:\n;   https://jrsoftware.org/files/istrans/\n;\n; Note: When translating this text, do not add periods (.) to the end of\n; messages that didn't have them already, because on those messages Inno\n; Setup adds the periods automatically (appending a period would result in\n; two periods being displayed).\n;\n; Maintained by Zhenghan Yang\n; Email: 847320916@QQ.com\n; Translation based on network resource\n; The latest Translation is on https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation\n;\n\n[LangOptions]\n; The following three entries are very important. Be sure to read and \n; understand the '[LangOptions] section' topic in the help file.\nLanguageName=简体中文\n; If Language Name display incorrect, uncomment next line\n; LanguageName=<7B80><4F53><4E2D><6587>\n; About LanguageID, to reference link:\n; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c\nLanguageID=$0804\n; About CodePage, to reference link:\n; https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers\nLanguageCodePage=936\n; If the language you are translating to requires special font faces or\n; sizes, uncomment any of the following entries and change them accordingly.\n;DialogFontName=\n;DialogFontSize=8\n;WelcomeFontName=Verdana\n;WelcomeFontSize=12\n;TitleFontName=Arial\n;TitleFontSize=29\n;CopyrightFontName=Arial\n;CopyrightFontSize=8\n\n[Messages]\n\n; *** 应用程序标题\nSetupAppTitle=安装\nSetupWindowTitle=安装 - %1\nUninstallAppTitle=卸载\nUninstallAppFullTitle=%1 卸载\n\n; *** Misc. common\nInformationTitle=信息\nConfirmTitle=确认\nErrorTitle=错误\n\n; *** SetupLdr messages\nSetupLdrStartupMessage=现在将安装 %1。您想要继续吗？\nLdrCannotCreateTemp=无法创建临时文件。安装程序已中止\nLdrCannotExecTemp=无法执行临时目录中的文件。安装程序已中止\nHelpTextNote=\n\n; *** 启动错误消息\nLastErrorMessage=%1。%n%n错误 %2: %3\nSetupFileMissing=安装目录中缺少文件 %1。请修正这个问题或者获取程序的新副本。\nSetupFileCorrupt=安装文件已损坏。请获取程序的新副本。\nSetupFileCorruptOrWrongVer=安装文件已损坏，或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。\nInvalidParameter=无效的命令行参数：%n%n%1\nSetupAlreadyRunning=安装程序正在运行。\nWindowsVersionNotSupported=此程序不支持当前计算机运行的 Windows 版本。\nWindowsServicePackRequired=此程序需要 %1 服务包 %2 或更高版本。\nNotOnThisPlatform=此程序不能在 %1 上运行。\nOnlyOnThisPlatform=此程序只能在 %1 上运行。\nOnlyOnTheseArchitectures=此程序只能安装到为下列处理器架构设计的 Windows 版本中：%n%n%1\nWinVersionTooLowError=此程序需要 %1 版本 %2 或更高。\nWinVersionTooHighError=此程序不能安装于 %1 版本 %2 或更高。\nAdminPrivilegesRequired=在安装此程序时您必须以管理员身份登录。\nPowerUserPrivilegesRequired=在安装此程序时您必须以管理员身份或有权限的用户组身份登录。\nSetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序，然后点击“确定”继续，或点击“取消”退出。\nUninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序，然后点击“确定”继续，或点击“取消”退出。\n\n; *** 启动问题\nPrivilegesRequiredOverrideTitle=选择安装程序模式\nPrivilegesRequiredOverrideInstruction=选择安装模式\nPrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限)，或仅为您安装。\nPrivilegesRequiredOverrideText2=%1 只能为您安装，或为所有用户安装(需要管理员权限)。\nPrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)\nPrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A) (建议选项)\nPrivilegesRequiredOverrideCurrentUser=只为我安装(&M)\nPrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(&M) (建议选项)\n\n; *** 其他错误\nErrorCreatingDir=安装程序无法创建目录“%1”\nErrorTooManyFilesInDir=无法在目录“%1”中创建文件，因为里面包含太多文件\n\n; *** 安装程序公共消息\nExitSetupTitle=退出安装程序\nExitSetupMessage=安装程序尚未完成。如果现在退出，将不会安装该程序。%n%n您之后可以再次运行安装程序完成安装。%n%n现在退出安装程序吗？\nAboutSetupMenuItem=关于安装程序(&A)...\nAboutSetupTitle=关于安装程序\nAboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页：%n%4\nAboutSetupNote=\nTranslatorNote=简体中文翻译由Kira(847320916@qq.com)维护。项目地址：https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation\n\n; *** 按钮\nButtonBack=< 上一步(&B)\nButtonNext=下一步(&N) >\nButtonInstall=安装(&I)\nButtonOK=确定\nButtonCancel=取消\nButtonYes=是(&Y)\nButtonYesToAll=全是(&A)\nButtonNo=否(&N)\nButtonNoToAll=全否(&O)\nButtonFinish=完成(&F)\nButtonBrowse=浏览(&B)...\nButtonWizardBrowse=浏览(&R)...\nButtonNewFolder=新建文件夹(&M)\n\n; *** “选择语言”对话框消息\nSelectLanguageTitle=选择安装语言\nSelectLanguageLabel=选择安装时使用的语言。\n\n; *** 公共向导文字\nClickNext=点击“下一步”继续，或点击“取消”退出安装程序。\nBeveledLabel=\nBrowseDialogTitle=浏览文件夹\nBrowseDialogLabel=在下面的列表中选择一个文件夹，然后点击“确定”。\nNewFolderName=新建文件夹\n\n; *** “欢迎”向导页\nWelcomeLabel1=欢迎使用 [name] 安装向导\nWelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n建议您在继续安装前关闭所有其他应用程序。\n\n; *** “密码”向导页\nWizardPassword=密码\nPasswordLabel1=这个安装程序有密码保护。\nPasswordLabel3=请输入密码，然后点击“下一步”继续。密码区分大小写。\nPasswordEditLabel=密码(&P)：\nIncorrectPassword=您输入的密码不正确，请重新输入。\n\n; *** “许可协议”向导页\nWizardLicense=许可协议\nLicenseLabel=请在继续安装前阅读以下重要信息。\nLicenseLabel3=请仔细阅读下列许可协议。在继续安装前您必须同意这些协议条款。\nLicenseAccepted=我同意此协议(&A)\nLicenseNotAccepted=我不同意此协议(&D)\n\n; *** “信息”向导页\nWizardInfoBefore=信息\nInfoBeforeLabel=请在继续安装前阅读以下重要信息。\nInfoBeforeClickLabel=准备好继续安装后，点击“下一步”。\nWizardInfoAfter=信息\nInfoAfterLabel=请在继续安装前阅读以下重要信息。\nInfoAfterClickLabel=准备好继续安装后，点击“下一步”。\n\n; *** “用户信息”向导页\nWizardUserInfo=用户信息\nUserInfoDesc=请输入您的信息。\nUserInfoName=用户名(&U)：\nUserInfoOrg=组织(&O)：\nUserInfoSerial=序列号(&S)：\nUserInfoNameRequired=您必须输入用户名。\n\n; *** “选择目标目录”向导页\nWizardSelectDir=选择目标位置\nSelectDirDesc=您想将 [name] 安装在哪里？\nSelectDirLabel3=安装程序将安装 [name] 到下面的文件夹中。\nSelectDirBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹，点击“浏览”。\nDiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。\nDiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。\nCannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。\nCannotInstallToUNCPath=安装程序无法安装到一个 UNC 路径。\nInvalidPath=您必须输入一个带驱动器卷标的完整路径，例如：%n%nC:\\APP%n%n或UNC路径：%n%n\\\\server\\share\nInvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选择其他位置。\nDiskSpaceWarningTitle=磁盘空间不足\nDiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装，但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗？\nDirNameTooLong=文件夹名称或路径太长。\nInvalidDirName=文件夹名称无效。\nBadDirName32=文件夹名称不能包含下列任何字符：%n%n%1\nDirExistsTitle=文件夹已存在\nDirExists=文件夹：%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗？\nDirDoesntExistTitle=文件夹不存在\nDirDoesntExist=文件夹：%n%n%1%n%n不存在。您想要创建此文件夹吗？\n\n; *** “选择组件”向导页\nWizardSelectComponents=选择组件\nSelectComponentsDesc=您想安装哪些程序组件？\nSelectComponentsLabel2=选中您想安装的组件；取消您不想安装的组件。然后点击“下一步”继续。\nFullInstallation=完全安装\n; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)\nCompactInstallation=简洁安装\nCustomInstallation=自定义安装\nNoUninstallWarningTitle=组件已存在\nNoUninstallWarning=安装程序检测到下列组件已安装在您的电脑中：%n%n%1%n%n取消选中这些组件不会卸载它们。%n%n确定要继续吗？\nComponentSize1=%1 KB\nComponentSize2=%1 MB\nComponentsDiskSpaceGBLabel=当前选择的组件需要至少 [gb] GB 的磁盘空间。\nComponentsDiskSpaceMBLabel=当前选择的组件需要至少 [mb] MB 的磁盘空间。\n\n; *** “选择附加任务”向导页\nWizardSelectTasks=选择附加任务\nSelectTasksDesc=您想要安装程序执行哪些附加任务？\nSelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务，然后点击“下一步”。\n\n; *** “选择开始菜单文件夹”向导页\nWizardSelectProgramGroup=选择开始菜单文件夹\nSelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式？\nSelectStartMenuFolderLabel3=安装程序将在下列“开始”菜单文件夹中创建程序的快捷方式。\nSelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹，点击“浏览”。\nMustEnterGroupName=您必须输入一个文件夹名。\nGroupNameTooLong=文件夹名或路径太长。\nInvalidGroupName=无效的文件夹名字。\nBadGroupName=文件夹名不能包含下列任何字符：%n%n%1\nNoProgramGroupCheck2=不创建开始菜单文件夹(&D)\n\n; *** “准备安装”向导页\nWizardReady=准备安装\nReadyLabel1=安装程序准备就绪，现在可以开始安装 [name] 到您的电脑。\nReadyLabel2a=点击“安装”继续此安装程序。如果您想重新考虑或修改任何设置，点击“上一步”。\nReadyLabel2b=点击“安装”继续此安装程序。\nReadyMemoUserInfo=用户信息：\nReadyMemoDir=目标位置：\nReadyMemoType=安装类型：\nReadyMemoComponents=已选择组件：\nReadyMemoGroup=开始菜单文件夹：\nReadyMemoTasks=附加任务：\n\n; *** TExtractionWizardPage wizard page and Extract7ZipArchive\nExtractionLabel=正在提取附加文件...\nButtonStopExtraction=停止提取(&S)\nStopExtraction=您确定要停止提取吗？\nErrorExtractionAborted=提取已中止\nErrorExtractionFailed=提取失败：%1\n\n; *** TDownloadWizardPage wizard page and DownloadTemporaryFile\nDownloadingLabel=正在下载附加文件...\nButtonStopDownload=停止下载(&S)\nStopDownload=您确定要停止下载吗？\nErrorDownloadAborted=下载已中止\nErrorDownloadFailed=下载失败：%1 %2\nErrorDownloadSizeFailed=获取下载大小失败：%1 %2\nErrorFileHash1=校验文件哈希失败：%1\nErrorFileHash2=无效的文件哈希：预期 %1，实际 %2\nErrorProgress=无效的进度：%1 / %2\nErrorFileSize=文件大小错误：预期 %1，实际 %2\n\n; *** “正在准备安装”向导页\nWizardPreparing=正在准备安装\nPreparingDesc=安装程序正在准备安装 [name] 到您的电脑。\nPreviousInstallNotCompleted=先前的程序安装或卸载未完成，您需要重启您的电脑以完成。%n%n在重启电脑后，再次运行安装程序以完成 [name] 的安装。\nCannotContinue=安装程序不能继续。请点击“取消”退出。\nApplicationsFound=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。\nApplicationsFound2=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。安装完成后，安装程序将尝试重新启动这些应用程序。\nCloseApplications=自动关闭应用程序(&A)\nDontCloseApplications=不要关闭应用程序(&D)\nErrorCloseApplications=安装程序无法自动关闭所有应用程序。建议您在继续之前，关闭所有在使用需要由安装程序更新的文件的应用程序。\nPrepareToInstallNeedsRestart=安装程序必须重启您的计算机。计算机重启后，请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动？\n\n; *** “正在安装”向导页\nWizardInstalling=正在安装\nInstallingLabel=安装程序正在安装 [name] 到您的电脑，请稍候。\n\n; *** “安装完成”向导页\nFinishedHeadingLabel=[name] 安装完成\nFinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。\nFinishedLabel=安装程序已在您的电脑中安装了 [name]。您可以通过已安装的快捷方式运行此应用程序。\nClickFinish=点击“完成”退出安装程序。\nFinishedRestartLabel=为完成 [name] 的安装，安装程序必须重新启动您的电脑。要立即重启吗？\nFinishedRestartMessage=为完成 [name] 的安装，安装程序必须重新启动您的电脑。%n%n要立即重启吗？\nShowReadmeCheck=是，我想查阅自述文件\nYesRadio=是，立即重启电脑(&Y)\nNoRadio=否，稍后重启电脑(&N)\n; used for example as 'Run MyProg.exe'\nRunEntryExec=运行 %1\n; used for example as 'View Readme.txt'\nRunEntryShellExec=查阅 %1\n\n; *** “安装程序需要下一张磁盘”提示\nChangeDiskTitle=安装程序需要下一张磁盘\nSelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到，请输入正确的路径或点击“浏览”。\nPathLabel=路径(&P)：\nFileNotInDir2=“%2”中找不到文件“%1”。请插入正确的磁盘或选择其他文件夹。\nSelectDirectoryLabel=请指定下一张磁盘的位置。\n\n; *** 安装状态消息\nSetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。\nAbortRetryIgnoreSelectAction=选择操作\nAbortRetryIgnoreRetry=重试(&T)\nAbortRetryIgnoreIgnore=忽略错误并继续(&I)\nAbortRetryIgnoreCancel=关闭安装程序\n\n; *** 安装状态消息\nStatusClosingApplications=正在关闭应用程序...\nStatusCreateDirs=正在创建目录...\nStatusExtractFiles=正在解压缩文件...\nStatusCreateIcons=正在创建快捷方式...\nStatusCreateIniEntries=正在创建 INI 条目...\nStatusCreateRegistryEntries=正在创建注册表条目...\nStatusRegisterFiles=正在注册文件...\nStatusSavingUninstall=正在保存卸载信息...\nStatusRunProgram=正在完成安装...\nStatusRestartingApplications=正在重启应用程序...\nStatusRollback=正在撤销更改...\n\n; *** 其他错误\nErrorInternal2=内部错误：%1\nErrorFunctionFailedNoCode=%1 失败\nErrorFunctionFailed=%1 失败；错误代码 %2\nErrorFunctionFailedWithMessage=%1 失败；错误代码 %2.%n%3\nErrorExecutingProgram=无法执行文件：%n%1\n\n; *** 注册表错误\nErrorRegOpenKey=打开注册表项时出错：%n%1\\%2\nErrorRegCreateKey=创建注册表项时出错：%n%1\\%2\nErrorRegWriteKey=写入注册表项时出错：%n%1\\%2\n\n; *** INI 错误\nErrorIniEntry=在文件“%1”中创建 INI 条目时出错。\n\n; *** 文件复制错误\nFileAbortRetryIgnoreSkipNotRecommended=跳过此文件(&S) (不推荐)\nFileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I) (不推荐)\nSourceIsCorrupted=源文件已损坏\nSourceDoesntExist=源文件“%1”不存在\nExistingFileReadOnly2=无法替换现有文件，它是只读的。\nExistingFileReadOnlyRetry=移除只读属性并重试(&R)\nExistingFileReadOnlyKeepExisting=保留现有文件(&K)\nErrorReadingExistingDest=尝试读取现有文件时出错：\nFileExistsSelectAction=选择操作\nFileExists2=文件已经存在。\nFileExistsOverwriteExisting=覆盖已存在的文件(&O)\nFileExistsKeepExisting=保留现有的文件(&K)\nFileExistsOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)\nExistingFileNewerSelectAction=选择操作\nExistingFileNewer2=现有的文件比安装程序将要安装的文件还要新。\nExistingFileNewerOverwriteExisting=覆盖已存在的文件(&O)\nExistingFileNewerKeepExisting=保留现有的文件(&K) (推荐)\nExistingFileNewerOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)\nErrorChangingAttr=尝试更改下列现有文件的属性时出错：\nErrorCreatingTemp=尝试在目标目录创建文件时出错：\nErrorReadingSource=尝试读取下列源文件时出错：\nErrorCopying=尝试复制下列文件时出错：\nErrorReplacingExistingFile=尝试替换现有文件时出错：\nErrorRestartReplace=重启并替换失败：\nErrorRenamingTemp=尝试重命名下列目标目录中的一个文件时出错：\nErrorRegisterServer=无法注册 DLL/OCX：%1\nErrorRegSvr32Failed=RegSvr32 失败；退出代码 %1\nErrorRegisterTypeLib=无法注册类库：%1\n\n; *** 卸载显示名字标记\n; used for example as 'My Program (32-bit)'\nUninstallDisplayNameMark=%1 (%2)\n; used for example as 'My Program (32-bit, All users)'\nUninstallDisplayNameMarks=%1 (%2, %3)\nUninstallDisplayNameMark32Bit=32 位\nUninstallDisplayNameMark64Bit=64 位\nUninstallDisplayNameMarkAllUsers=所有用户\nUninstallDisplayNameMarkCurrentUser=当前用户\n\n; *** 安装后错误\nErrorOpeningReadme=尝试打开自述文件时出错。\nErrorRestartingComputer=安装程序无法重启电脑，请手动重启。\n\n; *** 卸载消息\nUninstallNotFound=文件“%1”不存在。无法卸载。\nUninstallOpenError=文件“%1”不能被打开。无法卸载。\nUninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载\nUninstallUnknownEntry=卸载日志中遇到一个未知条目 (%1)\nConfirmUninstall=您确认要完全移除 %1 及其所有组件吗？\nUninstallOnlyOnWin64=仅允许在 64 位 Windows 中卸载此程序。\nOnlyAdminCanUninstall=仅使用管理员权限的用户能完成此卸载。\nUninstallStatusLabel=正在从您的电脑中移除 %1，请稍候。\nUninstalledAll=已顺利从您的电脑中移除 %1。\nUninstalledMost=%1 卸载完成。%n%n有部分内容未能被删除，但您可以手动删除它们。\nUninstalledAndNeedsRestart=为完成 %1 的卸载，需要重启您的电脑。%n%n立即重启电脑吗？\nUninstallDataCorrupted=文件“%1”已损坏。无法卸载\n\n; *** 卸载状态消息\nConfirmDeleteSharedFileTitle=删除共享的文件吗？\nConfirmDeleteSharedFile2=系统表示下列共享的文件已不有其他程序使用。您希望卸载程序删除这些共享的文件吗？%n%n如果删除这些文件，但仍有程序在使用这些文件，则这些程序可能出现异常。如果您不能确定，请选择“否”，在系统中保留这些文件以免引发问题。\nSharedFileNameLabel=文件名：\nSharedFileLocationLabel=位置：\nWizardUninstalling=卸载状态\nStatusUninstalling=正在卸载 %1...\n\n; *** Shutdown block reasons\nShutdownBlockReasonInstallingApp=正在安装 %1。\nShutdownBlockReasonUninstallingApp=正在卸载 %1。\n\n; The custom messages below aren't used by Setup itself, but if you make\n; use of them in your scripts, you'll want to translate them.\n\n[CustomMessages]\n\nNameAndVersion=%1 版本 %2\nAdditionalIcons=附加快捷方式：\nCreateDesktopIcon=创建桌面快捷方式(&D)\nCreateQuickLaunchIcon=创建快速启动栏快捷方式(&Q)\nProgramOnTheWeb=%1 网站\nUninstallProgram=卸载 %1\nLaunchProgram=运行 %1\nAssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)\nAssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...\nAutoStartProgramGroupDescription=启动：\nAutoStartProgram=自动启动 %1\nAddonHostProgramNotFound=您选择的文件夹中无法找到 %1。%n%n您要继续吗？\n"
  },
  {
    "path": "simple_live_app/windows/packaging/exe/make_config.yaml",
    "content": "display_name: Slive\napp_id: 45F6FA98-DA23-4795-8685-60F607317A1F\npublisher: slotsun\npublisher_url: https://github.com/fastforgedev/fastforge\ncreate_desktop_icon: true\n# See: https://jrsoftware.org/ishelp/index.php?topic=setup_defaultdirname\ninstall_dir_name: \"D:\\\\Program Files (x86)\\\\simple_live\"\n# 这里的路径是相对于项目根目录的路径； 图标格式必须是ico格式，不能是png或其它\nsetup_icon_file: assets/icons/app_icon.ico\nlocales:\n  - en\n  - zh"
  },
  {
    "path": "simple_live_app/windows/packaging/msix/make_config.yaml",
    "content": "display_name: Slive\npublisher_display_name: slotsun\nidentity_name: com.slotsun.slive\nlogo_path: assets/logo_400.png\ncapabilities: internetClient\nlanguages: zh-cn\ninstall_certificate: \"false\"\nsigntool_options: /td SHA256"
  },
  {
    "path": "simple_live_app/windows/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.14)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name, change BINARY_NAME in the\n# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer\n# work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME} WIN32\n  \"flutter_window.cpp\"\n  \"main.cpp\"\n  \"utils.cpp\"\n  \"win32_window.cpp\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n  \"Runner.rc\"\n  \"runner.exe.manifest\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add preprocessor definitions for the build version.\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION=\\\"${FLUTTER_VERSION}\\\"\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}\")\n\n# Disable Windows macros that collide with C++ standard library functions.\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"NOMINMAX\")\n\n# Add dependency libraries and include directories. Add any application-specific\n# dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)\ntarget_link_libraries(${BINARY_NAME} PRIVATE \"dwmapi.lib\")\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\n\n# Run the Flutter tool portions of the build. This must not be removed.\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n"
  },
  {
    "path": "simple_live_app/windows/runner/Runner.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_APP_ICON            ICON                    \"resources\\\\app_icon.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\n#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)\n#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD\n#else\n#define VERSION_AS_NUMBER 1,0,0,0\n#endif\n\n#if defined(FLUTTER_VERSION)\n#define VERSION_AS_STRING FLUTTER_VERSION\n#else\n#define VERSION_AS_STRING \"1.0.0\"\n#endif\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION VERSION_AS_NUMBER\n PRODUCTVERSION VERSION_AS_NUMBER\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS__WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904e4\"\n        BEGIN\n            VALUE \"CompanyName\", \"com.slotsun\" \"\\0\"\n            VALUE \"FileDescription\", \"slive\" \"\\0\"\n            VALUE \"FileVersion\", VERSION_AS_STRING \"\\0\"\n            VALUE \"InternalName\", \"slive\" \"\\0\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2023 com.xycz and com.slotsun. All rights reserved.\" \"\\0\"\n            VALUE \"OriginalFilename\", \"slive.exe\" \"\\0\"\n            VALUE \"ProductName\", \"slive\" \"\\0\"\n            VALUE \"ProductVersion\", VERSION_AS_STRING \"\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n"
  },
  {
    "path": "simple_live_app/windows/runner/flutter_window.cpp",
    "content": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::FlutterWindow(const flutter::DartProject& project)\n    : project_(project) {}\n\nFlutterWindow::~FlutterWindow() {}\n\nbool FlutterWindow::OnCreate() {\n  if (!Win32Window::OnCreate()) {\n    return false;\n  }\n\n  RECT frame = GetClientArea();\n\n  // The size here must match the window dimensions to avoid unnecessary surface\n  // creation / destruction in the startup path.\n  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(\n      frame.right - frame.left, frame.bottom - frame.top, project_);\n  // Ensure that basic setup of the controller was successful.\n  if (!flutter_controller_->engine() || !flutter_controller_->view()) {\n    return false;\n  }\n  RegisterPlugins(flutter_controller_->engine());\n  SetChildContent(flutter_controller_->view()->GetNativeWindow());\n\n  flutter_controller_->engine()->SetNextFrameCallback([&]() {\n    this->Show();\n  });\n\n  // Flutter can complete the first frame before the \"show window\" callback is\n  // registered. The following call ensures a frame is pending to ensure the\n  // window is shown. It is a no-op if the first frame hasn't completed yet.\n  flutter_controller_->ForceRedraw();\n\n  return true;\n}\n\nvoid FlutterWindow::OnDestroy() {\n  if (flutter_controller_) {\n    flutter_controller_ = nullptr;\n  }\n\n  Win32Window::OnDestroy();\n}\n\nLRESULT\nFlutterWindow::MessageHandler(HWND hwnd, UINT const message,\n                              WPARAM const wparam,\n                              LPARAM const lparam) noexcept {\n  // Give Flutter, including plugins, an opportunity to handle window messages.\n  if (flutter_controller_) {\n    std::optional<LRESULT> result =\n        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,\n                                                      lparam);\n    if (result) {\n      return *result;\n    }\n  }\n\n  switch (message) {\n    case WM_FONTCHANGE:\n      flutter_controller_->engine()->ReloadSystemFonts();\n      break;\n  }\n\n  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);\n}\n"
  },
  {
    "path": "simple_live_app/windows/runner/flutter_window.h",
    "content": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n\n#include <memory>\n\n#include \"win32_window.h\"\n\n// A window that does nothing but host a Flutter view.\nclass FlutterWindow : public Win32Window {\n public:\n  // Creates a new FlutterWindow hosting a Flutter view running |project|.\n  explicit FlutterWindow(const flutter::DartProject& project);\n  virtual ~FlutterWindow();\n\n protected:\n  // Win32Window:\n  bool OnCreate() override;\n  void OnDestroy() override;\n  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,\n                         LPARAM const lparam) noexcept override;\n\n private:\n  // The project to run.\n  flutter::DartProject project_;\n\n  // The Flutter instance hosted by this window.\n  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;\n};\n\n#endif  // RUNNER_FLUTTER_WINDOW_H_\n"
  },
  {
    "path": "simple_live_app/windows/runner/main.cpp",
    "content": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_window.h\"\n#include \"utils.h\"\n\nint APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,\n                      _In_ wchar_t *command_line, _In_ int show_command) {\n  HWND hwnd = ::FindWindow(NULL, L\"Slive\");\n  if (hwnd != NULL) {\n    ::ShowWindow(hwnd, SW_NORMAL);\n    ::SetForegroundWindow(hwnd);\n    return EXIT_FAILURE;\n  }\n\n  // Attach to console when present (e.g., 'flutter run') or create a\n  // new console when running with a debugger.\n  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {\n    CreateAndAttachConsole();\n  }\n\n  // Initialize COM, so that it is available for use in the library and/or\n  // plugins.\n  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);\n\n  flutter::DartProject project(L\"data\");\n\n  std::vector<std::string> command_line_arguments =\n      GetCommandLineArguments();\n\n  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));\n\n  FlutterWindow window(project);\n  Win32Window::Point origin(10, 10);\n  Win32Window::Size size(1280, 720);\n  if (!window.Create(L\"Slive\", origin, size)) {\n    return EXIT_FAILURE;\n  }\n  window.SetQuitOnClose(true);\n\n  ::MSG msg;\n  while (::GetMessage(&msg, nullptr, 0, 0)) {\n    ::TranslateMessage(&msg);\n    ::DispatchMessage(&msg);\n  }\n\n  ::CoUninitialize();\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "simple_live_app/windows/runner/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Runner.rc\n//\n#define IDI_APP_ICON                    101\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "simple_live_app/windows/runner/runner.exe.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2</dpiAwareness>\n    </windowsSettings>\n  </application>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <!-- Windows 10 and Windows 11 -->\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n      <!-- Windows 8.1 -->\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <!-- Windows 8 -->\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <!-- Windows 7 -->\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n    </application>\n  </compatibility>\n</assembly>\n"
  },
  {
    "path": "simple_live_app/windows/runner/utils.cpp",
    "content": "#include \"utils.h\"\n\n#include <flutter_windows.h>\n#include <io.h>\n#include <stdio.h>\n#include <windows.h>\n\n#include <iostream>\n\nvoid CreateAndAttachConsole() {\n  if (::AllocConsole()) {\n    FILE *unused;\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stdout)) {\n      _dup2(_fileno(stdout), 1);\n    }\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stderr)) {\n      _dup2(_fileno(stdout), 2);\n    }\n    std::ios::sync_with_stdio();\n    FlutterDesktopResyncOutputStreams();\n  }\n}\n\nstd::vector<std::string> GetCommandLineArguments() {\n  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.\n  int argc;\n  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);\n  if (argv == nullptr) {\n    return std::vector<std::string>();\n  }\n\n  std::vector<std::string> command_line_arguments;\n\n  // Skip the first argument as it's the binary name.\n  for (int i = 1; i < argc; i++) {\n    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));\n  }\n\n  ::LocalFree(argv);\n\n  return command_line_arguments;\n}\n\nstd::string Utf8FromUtf16(const wchar_t* utf16_string) {\n  if (utf16_string == nullptr) {\n    return std::string();\n  }\n  int target_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, nullptr, 0, nullptr, nullptr)\n    -1; // remove the trailing null character\n  int input_length = (int)wcslen(utf16_string);\n  std::string utf8_string;\n  if (target_length <= 0 || target_length > utf8_string.max_size()) {\n    return utf8_string;\n  }\n  utf8_string.resize(target_length);\n  int converted_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      input_length, utf8_string.data(), target_length, nullptr, nullptr);\n  if (converted_length == 0) {\n    return std::string();\n  }\n  return utf8_string;\n}\n"
  },
  {
    "path": "simple_live_app/windows/runner/utils.h",
    "content": "#ifndef RUNNER_UTILS_H_\n#define RUNNER_UTILS_H_\n\n#include <string>\n#include <vector>\n\n// Creates a console for the process, and redirects stdout and stderr to\n// it for both the runner and the Flutter library.\nvoid CreateAndAttachConsole();\n\n// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string\n// encoded in UTF-8. Returns an empty std::string on failure.\nstd::string Utf8FromUtf16(const wchar_t* utf16_string);\n\n// Gets the command line arguments passed in as a std::vector<std::string>,\n// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.\nstd::vector<std::string> GetCommandLineArguments();\n\n#endif  // RUNNER_UTILS_H_\n"
  },
  {
    "path": "simple_live_app/windows/runner/win32_window.cpp",
    "content": "#include \"win32_window.h\"\n\n#include <dwmapi.h>\n#include <flutter_windows.h>\n\n#include \"resource.h\"\n\nnamespace {\n\n/// Window attribute that enables dark mode window decorations.\n///\n/// Redefined in case the developer's machine has a Windows SDK older than\n/// version 10.0.22000.0.\n/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute\n#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE\n#define DWMWA_USE_IMMERSIVE_DARK_MODE 20\n#endif\n\nconstexpr const wchar_t kWindowClassName[] = L\"FLUTTER_RUNNER_WIN32_WINDOW\";\n\n/// Registry key for app theme preference.\n///\n/// A value of 0 indicates apps should use dark mode. A non-zero or missing\n/// value indicates apps should use light mode.\nconstexpr const wchar_t kGetPreferredBrightnessRegKey[] =\n  L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Themes\\\\Personalize\";\nconstexpr const wchar_t kGetPreferredBrightnessRegValue[] = L\"AppsUseLightTheme\";\n\n// The number of Win32Window objects that currently exist.\nstatic int g_active_window_count = 0;\n\nusing EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);\n\n// Scale helper to convert logical scaler values to physical using passed in\n// scale factor\nint Scale(int source, double scale_factor) {\n  return static_cast<int>(source * scale_factor);\n}\n\n// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.\n// This API is only needed for PerMonitor V1 awareness mode.\nvoid EnableFullDpiSupportIfAvailable(HWND hwnd) {\n  HMODULE user32_module = LoadLibraryA(\"User32.dll\");\n  if (!user32_module) {\n    return;\n  }\n  auto enable_non_client_dpi_scaling =\n      reinterpret_cast<EnableNonClientDpiScaling*>(\n          GetProcAddress(user32_module, \"EnableNonClientDpiScaling\"));\n  if (enable_non_client_dpi_scaling != nullptr) {\n    enable_non_client_dpi_scaling(hwnd);\n  }\n  FreeLibrary(user32_module);\n}\n\n}  // namespace\n\n// Manages the Win32Window's window class registration.\nclass WindowClassRegistrar {\n public:\n  ~WindowClassRegistrar() = default;\n\n  // Returns the singleton registrar instance.\n  static WindowClassRegistrar* GetInstance() {\n    if (!instance_) {\n      instance_ = new WindowClassRegistrar();\n    }\n    return instance_;\n  }\n\n  // Returns the name of the window class, registering the class if it hasn't\n  // previously been registered.\n  const wchar_t* GetWindowClass();\n\n  // Unregisters the window class. Should only be called if there are no\n  // instances of the window.\n  void UnregisterWindowClass();\n\n private:\n  WindowClassRegistrar() = default;\n\n  static WindowClassRegistrar* instance_;\n\n  bool class_registered_ = false;\n};\n\nWindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;\n\nconst wchar_t* WindowClassRegistrar::GetWindowClass() {\n  if (!class_registered_) {\n    WNDCLASS window_class{};\n    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);\n    window_class.lpszClassName = kWindowClassName;\n    window_class.style = CS_HREDRAW | CS_VREDRAW;\n    window_class.cbClsExtra = 0;\n    window_class.cbWndExtra = 0;\n    window_class.hInstance = GetModuleHandle(nullptr);\n    window_class.hIcon =\n        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));\n    window_class.hbrBackground = 0;\n    window_class.lpszMenuName = nullptr;\n    window_class.lpfnWndProc = Win32Window::WndProc;\n    RegisterClass(&window_class);\n    class_registered_ = true;\n  }\n  return kWindowClassName;\n}\n\nvoid WindowClassRegistrar::UnregisterWindowClass() {\n  UnregisterClass(kWindowClassName, nullptr);\n  class_registered_ = false;\n}\n\nWin32Window::Win32Window() {\n  ++g_active_window_count;\n}\n\nWin32Window::~Win32Window() {\n  --g_active_window_count;\n  Destroy();\n}\n\nbool Win32Window::Create(const std::wstring& title,\n                         const Point& origin,\n                         const Size& size) {\n  Destroy();\n\n  const wchar_t* window_class =\n      WindowClassRegistrar::GetInstance()->GetWindowClass();\n\n  const POINT target_point = {static_cast<LONG>(origin.x),\n                              static_cast<LONG>(origin.y)};\n  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);\n  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);\n  double scale_factor = dpi / 96.0;\n\n  HWND window = CreateWindow(\n      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,\n      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),\n      Scale(size.width, scale_factor), Scale(size.height, scale_factor),\n      nullptr, nullptr, GetModuleHandle(nullptr), this);\n\n  if (!window) {\n    return false;\n  }\n\n  UpdateTheme(window);\n\n  return OnCreate();\n}\n\nbool Win32Window::Show() {\n  return ShowWindow(window_handle_, SW_SHOWNORMAL);\n}\n\n// static\nLRESULT CALLBACK Win32Window::WndProc(HWND const window,\n                                      UINT const message,\n                                      WPARAM const wparam,\n                                      LPARAM const lparam) noexcept {\n  if (message == WM_NCCREATE) {\n    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);\n    SetWindowLongPtr(window, GWLP_USERDATA,\n                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));\n\n    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);\n    EnableFullDpiSupportIfAvailable(window);\n    that->window_handle_ = window;\n  } else if (Win32Window* that = GetThisFromHandle(window)) {\n    return that->MessageHandler(window, message, wparam, lparam);\n  }\n\n  return DefWindowProc(window, message, wparam, lparam);\n}\n\nLRESULT\nWin32Window::MessageHandler(HWND hwnd,\n                            UINT const message,\n                            WPARAM const wparam,\n                            LPARAM const lparam) noexcept {\n  switch (message) {\n    case WM_DESTROY:\n      window_handle_ = nullptr;\n      Destroy();\n      if (quit_on_close_) {\n        PostQuitMessage(0);\n      }\n      return 0;\n\n    case WM_DPICHANGED: {\n      auto newRectSize = reinterpret_cast<RECT*>(lparam);\n      LONG newWidth = newRectSize->right - newRectSize->left;\n      LONG newHeight = newRectSize->bottom - newRectSize->top;\n\n      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,\n                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);\n\n      return 0;\n    }\n    case WM_SIZE: {\n      RECT rect = GetClientArea();\n      if (child_content_ != nullptr) {\n        // Size and position the child window.\n        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,\n                   rect.bottom - rect.top, TRUE);\n      }\n      return 0;\n    }\n\n    case WM_ACTIVATE:\n      if (child_content_ != nullptr) {\n        SetFocus(child_content_);\n      }\n      return 0;\n\n    case WM_DWMCOLORIZATIONCOLORCHANGED:\n      UpdateTheme(hwnd);\n      return 0;\n  }\n\n  return DefWindowProc(window_handle_, message, wparam, lparam);\n}\n\nvoid Win32Window::Destroy() {\n  OnDestroy();\n\n  if (window_handle_) {\n    DestroyWindow(window_handle_);\n    window_handle_ = nullptr;\n  }\n  if (g_active_window_count == 0) {\n    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();\n  }\n}\n\nWin32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {\n  return reinterpret_cast<Win32Window*>(\n      GetWindowLongPtr(window, GWLP_USERDATA));\n}\n\nvoid Win32Window::SetChildContent(HWND content) {\n  child_content_ = content;\n  SetParent(content, window_handle_);\n  RECT frame = GetClientArea();\n\n  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,\n             frame.bottom - frame.top, true);\n\n  SetFocus(child_content_);\n}\n\nRECT Win32Window::GetClientArea() {\n  RECT frame;\n  GetClientRect(window_handle_, &frame);\n  return frame;\n}\n\nHWND Win32Window::GetHandle() {\n  return window_handle_;\n}\n\nvoid Win32Window::SetQuitOnClose(bool quit_on_close) {\n  quit_on_close_ = quit_on_close;\n}\n\nbool Win32Window::OnCreate() {\n  // No-op; provided for subclasses.\n  return true;\n}\n\nvoid Win32Window::OnDestroy() {\n  // No-op; provided for subclasses.\n}\n\nvoid Win32Window::UpdateTheme(HWND const window) {\n  DWORD light_mode;\n  DWORD light_mode_size = sizeof(light_mode);\n  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,\n                               kGetPreferredBrightnessRegValue,\n                               RRF_RT_REG_DWORD, nullptr, &light_mode,\n                               &light_mode_size);\n\n  if (result == ERROR_SUCCESS) {\n    BOOL enable_dark_mode = light_mode == 0;\n    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,\n                          &enable_dark_mode, sizeof(enable_dark_mode));\n  }\n}\n"
  },
  {
    "path": "simple_live_app/windows/runner/win32_window.h",
    "content": "#ifndef RUNNER_WIN32_WINDOW_H_\n#define RUNNER_WIN32_WINDOW_H_\n\n#include <windows.h>\n\n#include <functional>\n#include <memory>\n#include <string>\n\n// A class abstraction for a high DPI-aware Win32 Window. Intended to be\n// inherited from by classes that wish to specialize with custom\n// rendering and input handling\nclass Win32Window {\n public:\n  struct Point {\n    unsigned int x;\n    unsigned int y;\n    Point(unsigned int x, unsigned int y) : x(x), y(y) {}\n  };\n\n  struct Size {\n    unsigned int width;\n    unsigned int height;\n    Size(unsigned int width, unsigned int height)\n        : width(width), height(height) {}\n  };\n\n  Win32Window();\n  virtual ~Win32Window();\n\n  // Creates a win32 window with |title| that is positioned and sized using\n  // |origin| and |size|. New windows are created on the default monitor. Window\n  // sizes are specified to the OS in physical pixels, hence to ensure a\n  // consistent size this function will scale the inputted width and height as\n  // as appropriate for the default monitor. The window is invisible until\n  // |Show| is called. Returns true if the window was created successfully.\n  bool Create(const std::wstring& title, const Point& origin, const Size& size);\n\n  // Show the current window. Returns true if the window was successfully shown.\n  bool Show();\n\n  // Release OS resources associated with window.\n  void Destroy();\n\n  // Inserts |content| into the window tree.\n  void SetChildContent(HWND content);\n\n  // Returns the backing Window handle to enable clients to set icon and other\n  // window properties. Returns nullptr if the window has been destroyed.\n  HWND GetHandle();\n\n  // If true, closing this window will quit the application.\n  void SetQuitOnClose(bool quit_on_close);\n\n  // Return a RECT representing the bounds of the current client area.\n  RECT GetClientArea();\n\n protected:\n  // Processes and route salient window messages for mouse handling,\n  // size change and DPI. Delegates handling of these to member overloads that\n  // inheriting classes can handle.\n  virtual LRESULT MessageHandler(HWND window,\n                                 UINT const message,\n                                 WPARAM const wparam,\n                                 LPARAM const lparam) noexcept;\n\n  // Called when CreateAndShow is called, allowing subclass window-related\n  // setup. Subclasses should return false if setup fails.\n  virtual bool OnCreate();\n\n  // Called when Destroy is called.\n  virtual void OnDestroy();\n\n private:\n  friend class WindowClassRegistrar;\n\n  // OS callback called by message pump. Handles the WM_NCCREATE message which\n  // is passed when the non-client area is being created and enables automatic\n  // non-client DPI scaling so that the non-client area automatically\n  // responds to changes in DPI. All other messages are handled by\n  // MessageHandler.\n  static LRESULT CALLBACK WndProc(HWND const window,\n                                  UINT const message,\n                                  WPARAM const wparam,\n                                  LPARAM const lparam) noexcept;\n\n  // Retrieves a class instance pointer for |window|\n  static Win32Window* GetThisFromHandle(HWND const window) noexcept;\n\n  // Update the window frame's theme to match the system theme.\n  static void UpdateTheme(HWND const window);\n\n  bool quit_on_close_ = false;\n\n  // window handle for top level window.\n  HWND window_handle_ = nullptr;\n\n  // window handle for hosted content.\n  HWND child_content_ = nullptr;\n};\n\n#endif  // RUNNER_WIN32_WINDOW_H_\n"
  },
  {
    "path": "simple_live_console/.fvmrc",
    "content": "{\n  \"flutter\": \"3.35.7\"\n}\n"
  },
  {
    "path": "simple_live_console/.gitignore",
    "content": "# https://dart.dev/guides/libraries/private-files\n# Created by `dart pub`\n.dart_tool/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n"
  },
  {
    "path": "simple_live_console/CHANGELOG.md",
    "content": "## 1.0.0\n\n- Initial version.\n"
  },
  {
    "path": "simple_live_console/README.md",
    "content": "# simple_live_console\n\n基于simple_live_core的控制台程序。\n\n输入直播间播放直链获取信息及播放地址：\n\n```\nsimple_live.exe -i [URL]\n```\n\n输入直播间链接获取弹幕：\n\n```\nsimple_live.exe -d [URL]\n```"
  },
  {
    "path": "simple_live_console/analysis_options.yaml",
    "content": "# This file configures the static analysis results for your project (errors,\n# warnings, and lints).\n#\n# This enables the 'recommended' set of lints from `package:lints`.\n# This set helps identify many issues that may lead to problems when running\n# or consuming Dart code, and enforces writing Dart using a single, idiomatic\n# style and format.\n#\n# If you want a smaller set of lints you can change this to specify\n# 'package:lints/core.yaml'. These are just the most critical lints\n# (the recommended set includes the core lints).\n# The core lints are also what is used by pub.dev for scoring packages.\n\ninclude: package:lints/recommended.yaml\n\n# Uncomment the following section to specify additional rules.\n\n# linter:\n#   rules:\n#     - camel_case_types\n\n# analyzer:\n#   exclude:\n#     - path/to/excluded/files/**\n\n# For more information about the core and recommended set of lints, see\n# https://dart.dev/go/core-lints\n\n# For additional information about configuring this file, see\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_console/bin/simple_live_console.dart",
    "content": "import 'dart:io';\n\nimport 'package:simple_live_core/simple_live_core.dart';\n\nvoid main(List<String> arguments) async {\n  CoreLog.enableLog = false;\n  if (arguments.isEmpty) {\n    printHelp();\n    return;\n  }\n\n  var action = arguments.first.toLowerCase().replaceAll(\"-\", \"\");\n  if (arguments.length < 2) {\n    print(\"错误的参数\");\n    printHelp();\n    return;\n  }\n  var url = arguments[1];\n  if (url.isEmpty) {\n    print(\"[URL]不能为空\");\n    printHelp();\n    return;\n  }\n  if (action == \"i\") {\n    await printInfo(url);\n  } else if (action == \"d\") {\n    printDanmaku(url);\n  } else if (action == \"h\") {\n    printHelp();\n  } else {\n    print(\"未知指令:$action\");\n    printHelp();\n  }\n}\n\nvoid printHelp() {\n  print(\"-i [URL] ：获取直播间信息及播放直链\");\n  print(\"-d [URL] ：持续输出直播间弹幕\");\n}\n\nFuture printInfo(String url) async {\n  var urlInfo = parseUrl(url);\n  LiveSite site = urlInfo.first;\n  var id = urlInfo.last;\n  var detail = await site.getRoomDetail(roomId: id);\n  print(\"来源：${site.name}\");\n  print(\"房间号：${detail.roomId}\");\n  print(\"房间标题：${detail.title}\");\n  print(\"直播用户：${detail.userName}\");\n  print(\"人气值：${detail.online}\");\n  print(\"状态：${(detail.status ? \"直播中\" : \"未开播\")}\");\n  if (detail.status) {\n    print(\"可用清晰度：\");\n    var quality = await site.getPlayQualites(detail: detail);\n\n    for (int i = 0; i < quality.length; i++) {\n      print(\"【${i + 1}】${quality[i].quality}\");\n    }\n    print(\"请输入【】内数字，获取对应清晰度的直链\");\n    var input = stdin.readLineSync() ?? \"\";\n    print(\"正在获取直链...\");\n    var index = int.tryParse(input) ?? 0;\n    if (index > 0) {\n      var url =\n          await site.getPlayUrls(detail: detail, quality: quality[index - 1]);\n      for (int i = 0; i < url.urls.length; i++) {\n        print(\"线路${i + 1}:\\r\\n${url.urls[i]}\");\n      }\n    }\n  }\n}\n\nFuture printDanmaku(String url) async {\n  var urlInfo = parseUrl(url);\n  LiveSite site = urlInfo.first;\n  var id = urlInfo.last;\n  var detail = await site.getRoomDetail(roomId: id);\n  print(\"来源：${site.name}\");\n  print(\"房间号：${detail.roomId}\");\n  print(\"房间标题：${detail.title}\");\n  print(\"直播用户：${detail.userName}\");\n  print(\"状态：${(detail.status ? \"直播中\" : \"未开播\")}\");\n  var danmaku = site.getDanmaku();\n  danmaku.onMessage = (LiveMessage e) {\n    if (e.type == LiveMessageType.online) {\n      print(\"-----人气值：${e.data}-----\");\n    } else if (e.type == LiveMessageType.chat) {\n      print(\"${e.userName}：${e.message}\");\n    }\n  };\n  danmaku.onClose = (String e) {\n    print(e);\n  };\n\n  print(\"【开始获取弹幕】\");\n  await danmaku.start(detail.danmakuData);\n  await Future(() {});\n}\n\nList parseUrl(String url) {\n  if (url.contains(\"bilibili.com\")) {\n    var id =\n        RegExp(r\"bilibili\\.com/([\\d|\\w]+)\").firstMatch(url)?.group(1) ?? \"\";\n    return [BiliBiliSite(), id];\n  }\n  if (url.contains(\"huya.com\")) {\n    var id = RegExp(r\"huya\\.com/([\\d|\\w]+)\").firstMatch(url)?.group(1) ?? \"\";\n    return [HuyaSite(), id];\n  }\n  if (url.contains(\"douyu.com\")) {\n    var id = RegExp(r\"douyu\\.com/([\\d|\\w]+)\").firstMatch(url)?.group(1) ?? \"\";\n    return [DouyuSite(), id];\n  }\n  if (url.contains(\"live.douyin.com\")) {\n    var id =\n        RegExp(r\"live\\.douyin\\.com/([\\d|\\w]+)\").firstMatch(url)?.group(1) ?? \"\";\n    return [DouyinSite(), id];\n  }\n  throw Exception(\"链接解析失败\");\n}\n"
  },
  {
    "path": "simple_live_console/pubspec.yaml",
    "content": "name: simple_live_console\ndescription: A sample command-line application.\nversion: 1.0.0\npublish_to: \"none\"\n# repository: https://github.com/my_org/my_repo\n\nenvironment:\n  sdk: '>=2.19.1 <3.0.0'\n\ndependencies:\n  simple_live_core:\n    path: ../simple_live_core\n\ndev_dependencies:\n  lints: ^6.0.0\n  test: ^1.21.0\n"
  },
  {
    "path": "simple_live_console/test/all_live_console_test.dart",
    "content": "import 'package:test/test.dart';\n\nvoid main() {\n  test('calculate', () {});\n}\n"
  },
  {
    "path": "simple_live_core/.fvmrc",
    "content": "{\n  \"flutter\": \"3.38.4\"\n}\n"
  },
  {
    "path": "simple_live_core/.gitattributes",
    "content": "﻿* text=auto eol=lf"
  },
  {
    "path": "simple_live_core/.gitignore",
    "content": "# https://dart.dev/guides/libraries/private-files\n# Created by `dart pub`\n.dart_tool/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n"
  },
  {
    "path": "simple_live_core/CHANGELOG.md",
    "content": "## 1.0.0\n\n- Initial version.\n"
  },
  {
    "path": "simple_live_core/README.md",
    "content": "# simple_live_core\n\n项目核心库，实现获取各个网站的信息及弹幕。\n"
  },
  {
    "path": "simple_live_core/analysis_options.yaml",
    "content": "# This file configures the static analysis results for your project (errors,\n# warnings, and lints).\n#\n# This enables the 'recommended' set of lints from `package:lints`.\n# This set helps identify many issues that may lead to problems when running\n# or consuming Dart code, and enforces writing Dart using a single, idiomatic\n# style and format.\n#\n# If you want a smaller set of lints you can change this to specify\n# 'package:lints/core.yaml'. These are just the most critical lints\n# (the recommended set includes the core lints).\n# The core lints are also what is used by pub.dev for scoring packages.\n\ninclude: package:lints/recommended.yaml\n\n# Uncomment the following section to specify additional rules.\n\nlinter:\n  rules:\n    constant_identifier_names: false\n\n# analyzer:\n#   exclude:\n#     - path/to/excluded/files/**\n\n# For more information about the core and recommended set of lints, see\n# https://dart.dev/go/core-lints\n\n# For additional information about configuring this file, see\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_core/assets/js/a_bogus.js",
    "content": "// All the content in this article is only for learning and communication use, not for any other purpose, strictly prohibited for commercial use and illegal use, otherwise all the consequences are irrelevant to the author!\nfunction rc4_encrypt(plaintext, key) {\n    var s = [];\n    for (var i = 0; i < 256; i++) {\n        s[i] = i;\n    }\n    var j = 0;\n    for (var i = 0; i < 256; i++) {\n        j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;\n        var temp = s[i];\n        s[i] = s[j];\n        s[j] = temp;\n    }\n\n    var i = 0;\n    var j = 0;\n    var cipher = [];\n    for (var k = 0; k < plaintext.length; k++) {\n        i = (i + 1) % 256;\n        j = (j + s[i]) % 256;\n        var temp = s[i];\n        s[i] = s[j];\n        s[j] = temp;\n        var t = (s[i] + s[j]) % 256;\n        cipher.push(String.fromCharCode(s[t] ^ plaintext.charCodeAt(k)));\n    }\n    return cipher.join('');\n}\n\nfunction le(e, r) {\n    return (e << (r %= 32) | e >>> 32 - r) >>> 0\n}\n\nfunction de(e) {\n    return 0 <= e && e < 16 ? 2043430169 : 16 <= e && e < 64 ? 2055708042 : void console['error'](\"invalid j for constant Tj\")\n}\n\nfunction pe(e, r, t, n) {\n    return 0 <= e && e < 16 ? (r ^ t ^ n) >>> 0 : 16 <= e && e < 64 ? (r & t | r & n | t & n) >>> 0 : (console['error']('invalid j for bool function FF'),\n        0)\n}\n\nfunction he(e, r, t, n) {\n    return 0 <= e && e < 16 ? (r ^ t ^ n) >>> 0 : 16 <= e && e < 64 ? (r & t | ~r & n) >>> 0 : (console['error']('invalid j for bool function GG'),\n        0)\n}\n\nfunction reset() {\n    this.reg[0] = 1937774191,\n        this.reg[1] = 1226093241,\n        this.reg[2] = 388252375,\n        this.reg[3] = 3666478592,\n        this.reg[4] = 2842636476,\n        this.reg[5] = 372324522,\n        this.reg[6] = 3817729613,\n        this.reg[7] = 2969243214,\n        this[\"chunk\"] = [],\n        this[\"size\"] = 0\n}\n\nfunction write(e) {\n    var a = \"string\" == typeof e ? function (e) {\n        n = encodeURIComponent(e)['replace'](/%([0-9A-F]{2})/g, (function (e, r) {\n                return String['fromCharCode'](\"0x\" + r)\n            }\n        ))\n            , a = new Array(n['length']);\n        return Array['prototype']['forEach']['call'](n, (function (e, r) {\n                a[r] = e.charCodeAt(0)\n            }\n        )),\n            a\n    }(e) : e;\n    this.size += a.length;\n    var f = 64 - this['chunk']['length'];\n    if (a['length'] < f)\n        this['chunk'] = this['chunk'].concat(a);\n    else\n        for (this['chunk'] = this['chunk'].concat(a.slice(0, f)); this['chunk'].length >= 64;)\n            this['_compress'](this['chunk']),\n                f < a['length'] ? this['chunk'] = a['slice'](f, Math['min'](f + 64, a['length'])) : this['chunk'] = [],\n                f += 64\n}\n\nfunction sum(e, t) {\n    e && (this['reset'](),\n        this['write'](e)),\n        this['_fill']();\n    for (var f = 0; f < this.chunk['length']; f += 64)\n        this._compress(this['chunk']['slice'](f, f + 64));\n    var i = null;\n    if (t == 'hex') {\n        i = \"\";\n        for (f = 0; f < 8; f++)\n            i += se(this['reg'][f]['toString'](16), 8, \"0\")\n    } else\n        for (i = new Array(32),\n                 f = 0; f < 8; f++) {\n            var c = this.reg[f];\n            i[4 * f + 3] = (255 & c) >>> 0,\n                c >>>= 8,\n                i[4 * f + 2] = (255 & c) >>> 0,\n                c >>>= 8,\n                i[4 * f + 1] = (255 & c) >>> 0,\n                c >>>= 8,\n                i[4 * f] = (255 & c) >>> 0\n        }\n    return this['reset'](),\n        i\n}\n\nfunction _compress(t) {\n    if (t < 64)\n        console.error(\"compress error: not enough data\");\n    else {\n        for (var f = function (e) {\n            for (var r = new Array(132), t = 0; t < 16; t++)\n                r[t] = e[4 * t] << 24,\n                    r[t] |= e[4 * t + 1] << 16,\n                    r[t] |= e[4 * t + 2] << 8,\n                    r[t] |= e[4 * t + 3],\n                    r[t] >>>= 0;\n            for (var n = 16; n < 68; n++) {\n                var a = r[n - 16] ^ r[n - 9] ^ le(r[n - 3], 15);\n                a = a ^ le(a, 15) ^ le(a, 23),\n                    r[n] = (a ^ le(r[n - 13], 7) ^ r[n - 6]) >>> 0\n            }\n            for (n = 0; n < 64; n++)\n                r[n + 68] = (r[n] ^ r[n + 4]) >>> 0;\n            return r\n        }(t), i = this['reg'].slice(0), c = 0; c < 64; c++) {\n            var o = le(i[0], 12) + i[4] + le(de(c), c)\n                , s = ((o = le(o = (4294967295 & o) >>> 0, 7)) ^ le(i[0], 12)) >>> 0\n                , u = pe(c, i[0], i[1], i[2]);\n            u = (4294967295 & (u = u + i[3] + s + f[c + 68])) >>> 0;\n            var b = he(c, i[4], i[5], i[6]);\n            b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0,\n                i[3] = i[2],\n                i[2] = le(i[1], 9),\n                i[1] = i[0],\n                i[0] = u,\n                i[7] = i[6],\n                i[6] = le(i[5], 19),\n                i[5] = i[4],\n                i[4] = (b ^ le(b, 9) ^ le(b, 17)) >>> 0\n        }\n        for (var l = 0; l < 8; l++)\n            this['reg'][l] = (this['reg'][l] ^ i[l]) >>> 0\n    }\n}\n\nfunction _fill() {\n    var a = 8 * this['size']\n        , f = this['chunk']['push'](128) % 64;\n    for (64 - f < 8 && (f -= 64); f < 56; f++)\n        this.chunk['push'](0);\n    for (var i = 0; i < 4; i++) {\n        var c = Math['floor'](a / 4294967296);\n        this['chunk'].push(c >>> 8 * (3 - i) & 255)\n    }\n    for (i = 0; i < 4; i++)\n        this['chunk']['push'](a >>> 8 * (3 - i) & 255)\n\n}\n\nfunction SM3() {\n    this.reg = [];\n    this.chunk = [];\n    this.size = 0;\n    this.reset()\n}\nSM3.prototype.reset = reset;\nSM3.prototype.write = write;\nSM3.prototype.sum = sum;\nSM3.prototype._compress = _compress;\nSM3.prototype._fill = _fill;\n\nfunction result_encrypt(long_str, num = null) {\n    let s_obj = {\n        \"s0\": \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",\n        \"s1\": \"Dkdpgh4ZKsQB80/Mfvw36XI1R25+WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=\",\n        \"s2\": \"Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=\",\n        \"s3\": \"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe\",\n        \"s4\": \"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe\"\n    }\n    let constant = {\n        \"0\": 16515072,\n        \"1\": 258048,\n        \"2\": 4032,\n        \"str\": s_obj[num],\n    }\n\n    let result = \"\";\n    let lound = 0;\n    let long_int = get_long_int(lound, long_str);\n    for (let i = 0; i < long_str.length / 3 * 4; i++) {\n        if (Math.floor(i / 4) !== lound) {\n            lound += 1;\n            long_int = get_long_int(lound, long_str);\n        }\n        let key = i % 4;\n        switch (key) {\n            case 0:\n                temp_int = (long_int & constant[\"0\"]) >> 18;\n                result += constant[\"str\"].charAt(temp_int);\n                break;\n            case 1:\n                temp_int = (long_int & constant[\"1\"]) >> 12;\n                result += constant[\"str\"].charAt(temp_int);\n                break;\n            case 2:\n                temp_int = (long_int & constant[\"2\"]) >> 6;\n                result += constant[\"str\"].charAt(temp_int);\n                break;\n            case 3:\n                temp_int = long_int & 63;\n                result += constant[\"str\"].charAt(temp_int);\n                break;\n            default:\n                break;\n        }\n    }\n    return result;\n}\n\nfunction get_long_int(round, long_str) {\n    round = round * 3;\n    return (long_str.charCodeAt(round) << 16) | (long_str.charCodeAt(round + 1) << 8) | (long_str.charCodeAt(round + 2));\n}\n\nfunction gener_random(random, option) {\n    return [\n        (random & 255 & 170) | option[0] & 85, // 163\n        (random & 255 & 85) | option[0] & 170, //87\n        (random >> 8 & 255 & 170) | option[1] & 85, //37\n        (random >> 8 & 255 & 85) | option[1] & 170, //41\n    ]\n}\n\n//////////////////////////////////////////////\nfunction generate_rc4_bb_str(url_search_params, user_agent, window_env_str, suffix = \"cus\", Arguments = [0, 1, 14]) {\n    let sm3 = new SM3()\n    let start_time = Date.now()\n    /**\n     * 进行3次加密处理\n     * 1: url_search_params两次sm3之的结果\n     * 2: 对后缀两次sm3之的结果\n     * 3: 对ua处理之后的结果\n     */\n        // url_search_params两次sm3之的结果\n    let url_search_params_list = sm3.sum(sm3.sum(url_search_params + suffix))\n    // 对后缀两次sm3之的结果\n    let cus = sm3.sum(sm3.sum(suffix))\n    // 对ua处理之后的结果\n    let ua = sm3.sum(result_encrypt(rc4_encrypt(user_agent, String.fromCharCode.apply(null, [0.00390625, 1, 14])), \"s3\"))\n    //\n    let end_time = Date.now()\n    // b\n    let b = {\n        8: 3, // 固定\n        10: end_time, //3次加密结束时间\n        15: {\n            \"aid\": 6383,\n            \"pageId\": 6241,\n            \"boe\": false,\n            \"ddrt\": 7,\n            \"paths\": {\n                \"include\": [\n                    {},\n                    {},\n                    {},\n                    {},\n                    {},\n                    {},\n                    {}\n                ],\n                \"exclude\": []\n            },\n            \"track\": {\n                \"mode\": 0,\n                \"delay\": 300,\n                \"paths\": []\n            },\n            \"dump\": true,\n            \"rpU\": \"\"\n        },\n        16: start_time, //3次加密开始时间\n        18: 44, //固定\n        19: [1, 0, 1, 5],\n    }\n\n    //3次加密开始时间\n    b[20] = (b[16] >> 24) & 255\n    b[21] = (b[16] >> 16) & 255\n    b[22] = (b[16] >> 8) & 255\n    b[23] = b[16] & 255\n    b[24] = (b[16] / 256 / 256 / 256 / 256) >> 0\n    b[25] = (b[16] / 256 / 256 / 256 / 256 / 256) >> 0\n\n    // 参数Arguments [0, 1, 14, ...]\n    // let Arguments = [0, 1, 14]\n    b[26] = (Arguments[0] >> 24) & 255\n    b[27] = (Arguments[0] >> 16) & 255\n    b[28] = (Arguments[0] >> 8) & 255\n    b[29] = Arguments[0] & 255\n\n    b[30] = (Arguments[1] / 256) & 255\n    b[31] = (Arguments[1] % 256) & 255\n    b[32] = (Arguments[1] >> 24) & 255\n    b[33] = (Arguments[1] >> 16) & 255\n\n    b[34] = (Arguments[2] >> 24) & 255\n    b[35] = (Arguments[2] >> 16) & 255\n    b[36] = (Arguments[2] >> 8) & 255\n    b[37] = Arguments[2] & 255\n\n    // (url_search_params + \"cus\") 两次sm3之的结果\n    /**let url_search_params_list = [\n     91, 186,  35,  86, 143, 253,   6,  76,\n     34,  21, 167, 148,   7,  42, 192, 219,\n     188,  20, 182,  85, 213,  74, 213, 147,\n     37, 155,  93, 139,  85, 118, 228, 213\n     ]*/\n    b[38] = url_search_params_list[21]\n    b[39] = url_search_params_list[22]\n\n    // (\"cus\") 对后缀两次sm3之的结果\n    /**\n     * let cus = [\n     136, 101, 114, 147,  58,  77, 207, 201,\n     215, 162, 154,  93, 248,  13, 142, 160,\n     105,  73, 215, 241,  83,  58,  51,  43,\n     255,  38, 168, 141, 216, 194,  35, 236\n     ]*/\n    b[40] = cus[21]\n    b[41] = cus[22]\n\n    // 对ua处理之后的结果\n    /**\n     * let ua = [\n     129, 190,  70, 186,  86, 196, 199,  53,\n     99,  38,  29, 209, 243,  17, 157,  69,\n     147, 104,  53,  23, 114, 126,  66, 228,\n     135,  30, 168, 185, 109, 156, 251,  88\n     ]*/\n    b[42] = ua[23]\n    b[43] = ua[24]\n\n    //3次加密结束时间\n    b[44] = (b[10] >> 24) & 255\n    b[45] = (b[10] >> 16) & 255\n    b[46] = (b[10] >> 8) & 255\n    b[47] = b[10] & 255\n    b[48] = b[8]\n    b[49] = (b[10] / 256 / 256 / 256 / 256) >> 0\n    b[50] = (b[10] / 256 / 256 / 256 / 256 / 256) >> 0\n\n\n    // object配置项\n    b[51] = b[15]['pageId']\n    b[52] = (b[15]['pageId'] >> 24) & 255\n    b[53] = (b[15]['pageId'] >> 16) & 255\n    b[54] = (b[15]['pageId'] >> 8) & 255\n    b[55] = b[15]['pageId'] & 255\n\n    b[56] = b[15]['aid']\n    b[57] = b[15]['aid'] & 255\n    b[58] = (b[15]['aid'] >> 8) & 255\n    b[59] = (b[15]['aid'] >> 16) & 255\n    b[60] = (b[15]['aid'] >> 24) & 255\n\n    // 中间进行了环境检测\n    // 代码索引:  2496 索引值:  17 （索引64关键条件）\n    // '1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32'.charCodeAt()得到65位数组\n    /**\n     * let window_env_list = [49, 53, 51, 54, 124, 55, 52, 55, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 48, 124, 51,\n     * 48, 124, 48, 124, 48, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 49, 53, 51, 54, 124, 56,\n     * 54, 52, 124, 49, 53, 50, 53, 124, 55, 52, 55, 124, 50, 52, 124, 50, 52, 124, 87, 105, 110,\n     * 51, 50]\n     */\n    let window_env_list = [];\n    for (let index = 0; index < window_env_str.length; index++) {\n        window_env_list.push(window_env_str.charCodeAt(index))\n    }\n    b[64] = window_env_list.length\n    b[65] = b[64] & 255\n    b[66] = (b[64] >> 8) & 255\n\n    b[69] = [].length\n    b[70] = b[69] & 255\n    b[71] = (b[69] >> 8) & 255\n\n    b[72] = b[18] ^ b[20] ^ b[26] ^ b[30] ^ b[38] ^ b[40] ^ b[42] ^ b[21] ^ b[27] ^ b[31] ^ b[35] ^ b[39] ^ b[41] ^ b[43] ^ b[22] ^\n        b[28] ^ b[32] ^ b[36] ^ b[23] ^ b[29] ^ b[33] ^ b[37] ^ b[44] ^ b[45] ^ b[46] ^ b[47] ^ b[48] ^ b[49] ^ b[50] ^ b[24] ^\n        b[25] ^ b[52] ^ b[53] ^ b[54] ^ b[55] ^ b[57] ^ b[58] ^ b[59] ^ b[60] ^ b[65] ^ b[66] ^ b[70] ^ b[71]\n    let bb = [\n        b[18], b[20], b[52], b[26], b[30], b[34], b[58], b[38], b[40], b[53], b[42], b[21], b[27], b[54], b[55], b[31],\n        b[35], b[57], b[39], b[41], b[43], b[22], b[28], b[32], b[60], b[36], b[23], b[29], b[33], b[37], b[44], b[45],\n        b[59], b[46], b[47], b[48], b[49], b[50], b[24], b[25], b[65], b[66], b[70], b[71]\n    ]\n    bb = bb.concat(window_env_list).concat(b[72])\n    return rc4_encrypt(String.fromCharCode.apply(null, bb), String.fromCharCode.apply(null, [121]));\n}\n\nfunction generate_random_str() {\n    let random_str_list = []\n    random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [3, 45]))\n    random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 0]))\n    random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 5]))\n    return String.fromCharCode.apply(null, random_str_list)\n}\n\nfunction generate_a_bogus(url_search_params, user_agent) {\n    /**\n     * url_search_params：\"device_platform=webapp&aid=6383&channel=channel_pc_web&update_version_code=170400&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=123.0.0.0&browser_online=true&engine_name=Blink&engine_version=123.0.0.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7362810250930783783&msToken=VkDUvz1y24CppXSl80iFPr6ez-3FiizcwD7fI1OqBt6IICq9RWG7nCvxKb8IVi55mFd-wnqoNkXGnxHrikQb4PuKob5Q-YhDp5Um215JzlBszkUyiEvR\"\n     * user_agent：\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\"\n     */\n    let result_str = generate_random_str() + generate_rc4_bb_str(\n        url_search_params,\n        user_agent,\n        \"1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32\"\n    );\n    return result_encrypt(result_str, \"s4\") + \"=\";\n}\n\n//测试调用\n// console.log(generate_a_bogus(\n//     \"device_platform=webapp&aid=6383&channel=channel_pc_web&update_version_code=170400&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=123.0.0.0&browser_online=true&engine_name=Blink&engine_version=123.0.0.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7362810250930783783&msToken=VkDUvz1y24CppXSl80iFPr6ez-3FiizcwD7fI1OqBt6IICq9RWG7nCvxKb8IVi55mFd-wnqoNkXGnxHrikQb4PuKob5Q-YhDp5Um215JzlBszkUyiEvR\",\n//     \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\"\n// ));"
  },
  {
    "path": "simple_live_core/assets/js/douyin-webmssdk.js",
    "content": "// extracted from douyin webmssdk.es5.js\n// Modified by @hua0512\n// Date: 2024-06-21\n// Below is a modification to make it work without the original environment\n\n// function my_handler(target_name, number) {\n//     console.log('my_handler', target_name, number)\n//     return target_name + number;\n// }\n//\n window = {}\n document = {}\n navigator = {\n     userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'\n };\n//\n// _history = {}\n// _screen = {}\n// _location = {}\n//\n// window = new Proxy(_window, { get: my_handler });\n// document = new Proxy(_document, { get: my_handler });\n// navigator = new Proxy(_navigator, { get: my_handler });\n// history = new Proxy(_history, { get: my_handler });\n// screen = new Proxy(_screen, { get: my_handler });\n// location = new Proxy(_location, { get: my_handler });\nvar crawler;\n\n\n/** 1.0.0.53 */\n;\nif (!window.byted_acrawler) {\n    function w_0x25f3(_0x545d0a, _0xb73ac6) {\n        var _0x4173a9 = w_0x42f5();\n        return w_0x25f3 = function (_0x138003, _0x35a375) {\n            _0x138003 = _0x138003 - (-0x1 * -0xd15 + -0x1044 + 0x48d);\n            var _0x484578 = _0x4173a9[_0x138003];\n            return _0x484578;\n        }\n            ,\n            w_0x25f3(_0x545d0a, _0xb73ac6);\n    }\n\n    (function (_0x2afeae, _0x11644f) {\n        var _0x34f31d = w_0x25f3\n            , _0x222a7c = _0x2afeae();\n        while (!![]) {\n            try {\n                var _0x5a962 = -parseInt(_0x34f31d(0x31b)) / (-0x1c * 0xac + 0x22 * 0x121 + 0x1 * -0x1391) * (-parseInt(_0x34f31d(0x26a)) / (0xa27 * -0x1 + 0x683 * -0x5 + 0x4 * 0xaae)) + parseInt(_0x34f31d(0x296)) / (-0x18c1 + 0xa9a + 0x715 * 0x2) + -parseInt(_0x34f31d(0x1f3)) / (0x446 * 0x4 + 0x649 + -0x175d) * (parseInt(_0x34f31d(0x31c)) / (0x3 * -0xbbf + 0xf67 * 0x1 + -0x12b * -0x11)) + parseInt(_0x34f31d(0x347)) / (-0x102f * 0x2 + 0x9e * 0x19 + 0x10f6) * (-parseInt(_0x34f31d(0x28f)) / (-0x1 * 0x1817 + -0x1 * -0x184d + -0x2f)) + -parseInt(_0x34f31d(0x241)) / (0x779 * -0x1 + -0x1e1d + 0x259e) * (-parseInt(_0x34f31d(0x2b9)) / (-0x435 + -0x8c9 * 0x2 + 0x1 * 0x15d0)) + -parseInt(_0x34f31d(0x295)) / (0x246e + 0x1 * -0x1c79 + 0x7eb * -0x1) * (-parseInt(_0x34f31d(0x291)) / (-0x1b67 + -0x3c3 * -0x3 + 0x1029)) + parseInt(_0x34f31d(0x307)) / (0x1c3d + -0xaa0 + 0x3 * -0x5db) * (-parseInt(_0x34f31d(0x39d)) / (-0x18de + -0x3 * -0x6f7 + 0x406));\n                if (_0x5a962 === _0x11644f)\n                    break;\n                else\n                    _0x222a7c['push'](_0x222a7c['shift']());\n            } catch (_0x4c4ab0) {\n                _0x222a7c['push'](_0x222a7c['shift']());\n            }\n        }\n    }(w_0x42f5, -0x131739 + 0x156382 + -0x7 * -0x144df));\n\n    function w_0x42f5() {\n        var _0x458f30 = ['\\x20can\\x27t\\x20have\\x20a\\x20.', '484e4f4a403f5243001f3009ad9ffc90000000dc0b1204fb00000477110001033f2e17000135491102004a120000110001110001031a2747000503414500201100010334274700050347450012110001033e2747000603041d45000303111d184301421101021400020211000211000103182c43010211000211000103122c43011802110002110001030c2c4301180211000211000103062c43011802110002110001430118421100011401010211010311000103022c430142110101031c2b11000103042d2f1400021100011401010211010311000243014202110103110101031a2b11000103062d2f4301021101021100014301184205000000003b0114000205000000473b01140003050000008b3b01140004050000009e3b0114000505000000be3b0114000603001400010300140007030014000811010144004a12000143000403e81b03002d14000911010212000232330033021101030211010303001100090700031843021101041200044a12000511010412000612000703021843014302050000fff11c140008110009110008050000fff11a3103002d4a1200080302430114000a11000a14000b11000a12000703202947001811000a4a12000511000a120007032019430114000b45004511000a12000703202747003907000314000c030014000d11000d032011000a120007192747001411000c0700091817000c354917000d214945ffdc11000c11000b1814000b07000a11000b18140007021101051100070302430214000702110103030011000707000318430214000e02110106430014000f11011807000b25470004014500010011000f07000c1607000314001011011612000d3300131101074a12000e11011612000d430107000f2647006503001400111101161200104700290211010803001101074a12000e0211010911011612000d1101161200104302430143021400114500200211010803001101074a12000e0211010a11011612000d43014301430214001107001111001118070012181400100211010b110116120013430114001211011612001447001511010c4a12001511001211011612001443024500031100121400121100100211010d110012430118140010110010070016180211010e1101161200134301180700121814001011001007001718070018181400100211010f11000f4301140013110102120002323300060211011043001400141101021200023233001811011112001934000f021101120211011307001a430143011400150211000411000743010211000511000706001b1b03002d4301180211000611001411000731430118021100040211010311000e1101021200023233000611011412001c4a12000843004302050000fff11c03102b0211010311000e110010070003184302050000fff11c2f4301180211000511001303082b11010212001d03042b2f110007314301180211000311000843011814001602110006030043014911001547000a1100161100151814001607001e1100161814001702110108030011001743024a120008031043011400181100184a12001f1100181200070302191100181200074302140019110017110019181400171100174200200c6b7f62604e656c7f4e626968076a6879596460680b6962604362795b6c6164690004657f686b097e786f7e797f64636a087d7f6279626e6261066168636a79650879625e797f64636a013d0e3c3d3d3d3d3d3d3d3c3c3d3d3d3d076b627f7f686c610a69647f686e795e646a63046f626974097e797f64636a646b740276700b6f6269745b6c613f7e797f0a6f62697452656c7e6530012b03787f61057c78687f740a6c7e626169527e646a63097d6c7965636c606830097979527a686f646930062b78786469300e526f74796869527e686e52696469077979527e6e64690a393f3439343b3a3f343b09787e687f4c6a686379096b685b687f7e6462630e523d3f4f39573b7a623d3d3d3d3c057e61646e68', '484e4f4a403f5243003c01321067d4bc00000824ebfd74540000087f0211010311000111000243024a12000505000000213b0105000001533b014302421100011200064701251100011200073300191100011200074a12000811030112000912000a430103011d2634000c0211030211000112000743014700f111000112000b4a12000c07000d43011400021100024700d902110303110001120007430114000311000311030412000e2547005511000211030515000f1100031103051500100211030607000f110002430249021103071100024301491100031101032947001f1103051200111200120300294700100211030811030903020403e81a4302494500161101031103051200102a47000911000211030515000f1101031103041200132533000c110305120011120012030a274700361103051200114a120014110002430149110305120011120012030125470017021103071100024301490211030607000f110002430249110001421100014008421100023400010d14000211020a33000711000111020b3714000307001514000407001614000507001514000611020c33000711000111020d374701c411000112000a14000411000212001747000f1100021200174a12001843004500030700161400050211020e1100044301330011110005070016253400071100050700192547017d11020512001014000711020512001a1400081100080700152347000f07000f11020512000f0c000245001207000f11020512000f07001a1100080c00041400090211020f021102101100044301110009430214000a0211021111000a430114000b0211021211000b11000212001b430214000c0211020f11000a11010111000c0c0002430214000d07001514000e11021312001c47000911000d14000e4500b10d021102140211000d43020e000714000f110005070019254700710211021511000111000243024a12001d07001e43010300134a12001f430014000602110216110006430147003b0211021711000f11000611000212001b4303490211021811000f0807002043031400100211020f11000d1101021100100c0002430214000e45000611000d14000e4500250211021811000f0807002043031400110211020f11000d1101021100110c0002430214000e1102131200214700130211021a430011000212000b110219120022160211010411000e1100021100074303421100034701e91100011200071400041100011200174700091100011200174500030700161400050211020e1100044301330011110005070016253400071100050700192547019811020512001014001211020512001a1400131100130700152347000f07000f11020512000f0c000245001207000f11020512000f07001a1100130c00041400140211020f021102101100044301110014430214001502110211110015430114001611000112000b1400171102131200214700161100174a1200231102191200220211021a4300430249110005070019254700480211021511000111000243024a12001d07001e43010300134a12001f43001400061100014a12002443004a12002543004a12000505000007293b01050000081e3b014302424500bd021102121100160243021400180211020f1100151101011100180c000243021400190d021102140211001943020e000714001a0211021811001a08070020430314001b0211020f11001911010211001b0c0002430214001c11020b11001c0d1100170e000b080e001b1100011200260e00261100011200270e00271100011200280e00281100011200290e002911000112002a0e002a11000112002b0e002b11000112002c0e002c440214001d0211010411001d110002110012430342021101031100011100024302424501df11000212000b324700070d11000215000b11000114000411000212001747000f1100021200174a12001843004500030700161400050211020e1100044301330011110005070016253400071100050700192547017d11020512001014001e11020512001a14001f11001f0700152347000f07000f11020512000f0c000245001207000f11020512000f07001a11001f0c00041400200211020f02110210110004430111002043021400210211021111002143011400220211021211002211000212001b43021400230211020f1100211101011100230c0002430214002407001514002511021312001c4700091100241400254500b10d021102140211002443020e0007140026110005070019254700710211021511000111000243024a12001d07001e43010300134a12001f430014000602110216110006430147003b0211021711002611000611000212001b430349021102181100260807002043031400270211020f1100241101021100270c00024302140025450006110024140025450025021102181100260807002043031400280211020f1100241101021100280c000243021400251102131200214700130211021a430011000212000b110219120022160211010411002511000211001e4303420211010311000111000243024208420700151400020211031211011611000143021400030211030f1101151102011100030c000243021400040211031611010643014700490d021103140211000443020e000714000502110317110005110106110001430349021103181100050807002043031400060211030f1100041102021100060c0002430214000245000611000414000211030b1100020d1101011200170e00171101170e000b1100010e001b1101011200260e00261101011200270e00271101011200280e00281101011200290e002911010112002a0e002a11010112002b0e002b11010112002c0e002c44021400070211020411000711010211011243034211000140084205000000003b0314000405000001593b021400050700001400010700011400020211010043003247000208421101011200024700020842001101011500021101011200031400031100031101011500041100051101011500030842002d0754214e636b797f0a537f656b626d78797e691653536d6f53656278697e6f697c786968536a69786f64056a69786f6406536a69786f64047864696202636703797e60076562686974436a0860636f6d7865636204647e696a0764696d68697e7f036b69780a7421617f217863676962037f696f07617f586367696208617f5f786d78797f0e617f42697b586367696240657f78066069626b78640465626578047c797f6400034b4958066169786463680b7863597c7c697e4f6d7f69045c435f580b53536d6f5378697f786568046e636875017a057f7c60657801370b786340637b697e4f6d7f69076a637e7e696d60037f68650d7f696f45626a6344696d68697e037f6978056f606362690478697478087e696a697e7e697e0e7e696a697e7e697e5c6360656f7504616368690b6f7e6968696278656d607f056f6d6f6469087e6968657e696f7809656278696b7e657875', 'own', 'Super\\x20expression\\x20must\\x20either\\x20be\\x20null\\x20or\\x20a\\x20function', 'getTimezoneOffset', 'array', 'toDataURL', 'enumerable', 'setPrototypeOf', 'field', 'WEBGL', 'wID', 'illegal\\x20catch\\x20attempt', 'TouchEvent', '3160hBpQVk', '484e4f4a403f5243000d0a13c08652000000000f3be74070000003930211021611010111000143024908421101003300031101013300031101023247000208420d0700000e000103040e00021101181200000e00030d0700040e000103030e00021101030e00050d0700060e000103030e00021101040e00050d0700070e000103030e00021101050e00050d0700080e000103030e00021101030e00050d0700090e000103000e00020d07000a0e000103000e00020d07000b0e000103000e00020d07000c0e000103000e00020d07000d0e000103000e00020d07000e0e000103030e00021101060e00050d07000f0e000103030e00021101070e00050d0700100e000103010e00020d0700110e000103010e00020d0700120e000103010e00020d0700130e000103000e00020d0700140e000103030e00021101080e000503010e00150d0700160e000103030e00021101090e00050d0700170e000103030e000211010a0e00050d0700180e000103030e00021101030e00050d0700190e000103030e000211010b0e00050d07001a0e000103030e000211010c0e00050d07001b0e000103030e000211010d0e00050d07001c0e000103030e00021101030e00050d07001d0e000103000e00020d07001e0e000103030e000211010e0e000507001f0e00200d0700210e000103030e000211010f0e00050d0700220e000103030e00021101100e00050d0700230e000103030e00021101110e000503010e00150d0700240e000103010e00020d0700250e000103040e00021101121200260e00030d0700270e000103030e00021101130e00050d0700280e000103030e00021101030e00050d0700290e000103040e00020c00221400010c0000140002030014000311000311000112002a274700eb110001110003131200020300480013030148002f0302480045030348005b494500be0211011411010011000111000313120001134301110001110003131500034500a011010111000111000313120001131100011100031315000345008511010211000111000313120001131100011100031315000345006a110001110003131200154700321101153a07002b264700241100024a12002c110001110003131200054a12002d110001110003131200204301430149450025110001110003131200054a12002d0211000111000313120020430211000111000313150003450003450000170003214945ff081101153a07002b2647001d1101154a12002e11000243014a12002f05000000003b0143014945000a02110116110001430149084200300349414c0146014e015a095b5c495a5c7c41454d015c09494a4144415c414d5b064b49465e495b0a5c41454d5b5c49455819085844495c4e475a451340495a4c5f495a4d6b47464b5d5a5a4d464b510c4c4d5e414b4d654d45475a51084449464f5d494f4d094449464f5d494f4d5b0a5a4d5b47445d5c4147460f495e4941447a4d5b47445d5c414746095b4b5a4d4d467c47580a5b4b5a4d4d46644d4e5c104c4d5e414b4d7841504d447a495c41470a585a474c5d4b5c7b5d4a074a495c5c4d5a510158095c475d4b4061464e47085c41454d5247464d0a5c41454d5b5c4945581a074f585d61464e470b425b6e47465c5b64415b5c0b58445d4f41465b64415b5c0a5c41454d5b5c4945581b095d5b4d5a694f4d465c0a4d5e4d5a6b474743414d075c5c775b4b414c01450b5b51465c49506d5a5a475a0c46495c415e4d644d464f5c40055a5c4b61780844474b495c414746094e587e4d5a5b4147460b77775e4d5a5b4147467777084b44414d465c614c0a5c41454d5b5c4945581c0b4d505c4d464c6e414d444c06444d464f5c40095d464c4d4e41464d4c04585d5b40044b49444403494444045c404d46', 'rewriteUrl\\x20', 'setTTWid', 'height', 'product', 'Vrinda', 'X-Mssdk-Info', 'arrayBuffer', 'vibrate', 'sendBeacon', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'canvas', 'Character\\x20outside\\x20valid\\x20Unicode\\x20range:\\x200x', 'join', 'throw', 'iterator\\x20result\\x20is\\x20not\\x20an\\x20object', 'DEPTH_BITS', 'compatMode', 'forEach', 'Attempted\\x20to\\x20access\\x20private\\x20element\\x20on\\x20non-instance', 'unsupport\\x20type', 'attempted\\x20to\\x20call\\x20addInitializer\\x20after\\x20decoration\\x20was\\x20finished', 'pageXOffset', 'length', 'method', 'bytes', 'charAt', 'Sylfaen', 'toElementDescriptor', 'base64', 'createElement', 'private', 'ttcid', 'msStatus', 'MAX_VARYING_VECTORS', 'elements', '484e4f4a403f524300232a0d2ebaf9a00000000042410a740000019d110100002347000200421101011200004700020042070001110102364700351101024a12000111010143011400011100014a120002070000430103002a34000f1100014a120002070003430103002a470002004211010333000611010312000433000911010312000412000533000c1101031200041200051200064700213e000414000c413d00171101031200041200054a1200064300082547000200424107000707000807000907000a07000b07000c07000d07000e07000f0700100700110c000b1400020700120700130700140c000314000303001400041100041100031200152747001e11000311000413140005110103110005134700020042170004214945ffd503001400061100061100021200152747002111000211000613140007110103120016110007134700020042170006214945ffd21101024a1200171101031200164301140008030014000911000814000a11000911000a1200152747003911000a1100091314000b11000b4a1200181101050700194401430133000e11010312001611000b1307001a134700020042170009214945ffba0142001b096d7f787e68736c7f68137d7f6e556d744a68756a7f686e63547b777f690773747e7f62557c09767b747d6f7b7d7f690679726875777f07686f746e73777f07797574747f796e1445456d7f787e68736c7f68457f6c7b766f7b6e7f134545697f767f74736f77457f6c7b766f7b6e7f1b45456d7f787e68736c7f6845697968736a6e457c6f74796e7375741745456d7f787e68736c7f6845697968736a6e457c6f74791545456d7f787e68736c7f6845697968736a6e457c741345457c627e68736c7f68457f6c7b766f7b6e7f1245457e68736c7f68456f746d687b6a6a7f7e1545456d7f787e68736c7f68456f746d687b6a6a7f7e1145457e68736c7f68457f6c7b766f7b6e7f144545697f767f74736f77456f746d687b6a6a7f7e1445457c627e68736c7f68456f746d687b6a6a7f7e0945697f767f74736f770c797b7676497f767f74736f771645497f767f74736f7745535e5f45487f7975687e7f6806767f747d6e72087e75796f777f746e04717f636905777b6e79720a463e417b3760477e794506797b79727f45', 'pop', 'showOffsetX', 'MAX_TEXTURE_IMAGE_UNITS', '2571598OPFKfY', 'webgl', 'appendChild', 'outerHeight', 'screenX', 'kind', 'navigator', 'attempted\\x20to\\x20use\\x20private\\x20field\\x20on\\x20non-instance', 'cookie', 'AsyncIterator', 'crypto', 'buffer', 'availHeight', 'The\\x20property\\x20descriptor\\x20of\\x20a\\x20field\\x20descriptor', 'resolve', 'react.element', 'close', 'monospace', 'stun:stun.l.google.com:19302', 'acc', 'BLUE_BITS', 'Arguments', 'style', 'nextLoc', 'pageYOffset', '72px', 'webkitRequestAnimationFrame', 'hidden', 'MAX_FRAGMENT_UNIFORM_VECTORS', 'node', 'Parchment', 'kWebsocket', 'xmst', 'number', 'altKey', 'A\\x20method\\x20descriptor', 'Leelawadee', '6300OtYFrs', 'href', '1155KnHwvu', 'storage', 'sTm', 'setMonth', '20690wmYtVy', '266076LNZfld', 'Malformed\\x20string', 'setConfig', 'touchmove', 'rval', 'unload', 'from', 'Image', 'tryLoc', 'ActiveXObject', 'assign', '\\x20property.', '_sent', 'mmmmmmmmmmlli', 'offsetHeight', 'slice', 'getOwnPropertyDescriptor', 'mhe', 'utf8', 'Object\\x20is\\x20not\\x20async\\x20iterable', 'reset', 'raw', 'constructor', 'attempted\\x20to\\x20', 'Invalid\\x20attempt\\x20to\\x20iterate\\x20non-iterable\\x20instance.\\x0aIn\\x20order\\x20to\\x20be\\x20iterable,\\x20non-array\\x20objects\\x20must\\x20have\\x20a\\x20[Symbol.iterator]()\\x20method.', 'isArray', 'chargingTime', '__await', '484e4f4a403f524300071336bc6677450000001613b112b6000003090b4a12000911021607000a07000b4402070001430242070000140001110115082633000511011502263300071101150700012647001d3e000a140029070002140001413d000d021101001101154301140001411101013234000611010212000347000b001401010211010343004902110104430049110105120004140002110106120005140003030214000411000414000503401400060211010011011443011400071101074a120006021101001101074a1200061100074301430143011400081101074a120006021101001101074a1200061100014301430143011400091101081200071200083247001005000000003b0011010812000715000811010912000c14000a11000a33000811000a3a07000d2547000c11000a4a120008430014000a0211010a110003110002430214000b0211010b11000b11000a430214000c0211010c11000c07000e430214000d1101074a1200060211010011000d4301430114000e11010d44004a12000f43000403e81b14000f0211010e43001400101100061400111100030401001b1400121100030401001c140013110002140014110008030e13140015110008030f13140016110009030e13140017110009030f1314001811000e030e1314001911000e030f1314001a11000f03182c0400ff2e14001b11000f03102c0400ff2e14001c11000f03082c0400ff2e14001d11000f03002c0400ff2e14001e11001003182c0400ff2e14001f11001003102c0400ff2e14002011001003082c0400ff2e14002111001003002c0400ff2e140022110011110012311100133111001431110015311100163111001731110018311100193111001a3111001b3111001c3111001d3111001e3111001f311100203111002131110022311400230400ff1400240211010f11001111001311001511001711001911001b11001d11001f11002111002311001211001411001611001811001a11001c11001e11002011002243131400250211010b0211011011002443011100254302140026021101111100051100241100264303140027021101121100270700104302140028110028420011201c4c491c401b1c41401e48481a4a484c1d414048484141401d1b1e404c4a4f1d00201e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e010e060d1a1b171c1d071d160e1b171c1d061c1d1b171c1d09080a170c170c01081d040c0a1115070a1d0814191b1d212623240b240d3e3d3e3e2400394825530423240b240d3e3d3e3e2400394825535c011f090d0b1d0a391f1d160c060b0c0a11161f020b48071f1d0c2c11151d020b4a', 'Arial\\x20Hebrew', 'msToken', 'An\\x20element\\x20descriptor\\x27s\\x20.placement\\x20property\\x20must\\x20be\\x20one\\x20of\\x20\\x22static\\x22,\\x20\\x22prototype\\x22\\x20or\\x20\\x22own\\x22,\\x20but\\x20a\\x20decorator\\x20created\\x20an\\x20element\\x20descriptor\\x20with\\x20.placement\\x20\\x22', 'visible', 'decode', 'concat', '30762fvQkGV', 'hash', 'STENCIL_BITS', 'configurable', '\\x20private\\x20field\\x20on\\x20non-instance', 'T_MOVE', 'clientX', 'images', 'version', 'renderer', 'removeItem', 'catchLoc', 'indexOf', 'msHidden', 'isView', 'toLocaleString', 'https://mssdk.bytedance.com', 'B4Z6wo', 'dispatchException', 'msvisibilitychange', '\\x20decorators\\x20must\\x20return\\x20a\\x20function\\x20or\\x20void\\x200', 'Dkdpgh4ZKsQB80/Mfvw36XI1R25+WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe', 'Cannot\\x20convert\\x20undefined\\x20or\\x20null\\x20to\\x20object', 'initializer', 'awrap', 'continue', 'mousedown', 'mousemove', 'update', '__ac_blank', '0123456789abcdef', 'getItem', 'Futura', 'MAX_RENDERBUFFER_SIZE', 'GPUINFO', 'host', '484e4f4a403f524300010a1106afb0650000000079a66ec20000008c1101001200004a12000143001400011100014a120002070003430103002a470002014211010307000444011400021101013300061101011200053300091101011200051200064700411101011200051200061400031100034a120002070007430103002534000f1100034a120002070008430103002534000c1100024a120009110003430147000200420142000a093b3d2b3c0f292b203a0b3a210221392b3c0d2f3d2b0727202a2b360128082b222b2d3a3c21204a10263a3a3e3d71741261126166157e637713357f627d33661260157e637713357f627d3367357d3332152f63287e637713357f627a336674152f63287e637713357f627a3367357933670822212d2f3a27212004263c2b28042827222b10263a3a3e74616122212d2f2226213d3a043a2b3d3a', 'BluetoothUUID', 'decorateClass', 'mozRTCPeerConnection', 'defineClassElement', 'credentials', 'writable', 'value', 'WEBKIT_EXT_texture_filter_anisotropic', 'JS_MD5_NO_ARRAY_BUFFER', 'Metadata\\x20keys\\x20must\\x20be\\x20symbols,\\x20received:\\x20', 'getReferer', 'indexDB', '__proto__', 'Object', 'splice', 'symbol', 'offsetWidth', 'executing', 'mozBattery', 'normal', 'kFakeOperations', 'reverse', 'finisher', 'createOffer', 'addEventListener', 'Cannot\\x20call\\x20a\\x20class\\x20as\\x20a\\x20function', '\\x20must\\x20be\\x20a\\x20function', 'getContext', 'referrer', 'afterLoc', 'has', 'return', 'kNoMove', 'netscape', 'MAX_CUBE_MAP_TEXTURE_SIZE', 'bind', 'width', 'valueOf', 'off', 'JS_MD5_NO_ARRAY_BUFFER_IS_VIEW', 'innerWidth', '257232gkndOM', 'null', 'isSecureContext', 'pixelDepth', '.initializer\\x20has\\x20been\\x20renamed\\x20to\\x20.init\\x20as\\x20of\\x20March\\x202022', '/web/report', 'removeChild', '[object\\x20Boolean]', 'getSupportedExtensions', 'error', 'GeneratorFunction', 'message', 'initializeInstanceElements', 'systemLanguage', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 'tt_webid', 'sqrt', '__ac_referer', 'blocks', 'MOZ_EXT_texture_filter_anisotropic', '1hcbEHL', '308350OyvEoV', '484e4f4a403f5243003a20169967f185000000000b49c93c000000761101001200004a12000143001400011100014a120002070003430103002a47000201421101013a070004263300191101021200051200064a12000711010112000843010700092534002b1101033a0700042547000607000445000902110104110103430107000a2533000a11010312000b07000c2542000d09282e382f1c3a3833290b293211322a382f1e3c2e38073433393825123b083831383e292f323309283339383b34333839092d2f32293229242d380829320e292f34333a043e3c3131072d2f323e382e2e1006323f37383e297d2d2f323e382e2e0006323f37383e290529342931380433323938', 'for', 'break', 'construct', 'Constantia', 'webkitvisibilitychange', 'activeState', 'toClassDescriptor', 'layers', 'bogusIndex', 'arg', 'screen', 'buffer8', 'getOwnPropertyNames', 'get', 'prev', 'buildID', 'lastByteIndex', '\\x27\\x20method', 'Bad\\x20UTF-8\\x20encoding\\x200x', '[object\\x20Array]', 'add', '484e4f4a403f5243000027194f9666590000000044a16fed000000270700001400013e000a140002070001140001413d000d0211010011010243011400014111000142000200200d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d', 'call', 'characterSet', 'bodyVal2str', 'tryEntries', '\\x22\\x20is\\x20read-only', 'tt_webid_v2', 'locationbar', 'maxTouchPoints', 'string', 'addElementPlacement', 'try\\x20statement\\x20without\\x20catch\\x20or\\x20finally', 'mozVisibilityState', 'showColor', 'name', 'split', 'xmstr', 'prototype', 'AcroPDF.PDF.1', 'Tunga', '4218tDAtHd', 'AVENIR', 'getMetadata', 'track', 'touchEvent', 'decorateConstructor', 'now', 'failed\\x20to\\x20set\\x20property', '484e4f4a403f524300263203ec75a3740000000817718683000003051100011100022e4211011507000013002547000a070001110115070002160d03000e0003000e00040c00000e00050c00000e0006010e0007010e00000700080e0002010e00090d0305033c1a0e000a03020e000b0305033c1a0e000c0e000d0700080e000e000e000f03030e00101400011101004a1200111100011101154302491100011200030300253400161101014a120012110001120003430111000112000326470009110102070013440140110001120014330007110001120015324700091101020700164401401101031200174a12001811000112000343014911010412000303002547000c1100011200031101041500031100011200043247009c110001120002070008254700091101020700194401401100011200020700012447000911010207001a44014011000112000211010415000202110105110001430111010415001b021101061101071100011200100403e81a43024911000112001c0826330005110001022647002e11010412001d4a12001811000112001c43014911010412001d4a12001e05000000003b024301323211010415001c11000112000d4700a60011010415001f11010847006411000112000d12000a33001311000112000d12000a11010412000d12000a2947003f021101091101084301491101004a1200110d11010412000d11000112000d430311010415000d0211010a11010b11010412000d12000a0403e81a43021401084500351101004a1200110d11010412000d11000112000d430311010415000d0211010a11010b11010412000d12000a0403e81a430214010811000112002047001c1100011200201101041500200211010611010c03050403e81a4302491100010b1500210211010d4300490211010e1100011200054301490211010f1100011200064301490211011043004911011132330006110001120007470020001401111100011200071101041500070211010611011203050403e81a43024911000112000f4700241101041200223247001a0011010415002202110106110113030a0403e81a11000143034900110104150023084200240350524402575a064651535d5b5a03555d50055d4767707f0e515a555658516455405c785d47400f414658665143465d405166415851470347505d0003505142035246510a415a5d4075595b415a4008415a5d40605d595105404655575f04595b5051044c4c56530450504640065547475d535a0552585b5b461e5b44405d5b5a14555d501c7d5a40515351461d145d47145a51515051501503565b5107565b517c5b474024565b517c5b474014594147401456511444465b425d505150145d5a14565b5114595b505107555d50785d4740044441475c0f4651535d5b5a145d47145a41585815124651535d5b5a145d47145d5a4255585d50150a4651535d5b5a775b5a520142106b515a55565851675d535a5540414651064651504157510b515a55565851604655575f0444514652075b44405d5b5a47046b5052440b5d5a5d405d55585d4e5150', 'appMinorVersion', 'Attempted\\x20to\\x20decorate\\x20a\\x20public\\x20method/accessor\\x20that\\x20has\\x20the\\x20same\\x20name\\x20as\\x20a\\x20previously\\x20decorated\\x20public\\x20method/accessor.\\x20This\\x20is\\x20not\\x20currently\\x20supported\\x20by\\x20the\\x20decorators\\x20plugin.\\x20Property\\x20name\\x20was:\\x20', 'hex', 'dischargingTime', 'PLUGIN', 'T_KEYBOARD', 'ret_code', '\\x22.\\x20Please\\x20configure\\x20the\\x20dynamicRequireTargets\\x20or/and\\x20ignoreDynamicRequires\\x20option\\x20of\\x20@rollup/plugin-commonjs\\x20appropriately\\x20for\\x20this\\x20require\\x20call\\x20to\\x20work.', '@@toPrimitive\\x20must\\x20return\\x20a\\x20primitive\\x20value.', 'battery', 'Generator\\x20is\\x20already\\x20running', 'headers', 'md5', 'setter', '=;\\x20expires=Mon,\\x2020\\x20Sep\\x202010\\x2000:00:00\\x20UTC;\\x20path=/;', '_raw_sec_did', 'hardwareConcurrency', 'script', 'fontSize', '_byted_sec_did', 'keydown', '__private_', 'screenY', 'Duplicated\\x20element\\x20(', '484e4f4a403f524300211209597bcccc0000053aae77fba6000005e50b1200093247004e0b12000a4a12000b0d0700050e000c1100000e000d43014911021607000e07000f44024a120010110001430147001f1100024a12001143004a12001243004a12001307001443010300130b1500151101054a1200160b1100004302421100000b1500171101074a1200160b1100004302420c00000b15000a0b12000a4a12000b0d0700040e000c1100000e000d4301491100014a12001843000b1500191100020b15001a1101044a1200160b1100004302421101094a1200240b120019430103011d26140002021102010b12001a43013300031100024702fe0b12001a4a120024070025430103011d2947000e1101064a1200160b1100004302421100010b1500260b1200271400030b12001b1400040b12001c1400050b12001d1400060b12001e1400070b12001f1400080b1200201400090b12002114000a0d14000b030014000c11000c1101081200282747001f0b12002911010811000c131311000b11010811000c131617000c214945ffd411020212002a14000d11020212002b14000e11000e07002c2347000f07002d11020212002d0c000245001207002d11020212002d07002b11000e0c000414000f02110203021102040b12001a430111000f4302140010021102051100104301140011021102061100110b1200264302140012021102031100101101011100120c0002430214001307002c14001411020712002e4700091100131400144500910d021102080211001343020e002f1400150b12001907002325470050021102090b120015430147003a0211020a1100150b1200150b1200264303490211020b110015080700304303140016021102031100131101021100160c000243021400144500061100131400144500250211020b110015080700304303140017021102031100131101021100170c000243021400140b12000a33000f0b12000a03001307000c130700042647000202420b12000a14001803001400191100191100181200282747005d11001903002547002d1100141100181100191312000d030116000b1500091101044a1200160b1100181100191312000d43024945001f0b1100181100191307000c13134a1200160b1100181100191312000d430249170019214945ff960b1200174700100b1200074a1200160b0b1200174302490b07000a39491102071200314700140b4a12000511020c1200320211020d43004302491100030b1500271100040b15001b1100050b15001c05000003ed3b010b15001d1100070b15001e1100080b15001f1100090b15002011000a0b150021030014001a11001a1101081200282747001f11000b11010811001a13130b12002911010811001a131617001a214945ffd41101064a1200160b11000043024203001400020b1200333400040b12001a34000307002c1400030211030e110003430147000503011400021100034a120024110300120034120035430103011d2647000503021400021100020300294700ea0b4a12003607003743011400041100044700d70211030f0b12001a43011400051100051103101200382547005511000411030215002d11000511030215002a0211031107002d1100044302490211031211000443014911000511010d2947001f1103021200391200280300294700100211031311031403020403e81a43024945001611010d11030212002a2a47000911000411030215002d11010d11031012003a2533000c110302120039120028030a274700361103021200394a12000b110004430149110302120039120028030125470017021103121100044301490211031107002d11000443024911010647000a02110106110001430149084207000014000107000114000211010012000212000314000311000312000414000411000312000514000511000312000614000611000312000714000711000312000847000208420011000315000805000000003b0211000315000505000000643b0011000315000705000000793b0211000315000407001b07001c07001d07001e07001f0700200700210c00071400080700220700230c000214000905000000ba3b011100031500060842003b0755204f626a787e0a527e646a636c79787f680e5540414579797d5f687c78687e79097d7f62796279747d6804627d6863107e68795f687c78687e7945686c69687f047e68636910627b687f7f6469684064606859747d680f526c6e52646379687f6e687d79686905527e68636915526f7479686952646379687f6e687d795261647e79047d787e65046b78636e096c7f6a78606863797e0e536e6263796863792079747d682901640479687e790879625e797f64636a0b796241627a687f4e6c7e68057e7d61647901360e526f74796869526e626379686379056c7d7d61741552627b687f7f6469684064606859747d684c7f6a7e0b7962587d7d687f4e6c7e680d526f74796869526068796562690a526f7479686952787f610762636c6f627f79076263687f7f627f06626361626c6909626361626c696863690b626361626c697e796c7f790a62637d7f626a7f687e7e09626379646068627879034a4859045d425e59076463696875426b0b527e646a636c79787f68300b526f74796869526f6269741262637f686c69747e796c79686e656c636a68066168636a796506787d61626c6908607e5e796c79787e0b52526c6e5279687e7964690007607e5962666863017b03787f61076b627f7f686c61037e69640d7e686e44636b6245686c69687f0b7f687e7d62637e68585f410861626e6c796462630465627e79116a68795f687e7d62637e6845686c69687f0a7520607e207962666863037e686e0e607e43687a596266686341647e790464636479', 'round', 'innerHTML', 'appCodeName', 'defineProperties', 'Could\\x20not\\x20dynamically\\x20require\\x20\\x22', 'push', '__destrObj', 'toElementDescriptors', 'defaultProps', 'fromElementDescriptor', 'documentMode', 'Object.keys\\x20called\\x20on\\x20non-object', 'WEBGL_debug_renderer_info', 'reduce', 'replace', 'setUserMode', 'changedTouches', 'JS_MD5_NO_WINDOW', '[object\\x20Object]', 'item', 'beforeunload', '%27', 'enableTrack', 'envcode', 'gpu', 'ubcode', 'getParameter', 'undefined', 'start', 'isGeneratorFunction', 'completion', 'getOwnPropertySymbols', 'next', 'availWidth', 'values', 'oscpu', 'Tw\\x20Cen\\x20MT', 'sort', 'bluetooth', 'requestMediaKeySystemAccess', 'keyboardList', 'key', 'window', 'Unfinished\\x20UTF-8\\x20octet\\x20sequence', 'setMetadata', 'static', 'debug', 'languages', 'toolbar', 'msDoNotTrack', 'reject', 'finishers', '208XZrBOJ', 'UNMASKED_RENDERER_WEBGL', 'external', 'shadowBlur', 'POST', '484e4f4a403f5243003e0d23e5c579310000006248d1745c000002cc0d140001110200070000131400021100020700012447000a11000211000107000016110200070002131400031100030700012447000a11000311000107000316110200070004131400041100040700012447000a110004110001070005161100014205000000003b001400010114000211010f3247000911010112000614010f11010f110101120007254700040014000211010244004a12000843001400030d1101001200094a12000a030043010e000b11010012000c4a12000a030043010e000d11010012000e4a12000a030043010e000f1101001200104a12000a030043010e001114000411000412000b12001203002533000c11000412000d12001203002533000c11000412000f12001203002533000c110004120011120012030025470002084211000412000b12001203101a11000412000d120012030c1a1811000412000f12001203041a1811000412001112001203081a181400051100031101031200131101041200141200150403e81a182747003a1101031200161101041200141200170404001a27470020110103120016110005181101030700163549021101054300490014000245000045001d11000311010315001311000511010315001602110105430049001400021100024700f703021400060d1100040e00181100060e00191400070d11000707001a1611010412001b11000707001a1307001b1607000111010244004a12000843001811000707001a1307001c1611010012001d11000707001a1307001d16030011000707001a1307001e160d11000707001f161101064a12002011000707001f13021100014300430249021101071101081200210211010911010a4a120022110007430111010b120023430243021400081101041200240700251314000911000932470002084211010f110101120026254700190211010c110009110008430214000a11000a3247000045000f0211010d1100091100080d0043044908420027052121223c31000821210a2230373c310721210230371c310b21210a2230373c310a23670921210230373c3103670727203b3b3c3b3205333920263d07323021013c383008383a2330193c2621062625393c3630063730183a23300936393c363e193c262107373016393c363e0c3e302c373a342731193c26210a37301e302c373a3427310b3436213c233006213421300b223c3b313a2206213421300639303b32213d0326013805212734363e08203b3c21013c3830033436360a203b3c2114383a203b210837303d34233c3a2707382632012c253003221c1103343c3109213c3830262134382507343c31193c26210b25273c2334362c183a313006362026213a38063426263c323b0f0210170a1110031c16100a1c1b131a092621273c3b323c332c043f263a3b0a2730323c3a3b163a3b33092730253a272100273904302d3c21', 'metadata', 'productSub', 'mark', '\\x20is\\x20not\\x20an\\x20object.', 'substr', 'Invalid\\x20attempt\\x20to\\x20spread\\x20non-iterable\\x20instance.\\x0aIn\\x20order\\x20to\\x20be\\x20iterable,\\x20non-array\\x20objects\\x20must\\x20have\\x20a\\x20[Symbol.iterator]()\\x20method.', 'Gulim', 'experimental-webgl', 'setRequestHeader', 'charging', '484e4f4a403f52430031032581faca6c0000000093505d60000001c60700001400010d1400020700011100020700021607000311000207000416070005110002070006161100021101021314000307000714000403001400061101011200081100060303182a4700b11101014a1200091700062143010400ff2e03102b1101014a1200091700062143010400ff2e03082b2f1101014a1200091700062143010400ff2e2f1400051100041100034a12000a1100050500fc00002e03122c43011817000435491100041100034a12000a110005050003f0002e030c2c43011817000435491100041100034a12000a110005040fc02e03062c43011817000435491100041100034a12000a110005033f2e430118170004354945ff3f110101120008110006190300294700b41101014a1200091700062143010400ff2e03102b110101120008110006294700161101014a12000911000643010400ff2e03082b45000203002f1400051100041100034a12000a1100050500fc00002e03122c43011817000435491100041100034a12000a110005050003f0002e030c2c4301181700043549110004110101120008110006294700161100034a12000a110005040fc02e03062c430145000311000118170004354911000411000118170004354911000442000b011441686b6a6d6c6f6e616063626564676679787b7a7d7c7f7e717073484b4a4d4c4f4e414043424544474659585b5a5d5c5f5e51505319181b1a1d1c1f1e1110020614025a19416d424d594e411d73625a786b111906644f5f5e1a1f7160187b1b1c027e7c68456c401e67654b4658707d66795c53446f4363475b505110617f6e4a487a5d6a4c14025a18416d424d594e411d73625a786b111906644f5f5e1a1f7160187b1b1c047e7c68456c401e67654b4658707d66795c53446f4363475b505110617f6e4a487a5d6a4c14025a1b0006454c474e5d410a4a41485b6a464d4c685d064a41485b685d', 'toString', 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx', 'warn', 'parse', 'sent', 'iterator', 'PDF.PdfCtrl.', '__ac_testid', 'clickList', 'create', 'hasOwnProperty', 'init', 'An\\x20initializer', 'clientHeight', 'extras', '__esModule', 'sessionStorage', 'kKeyboardFast', 'devicePixelRatio', ';\\x20path=/;', 'location', 'GREEN_BITS', '484e4f4a403f524300192d11257a6fc000000000d4cf00750000006703011400011101004a12000011010603062b1100012f43011400021101004a1200001101014a1200011101014a12000243000401001a4301430114000302110102110003110105430214000411000211000318110004181400050211010311000507000343024200040c5f4b56547a51584b7a565d5c055f5556564b064b58575d5654024a08', 'Castellar', 'toGMTString', 'mozHidden', 'Set', '[native\\x20code]', 'complete', '484e4f4a403f52430012270f0b8aa329000000005cddda270000008a0211010043003247007e1101014a12000007000143011400011100011200024a12000343004a120004110104070005070006440207000743024a120008070009430103002734002c1101021200034a12000343004a120004110104070005070006440207000743024a120008070009430103002734001011010212000a4a120003430007000b26420142000c0d18091e1a0f1e3e171e161e150f06181a150d1a08090f143f1a0f1a2e2937080f14280f0912151c07091e0b171a181e03270851011c000712151f1e03341d0a151a0f120d1e18141f1e070b170e1c12150814201419111e180f5b2b170e1c12153a09091a0226', 'filter', 'runClassFinishers', 'webkitVisibilityState', '2.11.0', '\\x20after\\x20decoration\\x20was\\x20finished', 'suffixes', 'completed', 'src', 'Cannot\\x20instantiate\\x20an\\x20arrow\\x20function', 'getTime', 'resultName', 'children', 'accessor.get', '484e4f4a403f52430024153c4037f00000000009d722c1e5000000d200110208150002084202110100430047001c1101014a120000070001430114000105000000003b001100011500030211010243004700553e002b140002110002120004110104070005132533000c11010312000612000703002547000700110108150002413d00241101031200064a12000807000907000a4302491101031200064a12000b0700094301494102110105430047002311010312000c3233000f11010312000d34000611010312000e4700070011010815000211010612000f11010812000203022b2f11010607000f35490842001004637c69620478697f780965626f636b62657863076362697e7e637e046f636869125d5943584d5349544f494948494853495e5e0e7f697f7f6563625f78637e6d6b69066069626b7864077f697845786961107f63616947697544697e694e75786968000a7e6961637a69457869610965626869746968484e0c5c63656278697e497a6962780e415f5c63656278697e497a6962780769627a6f636869', 'https://mssdk.bytedance.com/websdk/v1/getInfo', '?q=', '484e4f4a403f5243003e19390bcd41790000000084fc29f10000006111010012000033000d1101001200001200010700022347000303014211010112000311010112000412000326470003030142110101120005110101120006264700030301421101011200071200081101021200071200082447000303014203024200090c3125363a32123b323a3239230723363019363a32061e1105161a12083b383436233e3839062736253239230424323b3103233827063125363a3224063b323930233f', 'defineProperty', '[object\\x20Generator]', 'Wingdings', 'hasInstance', 'SHADING_LANGUAGE_VERSION', 'platform', '484e4f4a403f52430007152cc2c1a53c00000061235466970000007f1100010700022534000711000107000325340007110001070004253400071100010700052547000200423e0004140002413d002b1102021100011333001b11020211000113120006082634000c11020211000113120007082647000200424108421101014a12000011010243014a12000105000000003b0143011401000842000813717362596178466479667364626f58777b73650465797b7308757370457e77646608557370457e77646605737977667f16737941737454647961657364527f65667762757e73640f747f787259747c73756257656f78750e7f65535941737454647961657364', 'asyncIterator', 'object', 'colorDepth', 'keys', 'wrapped', 'getter', 'finalized', 'all', 'appName', 'regionConf', 'application/x-www-form-urlencoded', 'attempted\\x20to\\x20get\\x20private\\x20field\\x20on\\x20non-instance', 'createEvent', 'body', 'toElementFinisherExtras', 'open', 'displayName', '_urlRewriteRules', 'random', 'font', '484e4f4a403f52430031033191576c4000000000940c5eb50000005302110100430032470047070000110101363234000b110101120000110102373234000707000111010336340007070002110103363400070700031101033634000f0700041101033607000511010336274201420006077d61786a64637e08527d656c637962600b6e6c61615d656c637962600b525263646a6579606c7f68054c78696462184e6c637b6c7e5f686369687f64636a4e6263796875793f49', 'discharingTime', 'SimSun-ExtB', 'fromClassDescriptor', 'versions', 'charCodeAt', 'fillText', 'fetch', 'freeze', 'Create\\x20WebSocket', 'webkitRTCPeerConnection', 'digest', 'class', 'MAX_VERTEX_UNIFORM_VECTORS', 'filename', 'first', 'visibilitychange', 'A\\x20class\\x20descriptor', 'clientWidth', 'frontierSign', 'msVisibilityState', 'antialias', '484e4f4a403f5243002a3d04fa03273900000000b93145d7000004061101001200004a12000143001400011101001200024a120001430014000203001400030301140004030214000503031400060304140007030514000811000814000907000314000a07000414000b07000514000c07000614000d07000714000e07000814000f07000914001007000a1400111100014a12000b07000c430103002a34000f1100014a12000b07000d430103002a4700091100071400094500de1100014a12000b11000a430103002a4700091100031400094500c31100014a12000b11000c430103002a4700091100041400094500a81100014a12000b11000d430103002a34000f1100014a12000b07000e430103002a34000f1100014a12000b07000f430103002a4700091100051400094500691100014a12000b11000e430103002a34000f1100014a12000b11000f430103002a34000f1100014a12000b110010430103002a34000f1100014a12000b070010430103002a34000f1100014a12000b070011430103002a4700091100061400094500061100081400091100024a12000b11000b430103002a33000711000911000326470005004245012c1100024a12000b11000d430103002a34000f1100024a12000b11000c430103002a34000f1100024a12000b070012430103002a330007110009110005263300071100091100042647000500424500dd1100024a12000b110011430103002a34000f1100024a12000b11000f430103002a34000f1100024a12000b110010430103002a34000f1100024a12000b11000e430103002a3300071100091100072633000711000911000626470005004245007c1100024a12000b11000b430103002733000f1100024a12000b11000d430103002733000f1100024a12000b110011430103002733000f1100024a12000b11000e430103002733000f1100024a12000b11000f430103002733000f1100024a12000b1100104301030027140012110012110009110008252647000200420300140013030114001403021400150303140016030414001703051400181100181400191100014a12000b070013430103002a47000911001514001945008a1100014a12000b070014430103002a34000f1100014a12000b070015430103002a34000c1100014a12000b070016430147000911001414001945004e1100014a12000b070017430103002a4700091100131400194500331100014a12000b070018430103002a34000f1100014a12000b070019430103002a4700091100171400194500061100181400190211010143004a120001430014001a110019110013243300071100191100142433002111010212001a34001811010012001b4a12001c43004a12000b07001d430103002a4700020042110019110013243300071100191100142433000f11001a4a12000b07001a430103002a47000200420142001e090b0d1b0c3f191b100a0b0a113211091b0c3d1f0d1b080e121f0a18110c13070917101a11090d03091710071f101a0c11171a051217100b0606170e1611101b04170e1f1a04170e111a03131f1d0717101a1b06311809131f1d17100a110d160c131f1d210e11091b0c0e1d57041d0c110d03064f4f051d0c17110d05180617110d040e17151b0818170c1b1811065106110e1b0c1f51055e110e0c51055e110e0a51071d160c11131b51080a0c171a1b100a5104130d171b061d160c11131b06081b101a110c080a112d0a0c1710190639111119121b', 'setTTWebid', 'Buffer', '_enablePathListRegex', 'outerWidth', 'type', 'decorateElement', '484e4f4a403f524300040e131c85d3950000064d665eaab9000007ca05000001d03b0014000105000003953b00140002050000046a3b001400031102084400140004021100024300490211000343004907004b07004c07004d07004e07004f07005007005107005207005307005407005507005607005707005807005907005a07005b07005c0c001214000702110209110200110007030043031400051100050211020911020007005d1307005e0c000111000712005f43032f17000535490700600c00011400080211020911020607006113110008030043031400060d1400090211020a4300110009070062160211020b4300110009070063160211020c43001100090700641607001811020844004a1200654300181100090700661611020d4a1200671100044a12006843001d033c1b4301110009070069160211020e430011000907006a160211020f43004a120008430011000907001d1611000511000907006b1611000611000907006c1602110210430011000907006d1602110001430011000907006e1602110211430011000907006f16030114000a11021212007011000907007016021102130700714301110009070072160211021307007343011100090700741611000a1100090700751603001100090700761611021412007711000907007716110009423e000714000a030042413d01b6030014000111030007000013340014110301070001134a07000213070003430103002a47000607000445000203001400020700051103023a24470006070006450002030014000311030307000713070008134a0700091311030007000a1343014a0700021307000b430103002934002e11030007000c1333000b11030007000c1307000d1333001607000e11030007000c1307000d134a0700081343002534000711030007000f131400041100044700060700104500020300140004110004330011110301070001134a0700111307001243014700060700134500020300140005110300070014133300041100023247000607001545000203001400060211030443001400071100073233000711030007001613470006070017450002030014000807001814000911000247000b11000103012f170001354911000347000e110001030103012b2f170001354911000847000e110001030103022b2f170001354911000747000e110001030103032b2f170001354911000647000e110001030103042b2f170001354911000547000e110001030103052b2f170001354911000447000e110001030103062b2f17000135491100014241084211030512001907001a133247000c030011030512001907001a163e0010140003030111030512001907001a16413d004911030007001b1347003e11030007001b1344001400011103064a07001c1307001d43014a07001e1307001f430114000205000004103b0011000107002316070024110001070025164108423e0010140002030111040512001907001a16413d00421101024a070020131101010300030043034903001101024a0700211303000300030103014304070022130303132514000103021100011811040512001907001a164108420c000014000107002607002707002807002907002a07002b07002c07002d07002e07002f0700300700310700320700330700340700350700360700370700380700390c001414000211030107003a133247000e07003b11030512001907003c35423e001214000507003d11030512001907003c3542413d003b05000005203c021400031100024a0700481305000005c63b0243011400041103074a0700491311000443014a0700401305000005d33b0043014941084211050107003a134a07003e130d1100010e003f43014a0700401305000005523b0143014a07004513050000059e3b014301421100010700411307004248001007004348001607004448001c49450024030111030111010216450021030211030111010216450015030011030111010216450009030511030111010216084203011d110001070046134a0700021307004743012647000503044500020303110301110102160842021101031100011100024302421101014a07004a13070018430111040512001907003c35420d140001110214070078131400021100020700182447000a11000211000107007816110214070079131400031100030700182447000a11000311000107007a1611021407007b131400041100040700182447000a11000411000107007c161100014205000000003b0014000105000005eb3b0014000202110115430049021101164300490211011743004902110118430049021101194300491101034a12007d1101051200190211000143004302491101034a12007d11010512007e0211011a43004302491101034a12007d11010512007f0211011b43004302491101034a12007d1101051200800211000243004302491101141200814a120082030043011400030d1100030e00831400040700841400050211011c0211011d1100054301030a430214000611000647000e110006030118170006354945000503011400060211011e11000511000643024911000611010507001913070085161101034a12007d1100041101054302490211011f1101204a1200861100044301110121120087430214000702110122110123120088110007430214000811011212008907008a1314000911000932470002084211012447001b1101244a120040021101251100091100080d00430443014945000f021101251100091100080d004304490842008b051b0411061509010711063513111a00071d1a10110c3b1205543b24265b053b0411061509011a1011121d1a111007321d0611121b0c0904061b001b000d041108001b2700061d1a1304171518180b3c20393831181119111a000b371b1a0700060117001b060607151215061d100401071c3a1b001d121d1715001d1b1a212f1b161e1117005427151215061d2611191b00113a1b001d121d1715001d1b1a290f350404181124150d271107071d1b1a0627151215061d05191500171c0537061d3b270a371c061b1911543d3b2706171c061b191106371c061b19110a27000d18113911101d1504311013110003033d3004181b1510053d191513110d17061115001131181119111a000617151a0215070a131100371b1a00110c0002461009100615033d191513110c1311003d19151311301500150410150015061b1a181b15104e101500154e1d191513115b131d124f16150711424058264418333b30181c35253536353d35353535353535245b5b5b0d3c41363531353535353538353535353535363535313535353d3626353543030706170b13111b181b1715001d1b1a0d1a1b001d121d1715001d1b1a07040401071c04191d101d061715191106150a191d17061b041c1b1a1107070411151f11060b1011021d1711591d1a121b0f1615171f13061b011a1059070d1a170916180111001b1b001c12041106071d0700111a005907001b06151311141519161d111a0059181d131c005907111a071b060d151717111811061b191100110609130d061b07171b04110c1915131a11001b19110011060917181d04161b150610141517171107071d161d181d000d591102111a00070e17181d04161b15061059061115100f17181d04161b1506105903061d00110f04150d19111a00591c151a101811060b041106191d07071d1b1a070142031a1504014305050111060d041a15191104001c111a0507001500110604061b190400071306151a0011100610111a1d111005171500171c0719110707151311301d07541a1b005415540215181d1054111a0119540215180111541b1254000d041154241106191d07071d1b1a3a1519110319150403151818041e1b1d1a0e2c301b19151d1a261105011107000b170611150011241b040104130611191b02113102111a00381d0700111a11060d13181b16151827001b061513110c1b04111a3015001516150711091d1a10110c111030360b15000015171c3102111a000d3517001d02112c3b161e1117000d101d07041500171c3102111a000b15101036111c15021d1b06101510103102111a00381d0700111a11060b10110015171c3102111a0009121d06113102111a001039010015001d1b1a3b16071106021106133c20393839111a013d00111931181119111a00093d1a004c350606150d0b041b0700391107071513110d050111060d2711181117001b060b041106121b0619151a1711031a1b030618111a13001c0b171b1a00110c0039111a010f101b170119111a0031181119111a000c1a15001d021138111a13001c0b1e07321b1a0007381d07000b070d1a00150c3106061b0607131100201d191109001d191107001519040512181b1b0611131100201d19110e1b1a113b121207110008001d19110e1b1a11051915131d17060324061b0407061024061b0407031e07020b16061b03071106200d0411061d120615191103151d10050000171d100617181d111a000700002b07171d1005001b1f111a07190713200d04110b04061d0215170d391b101107151d10381d0700050000031d100800002b0311161d100700002311163d100b00002b0311161d102b02460900002311161d102246061507071d131a07041801131d1a070607170611111a06170107001b190e19073a1103201b1f111a381d0700060704181d171109001b1f111a381d0700040c19071d051d1a10110c090700061d1a131d120d041e071b1a0f2331362b3031223d37312b3d3a323b0a0611131d1b1a371b1a12090611041b0600210618', 'dev', '[object\\x20Function]', 'substring', '_invoke', 'getBattery', 'boeHost', 'asgw', 'Generator', 'boe', 'decorators', 'exports', 'accessor', 'plugins', 'this\\x20hasn\\x27t\\x20been\\x20initialised\\x20-\\x20super()\\x20hasn\\x27t\\x20been\\x20called', 'delegate', 'attempted\\x20to\\x20set\\x20read\\x20only\\x20static\\x20private\\x20field', 'callback=', 'MAX_TEXTURE_MAX_ANISOTROPY_EXT', 'toStringTag', ';\\x20expires=', 'match', 'root', 'setItem', 'getContextAttributes', 'withCredentials', 'Class\\x20\\x22', 'mozvisibilitychange', 'userLanguage', 'createHash', 'map', 'Cannot\\x20destructure\\x20', 'hBytes', '[object\\x20Number]', 'floor', 'access', '484e4f4a403f5243001a3309b621c6a00000000048c0ec7f000000650d14000111010012000047000c1101001200001400014500090211010143001400011101024a1200014300110001150002021101030304430114000211000202110104021101051101064a12000311000143011100024302070004430218140003110003420005077563656f6860690348495109524f4b435552474b56095552544f48414f405f40676465626360616e6f6c6d6a6b686976777475727370717e7f7c474445424340414e4f4c4d4a4b484956575455525350515e5f5c16171415121310111e1f0b08', 'MAX_COMBINED_TEXTURE_IMAGE_UNITS', 'default', 'public', 'vendorSub', 'touchstart', 'getExtension', 'Aparajita', 'finalize', 'propertyIsEnumerable', 'end', 'localStorage', '@@iterator', 'deviceMemory', 'kHttp', '@@toStringTag', 'cookieEnabled', 'fromCharCode', 'done', 'set', 'createDataChannel', 'stringify', 'async', 'Descriptor', 'hashed', 'ontouchstart', 'onicegatheringstatechange', 'getOwnPropertyDescriptors', 'then', 'function', 'CordiaUPC', 'T_CLICK', 'EXT_texture_filter_anisotropic', 'MS\\x20Outlook', '80pSJSjK', 'Jokerman', 'byted_acrawler', 'visibilityState', 'span', 'isWebmssdk', '__web_idontknowwhyiwriteit__', 'cpuClass', 'serif', 'initialized', 'accessor\\x20decorators\\x20must\\x20return\\x20an\\x20object\\x20with\\x20get,\\x20set,\\x20or\\x20init\\x20properties\\x20or\\x20void\\x200', '[object\\x20HTMLAllCollection]', 'Decorating\\x20class\\x20property\\x20failed.\\x20Please\\x20ensure\\x20that\\x20proposal-class-properties\\x20is\\x20enabled\\x20and\\x20runs\\x20after\\x20the\\x20decorators\\x20transform.', '\\x27\\x20to\\x20be\\x20a\\x20function', 'VERSION', 'toLowerCase', 'MAX_TEXTURE_SIZE', 'triggerUnload', 'MAX_VERTEX_TEXTURE_IMAGE_UNITS', 'element', 'apply', 'document', 'exec', 'send', ')\\x20can\\x27t\\x20be\\x20decorated.', 'min', '484e4f4a403f5243002814122ddd79950000009eb285a1cb000000e811000114000402110201110001430147007c1102021200041400051100050700052347000f0700061102021200060c00024500120700061102021200060700041100050c0004140006021102030211020411000143011100064302140007021102051100074301140008021102061100080700054302140009021102031100071101011100090c000243021400040211010211000411000211000343034205000000003b03140003070000140001110100120001082334000611010012000247000208421101001200011400021100021101001500030011010015000211000311010015000108420007070d78173a322026043a25303b150a0a34360a3c3b2130273630252130310a3a25303b050a3a25303b0b0a0a34360a213026213c3100073826013a3e303b', 'vivobrowser', 'descriptor', 'language', '484e4f4a403f524300023a25866a0150000000002b0aa01b000001541101001200004a12000143001400011100014a120002070003430103002a47000201420700041400021101013a070004254700060700044500090211010211010143011100022534000d1101014a1200054300070006263400161101031200071200054a12000811010143010700062634001e1101043a07000425470006070004450009021101021101044301110002253400151101044a12000543004a120002070009430103002734001e1101003a070004254700060700044500090211010211010043011100022534000d1101004a120005430007000a263400121101001200004a12000207000b430103002a34001e1101053a07000425470006070004450009021101021101054301110002254700020042021101064300324700331101073a070004254700060700044500090211010211010743011100022534000d1101074a120005430007000c2647000200420142000d096f697f685b7d7f746e0b6e7556756d7f68597b697f0773747e7f62557c087f767f796e687574096f747e7f7c73747f7e086e75496e6873747d0f417578707f796e3a4d73747e756d47096a68756e756e636a7f04797b7676085e75796f777f746e12417578707f796e3a547b6c737d7b6e7568470570697e757710417578707f796e3a5273696e75686347', 'vendor', 'level', 'attempted\\x20to\\x20call\\x20', 'placement', 'JS_MD5_NO_NODE_JS', 'initializeClassElements', 'indexedDB', 'perf', 'disallowProperty', 'lime', '484e4f4a403f524300341b3e336a785800000000dbd5951f000001b50114000111010012000000254700070014000145001b1101001200000125470007011400014500090211010143001400010d010e0001010e0002010e00031100010e0004010e0005010e0006010e0007010e0008010e0009010e000a010e000b000e000c1400020211010243001100021500051100021200053247005c021101031100024301490211010411000243014902110105430011000215000702110106430011000215000802110107430011000215000902110108430011000215000b0211010943001100021500030211010a4300110002150002030014000311000303012f170003354911000311000212000b03012b2f170003354911000311000212000a03022b2f170003354911000311000212000903032b2f170003354911000311000212000803042b2f170003354911000311000212000703052b2f17000335491100031100020700061303062b2f170003354911000311000212000503072b2f17000335491100031100020700041303082b2f170003354911000311000212000303092b2f1700033549110003110002120002030a2b2f170003354911010b12000d1100032f11010b07000d354911000242000e0e547b6a796a66587c627f686344650a6f62796e687f58626c650a6864657862787f6e657f086764686a7f62646506787c627f6863036f6466086f6e697e6c6c6e790465646f6e077b636a657f6466097c6e696f79627d6e7909626568646c65627f640463646460047f6e787f076e657d68646f6e', 'moveList', 'MYRIAD\\x20PRO', 'An\\x20element\\x20descriptor', 'finallyLoc', 'head', 'innerHeight', 'ORIGIN:\\x20', 'region', 'addInitializer', '[object\\x20SafariRemoteNotification]', 'candidate', 'content-type', 'userAgent', 'webkitHidden', 'test', 'getPrototypeOf', 'setDate', 'shiftKey', 'accessor.init', '@@asyncIterator', 'accessor.set'];\n        w_0x42f5 = function () {\n            return _0x458f30;\n        }\n        ;\n        return w_0x42f5();\n    }\n\n    function w_0x5c3140(_0x41676a, _0x3f9548, _0x39b0b8) {\n        var _0x2145df = w_0x25f3;\n\n        function _0x467cb0(_0x174e0d, _0x4ea737) {\n            var _0x569e4c = w_0x25f3\n                ,\n                _0x3ed868 = parseInt(_0x174e0d[_0x569e4c(0x2a5)](_0x4ea737, _0x4ea737 + (0x30 * 0x1a + 0x1 * 0x1424 + -0xc2 * 0x21)), -0x253b + -0x1ce1 + -0x974 * -0x7);\n            return _0x3ed868 >>> 0x23ca + 0x882 + 0x2c45 * -0x1 == 0x11cb + -0x5c7 * 0x3 + 0x2 * -0x3b ? [-0xc * 0x300 + 0x1 * 0x1067 + 0x139a, _0x3ed868] : _0x3ed868 >>> -0x3 * 0x3b9 + 0x4a * 0x75 + -0x16a1 == -0x742 + -0x429 + 0xb6d ? (_0x3ed868 = (-0x1eee + 0x1175 + 0xdb8 & _0x3ed868) << 0x2 * 0x108d + 0x2 * -0x5e6 + 0x1 * -0x1546,\n                [-0x949 + 0xe2f + -0x4 * 0x139, _0x3ed868 += parseInt(_0x174e0d['slice'](_0x4ea737 + (0x5 * -0x643 + -0x1 * 0x95 + -0x1fe6 * -0x1), _0x4ea737 + (0x9b6 + 0x8 * 0x24a + -0x1c02)), -0xa6 * 0x11 + -0x3f * -0x1 + 0x6f * 0x19)]) : (_0x3ed868 = (0x1af1 + 0x1442 + -0x964 * 0x5 & _0x3ed868) << 0x3f3 + -0xd93 + 0x9b0,\n                [-0x13 * -0x192 + -0x1588 + 0xc1 * -0xb, _0x3ed868 += parseInt(_0x174e0d[_0x569e4c(0x2a5)](_0x4ea737 + (-0x8 * 0x39c + 0x59 * 0x35 + 0x1 * 0xa75), _0x4ea737 + (0x1 * -0xad6 + -0x326 + 0x16 * 0xa3)), 0x20b0 + -0x7d + -0x1b1 * 0x13)]);\n        }\n\n        var _0x450bf1, _0x55d729 = 0x242c + 0x150c * 0x1 + -0x4 * 0xe4e, _0x26f45f = [], _0x408609 = [],\n            _0x5e254d = parseInt(_0x41676a[_0x2145df(0x2a5)](-0x43 * 0x7a + 0xbac * -0x1 + 0x2 * 0x15cd, -0x18c6 + -0x1515 + 0x2de3), -0x17e6 + 0x4 * -0x269 + 0x1fa * 0x11),\n            _0x56844b = parseInt(_0x41676a[_0x2145df(0x2a5)](0x262 * -0x3 + 0x19e0 + -0x12b2, 0x5 * 0x3e + 0xd * -0x2ec + -0x73 * -0x52), 0x1 * 0xd69 + 0x1 * 0xb9 + -0xe12);\n        if (-0x5eec40a * 0xd + 0x353b2368 + 0x60332064 !== _0x5e254d || 0x7b7 * 0x44245 + -0x712c7271 + 0x1ce9b3ad * 0x5 !== _0x56844b)\n            throw new Error(_0x2145df(0x2a7));\n        if (0x2 * 0xae1 + -0x1e47 + 0x885 !== parseInt(_0x41676a[_0x2145df(0x2a5)](0x1 * 0x45 + 0x149 * -0x1 + 0x114, -0x1d69 * -0x1 + 0xf47 * 0x1 + -0x2c9e), -0x59 * 0x4b + -0xfdb + -0xd7 * -0x32))\n            throw new Error('ve');\n        for (_0x450bf1 = 0x2 * 0xe7d + -0xdf * -0x19 + 0x3d * -0xd5; _0x450bf1 < -0x22db * -0x1 + -0xf98 * -0x1 + -0x1 * 0x326f; ++_0x450bf1) {\n            _0x55d729 += (-0x1a7 * 0x3 + 0x17 * -0x47 + 0xb59 & parseInt(_0x41676a[_0x2145df(0x2a5)](0x751 * -0x4 + 0x1d * 0xfd + 0xb3 + (-0x44b * 0x7 + -0x100 + 0x1f0f) * _0x450bf1, 0x8 * 0x3ae + 0x128d + -0xd * 0x3af + (0x2 * -0x80f + -0xd * 0x24a + 0x2de2) * _0x450bf1), -0x14d6 + -0x255 + 0x173b)) << (-0x1ce2 * -0x1 + 0x11e3 + -0x2ec3) * _0x450bf1;\n        }\n        var _0x537efa = parseInt(_0x41676a[_0x2145df(0x2a5)](0x13 * -0x209 + 0x116b + 0xc * 0x1c8, -0x26a0 + 0x10d * -0x12 + 0x39b2), 0x154e + -0x25e * -0xf + 0xe3 * -0x40)\n            ,\n            _0x3d66d8 = (0x1bdb * 0x1 + -0x4e9 * 0x3 + -0xd1e) * parseInt(_0x41676a[_0x2145df(0x2a5)](-0x1 * -0x24f5 + 0x2279 + 0x67a * -0xb, -0x2 * -0x1083 + -0x5 * 0x185 + 0xef * -0x1b), -0x82 + 0x8e6 + 0x4 * -0x215);\n        for (_0x450bf1 = -0x2471 + -0x116 * -0x7 + 0x1d0f * 0x1; _0x450bf1 < _0x3d66d8 + (-0x1c * -0x106 + 0x370 + -0x8 * 0x3fc); _0x450bf1 += 0x13ac * 0x1 + 0x9bd * 0x1 + -0x1 * 0x1d67)\n            _0x26f45f[_0x2145df(0x36e)](parseInt(_0x41676a[_0x2145df(0x2a5)](_0x450bf1, _0x450bf1 + (0x7 * 0x539 + 0x3cb * -0x2 + -0x1 * 0x1cf7)), 0x23fc + -0xa45 + -0x3 * 0x88d));\n        var _0x50f001 = _0x3d66d8 + (-0x1429 + -0x69d * -0x1 + 0x371 * 0x4)\n            ,\n            _0x23f32e = parseInt(_0x41676a[_0x2145df(0x2a5)](_0x50f001, _0x50f001 + (-0x179c + -0x3f + -0x61 * -0x3f)), -0x2a * 0x65 + -0x20e5 + 0x3187);\n        for (_0x50f001 += -0x20c6 + 0x3 * -0x1a5 + 0x25b9,\n                 _0x450bf1 = -0x2 * -0x766 + 0x127e + -0x214a; _0x450bf1 < _0x23f32e; ++_0x450bf1) {\n            var _0x37a7c1 = _0x467cb0(_0x41676a, _0x50f001);\n            _0x50f001 += (0xcfd + 0x399 * -0x3 + -0x7 * 0x50) * _0x37a7c1[-0x14ee + -0x912 + 0x1e00];\n            for (var _0x13d988 = '', _0x4b0c3a = -0x1bcf + 0x16cf + 0x10 * 0x50; _0x4b0c3a < _0x37a7c1[-0x476 * 0x3 + -0x112b + 0x2 * 0xf47]; ++_0x4b0c3a) {\n                var _0x49abb4 = _0x467cb0(_0x41676a, _0x50f001);\n                _0x13d988 += String[_0x2145df(0x1e2)](_0x55d729 ^ _0x49abb4[0x18f1 * -0x1 + -0x17e5 * 0x1 + -0x30d7 * -0x1]),\n                    _0x50f001 += (0x2dd * -0xd + -0x8 * 0x227 + 0x3673) * _0x49abb4[-0xd9 + 0x1702 + -0x763 * 0x3];\n            }\n            _0x408609['push'](_0x13d988);\n        }\n        return _0x3f9548['p'] = null,\n            function _0x970e7(_0x3e87c6, _0x536685, _0xecd4ef, _0x5acf67, _0x560641) {\n                var _0x261736 = _0x2145df, _0x1fc1ed, _0x281ec0, _0x5c0f33, _0xd55c82, _0x37b70b,\n                    _0x12cd72 = -(0x1bdd + -0x8 * 0x116 + -0x3 * 0x664), _0x27fcf3 = [],\n                    _0x42ef1a = [-0x5 * -0x2b6 + 0x1d6c + -0x2afa, null], _0x428c87 = null, _0x4444cf = [_0x536685];\n                for (_0x281ec0 = Math['min'](_0x536685[_0x261736(0x259)], _0xecd4ef),\n                         _0x5c0f33 = -0x90b + -0x1 * 0x1e2f + 0x273a; _0x5c0f33 < _0x281ec0; ++_0x5c0f33)\n                    _0x4444cf[_0x261736(0x36e)](_0x536685[_0x5c0f33]);\n                _0x4444cf['p'] = _0x5acf67;\n                for (var _0x4b7ccd = []; ;)\n                    try {\n                        var _0x5cd5b9 = _0x26f45f[_0x3e87c6++];\n                        if (_0x5cd5b9 < -0x788 + 0x18c7 + 0x1 * -0x1118) {\n                            if (_0x5cd5b9 < 0x208d + -0x1031 + -0x1049 * 0x1) {\n                                if (_0x5cd5b9 < 0x1a1c + -0xbff * 0x3 + 0x27a * 0x4)\n                                    _0x5cd5b9 < 0x3ee + 0x1 * 0x21c3 + -0x2e6 * 0xd ? _0x27fcf3[++_0x12cd72] = _0x5cd5b9 < -0x61 * 0x61 + 0x1115 + 0x13ad || -0x1d * -0x4f + 0x11c9 + 0x3 * -0x8e9 !== _0x5cd5b9 && null : _0x5cd5b9 < -0x783 + 0xa0d + -0x285 ? -0xb * 0x24f + 0x141a + 0x54e === _0x5cd5b9 ? (_0x1fc1ed = _0x26f45f[_0x3e87c6++],\n                                        _0x27fcf3[++_0x12cd72] = _0x1fc1ed << 0x12b * 0x1f + 0x5 * 0x70c + -0x4759 >> -0x352 + 0x7 * 0x58f + -0x237f) : (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0xb02 + 0x2af + -0xda9) + _0x26f45f[_0x3e87c6 + (0x220e + 0x1 * -0x1175 + -0x1098)],\n                                        _0x3e87c6 += -0x325 * 0x3 + 0xafe + -0x18d,\n                                        _0x27fcf3[++_0x12cd72] = _0x1fc1ed << -0xe7c * -0x1 + -0xe17 * -0x2 + -0x2a9a >> -0x23ae * 0x1 + -0x1f8f + -0x434d * -0x1) : -0xa * 0x15c + 0x24bc + -0x1 * 0x171f === _0x5cd5b9 ? (_0x1fc1ed = ((_0x1fc1ed = ((_0x1fc1ed = _0x26f45f[_0x3e87c6++]) << -0x1f87 + -0xda8 + 0x2d37) + _0x26f45f[_0x3e87c6++]) << -0x1d32 + -0x2 * 0x124 + 0x1f82) + _0x26f45f[_0x3e87c6++],\n                                        _0x27fcf3[++_0x12cd72] = (_0x1fc1ed << 0xc * -0x8 + -0x25f7 + 0x265f) + _0x26f45f[_0x3e87c6++]) : (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x1bf7 + 0x4e9 * 0x7 + -0xc76 * 0x5) + _0x26f45f[_0x3e87c6 + (0xba7 + -0x1611 + 0xa6b)],\n                                        _0x3e87c6 += 0xa1e + -0x1a21 + 0x557 * 0x3,\n                                        _0x27fcf3[++_0x12cd72] = +_0x408609[_0x1fc1ed]);\n                                else {\n                                    if (_0x5cd5b9 < 0x369 * -0x9 + 0x20de + -0x220)\n                                        _0x5cd5b9 < -0x2626 + 0x336 * -0x5 + 0x363f ? 0x12b * -0x15 + -0x2 * -0x11f5 + 0x5ae * -0x2 === _0x5cd5b9 ? (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x8 * 0x2 + 0x35 * 0x18 + -0x500) + _0x26f45f[_0x3e87c6 + (-0x330 + -0xec * -0x5 + -0x16b)],\n                                            _0x3e87c6 += 0x224 + -0x19 * -0xb3 + -0x1 * 0x139d,\n                                            _0x27fcf3[++_0x12cd72] = _0x408609[_0x1fc1ed]) : _0x27fcf3[++_0x12cd72] = void (0x5 * 0x1ef + 0x2493 * -0x1 + -0x35d * -0x8) : 0x1abb + 0x191 * 0xd + -0x3 * 0xfaf === _0x5cd5b9 ? _0x27fcf3[++_0x12cd72] = _0x560641 : (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << -0x20b0 + -0x3da + 0x2492) + _0x26f45f[_0x3e87c6 + (-0x129d * 0x1 + 0x1 * -0x2316 + 0x35b4)],\n                                            _0x3e87c6 += -0xcb8 + 0x1bb * -0xa + -0x2 * -0xf04,\n                                            _0x12cd72 = _0x12cd72 - _0x1fc1ed + (0xb3 * 0x1 + -0x2018 * 0x1 + 0x1 * 0x1f66),\n                                            _0x281ec0 = _0x27fcf3[_0x261736(0x2a5)](_0x12cd72, _0x12cd72 + _0x1fc1ed),\n                                            _0x27fcf3[_0x12cd72] = _0x281ec0);\n                                    else {\n                                        if (_0x5cd5b9 < 0x2 * -0xf38 + 0xdd0 + 0x10b1)\n                                            -0x15d2 + 0x26f0 + 0x11 * -0x101 === _0x5cd5b9 ? _0x27fcf3[++_0x12cd72] = {} : (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << -0x9ac + 0x1201 * 0x1 + -0x84d) + _0x26f45f[_0x3e87c6 + (0x1ecb + -0x1bdd + 0x7 * -0x6b)],\n                                                _0x3e87c6 += 0x6a4 + -0x922 + 0x280,\n                                                _0x281ec0 = _0x408609[_0x1fc1ed],\n                                                _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                                _0x27fcf3[_0x12cd72][_0x281ec0] = _0x5c0f33);\n                                        else {\n                                            if (0x17 * -0xc3 + 0x1da5 + 0x3 * -0x405 === _0x5cd5b9) {\n                                                for (_0x281ec0 = _0x26f45f[_0x3e87c6++],\n                                                         _0x5c0f33 = _0x26f45f[_0x3e87c6++],\n                                                         _0xd55c82 = _0x4444cf; _0x281ec0 > -0x3 * 0x4ba + -0x12 * 0xb1 + 0x1aa0; --_0x281ec0)\n                                                    _0xd55c82 = _0xd55c82['p'];\n                                                _0x27fcf3[++_0x12cd72] = _0xd55c82[_0x5c0f33];\n                                            } else\n                                                _0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x15c3 + -0x453 + -0x1168) + _0x26f45f[_0x3e87c6 + (-0x1f3f * 0x1 + 0x1f6a + 0x6 * -0x7)],\n                                                    _0x3e87c6 += 0x1 * -0x1f4e + -0x118f * 0x1 + 0x30df,\n                                                    _0x281ec0 = _0x408609[_0x1fc1ed],\n                                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72][_0x281ec0];\n                                        }\n                                    }\n                                }\n                            } else {\n                                if (_0x5cd5b9 < -0xf5c + -0x6d7 + 0x164e) {\n                                    if (_0x5cd5b9 < 0xc8 * -0x2f + 0xee * -0x9 + -0xf * -0x303) {\n                                        if (_0x5cd5b9 < 0x1 * -0x2426 + 0x224e + 0x11 * 0x1d) {\n                                            if (-0xb15 + 0x2d5 * 0x1 + -0x853 * -0x1 === _0x5cd5b9)\n                                                _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72][_0x281ec0];\n                                            else {\n                                                for (_0x281ec0 = _0x26f45f[_0x3e87c6++],\n                                                         _0x5c0f33 = _0x26f45f[_0x3e87c6++],\n                                                         _0xd55c82 = _0x4444cf; _0x281ec0 > 0x2 * -0x11b8 + 0x240a + -0x9a; --_0x281ec0)\n                                                    _0xd55c82 = _0xd55c82['p'];\n                                                _0xd55c82[_0x5c0f33] = _0x27fcf3[_0x12cd72--];\n                                            }\n                                        } else\n                                            0x1 * 0x17f1 + 0x115 * -0x9 + 0x2d3 * -0x5 === _0x5cd5b9 ? (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x16ff + 0x158a + -0x2c81 * 0x1) + _0x26f45f[_0x3e87c6 + (0x88f * -0x3 + 0x1c82 + 0x16a * -0x2)],\n                                                _0x3e87c6 += 0x1 * -0xa7 + 0x18d4 + 0x1 * -0x182b,\n                                                _0x281ec0 = _0x408609[_0x1fc1ed],\n                                                _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                                _0xd55c82 = _0x27fcf3[_0x12cd72--],\n                                                _0x5c0f33[_0x281ec0] = _0xd55c82) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                                _0xd55c82 = _0x27fcf3[_0x12cd72--],\n                                                _0x5c0f33[_0x281ec0] = _0xd55c82);\n                                    } else {\n                                        if (_0x5cd5b9 < -0x19f3 + 0x1c6b + -0x25f) {\n                                            if (0x1b * -0xbd + -0x84a * -0x2 + -0x126 * -0x3 === _0x5cd5b9) {\n                                                for (_0x281ec0 = _0x26f45f[_0x3e87c6++],\n                                                         _0x5c0f33 = _0x26f45f[_0x3e87c6++],\n                                                         _0xd55c82 = _0x4444cf,\n                                                         _0xd55c82 = _0x4444cf; _0x281ec0 > 0x3 * -0x65a + 0xe28 + 0x4e6; --_0x281ec0)\n                                                    _0xd55c82 = _0xd55c82['p'];\n                                                _0x27fcf3[++_0x12cd72] = _0xd55c82,\n                                                    _0x27fcf3[++_0x12cd72] = _0x5c0f33;\n                                            } else\n                                                _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                    _0x27fcf3[_0x12cd72] += _0x281ec0;\n                                        } else\n                                            0x44b * -0x9 + 0x61 * -0xa + -0x2a86 * -0x1 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                _0x27fcf3[_0x12cd72] -= _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                _0x27fcf3[_0x12cd72] *= _0x281ec0);\n                                    }\n                                } else\n                                    _0x5cd5b9 < 0x3 * -0x7ce + 0x907 * -0x1 + -0x1 * -0x2094 ? _0x5cd5b9 < 0xa68 + -0xc5f + 0x214 ? 0x3e * -0x7d + 0x13d1 + 0xa90 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] /= _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] %= _0x281ec0) : -0x171d * -0x1 + -0x6a2 * -0x3 + -0x2ae6 === _0x5cd5b9 ? _0x27fcf3[_0x12cd72] = -_0x27fcf3[_0x12cd72] : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[++_0x12cd72] = _0x5c0f33[_0x281ec0]++) : _0x5cd5b9 < 0x2565 + -0x2 * -0xd76 + -0x1bc * 0x25 ? 0x951 + 0x13da + -0x1d08 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] == _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] != _0x281ec0) : -0x144c * -0x1 + 0xd01 + -0x2128 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] === _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] !== _0x281ec0);\n                            }\n                        } else {\n                            if (_0x5cd5b9 < -0x3bb + 0xdb6 + -0x9c2 * 0x1)\n                                _0x5cd5b9 < -0xe16 + -0x2 * -0x409 + 0x633 ? _0x5cd5b9 < 0x1 * 0xeea + -0x3 * 0x863 + 0x2b * 0x3e ? _0x5cd5b9 < -0x2f * -0x15 + 0x185 * 0x2 + -0x35e * 0x2 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] < _0x281ec0) : -0x2152 + -0x1853 + 0x39ce === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] > _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >= _0x281ec0) : _0x5cd5b9 < 0x3 * -0x822 + 0xc76 + 0x1bb * 0x7 ? 0x20ae + -0x21ca + -0x6d * -0x3 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] << _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >> _0x281ec0) : -0x10 * 0x1a + -0x1431 + 0xa * 0x233 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >>> _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] & _0x281ec0) : _0x5cd5b9 < 0x1 * 0x1ca7 + 0x1ea1 * 0x1 + -0x31c * 0x13 ? _0x5cd5b9 < -0xa63 * -0x2 + -0x114d + -0x1 * 0x347 ? -0x12b5 + -0x153 * 0x4 + 0x8 * 0x306 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] | _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] ^ _0x281ec0) : -0xab + 0x10c1 + 0x9 * -0x1c4 === _0x5cd5b9 ? _0x27fcf3[_0x12cd72] = !_0x27fcf3[_0x12cd72] : (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x9 * -0xd0 + -0x1 * -0xa04 + 0x2 * -0x156) + _0x26f45f[_0x3e87c6 + (0xa6a + 0x113c + 0x1ba5 * -0x1)]) << 0x2 * -0x41b + -0x1bf1 + 0x7f * 0x49 >> -0x1bc0 + 0x232e + -0x75e,\n                                    _0x3e87c6 += -0x62 * 0x31 + 0x26b * 0x7 + 0x1d7 * 0x1,\n                                    _0x27fcf3[_0x12cd72] ? --_0x12cd72 : _0x3e87c6 += _0x1fc1ed) : _0x5cd5b9 < 0x8 * 0x493 + -0x6c * 0x49 + 0x1a * -0x37 ? -0x21 * 0x1 + -0x3 * -0xc19 + 0x2 * -0x11fb === _0x5cd5b9 ? (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << -0x2 * 0x11ff + 0x9d3 + 0x1a33) + _0x26f45f[_0x3e87c6 + (0x1ba6 + -0x134f * -0x1 + -0x2ef4)]) << 0x10dc * -0x1 + -0x1130 + 0x221c >> -0x5 * 0x685 + 0x1a23 + 0x686,\n                                    _0x3e87c6 += 0x4 * 0xf9 + -0x21c5 + 0x1de3,\n                                    _0x27fcf3[_0x12cd72] ? _0x3e87c6 += _0x1fc1ed : --_0x12cd72) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    (_0x5c0f33 = _0x27fcf3[_0x12cd72--])[_0x281ec0] = _0x27fcf3[_0x12cd72]) : -0x5 * -0x65c + 0x15 * 0x17b + -0x3ead === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] in _0x281ec0) : (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                    _0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] instanceof _0x281ec0);\n                            else {\n                                if (_0x5cd5b9 < 0x52 + 0x7 * 0x102 + -0x2 * 0x38f) {\n                                    if (_0x5cd5b9 < -0x1887 + -0x303 + 0x1bc7)\n                                        _0x5cd5b9 < 0x2132 + -0x592 * 0x2 + -0x15d3 ? -0x136b + -0x21cd + 0x3571 * 0x1 === _0x5cd5b9 ? (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                            _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                            _0x27fcf3[++_0x12cd72] = delete _0x5c0f33[_0x281ec0]) : _0x27fcf3[_0x12cd72] = typeof _0x27fcf3[_0x12cd72] : 0xeed * 0x1 + -0xa1e + 0x2 * -0x24a === _0x5cd5b9 ? (_0x1fc1ed = _0x26f45f[_0x3e87c6++],\n                                            _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                            (_0x5c0f33 = function _0x3b7712() {\n                                                    var _0x295f58 = _0x3b7712['_u']\n                                                        , _0x29116a = _0x3b7712['_v'];\n                                                    return _0x295f58(_0x29116a[0x28c * 0x4 + -0x6 * 0x1d6 + 0xd4], arguments, _0x29116a[0x1d72 * 0x1 + 0x7b * -0x1b + -0x1078], _0x29116a[0x11e6 + 0x1a1f * -0x1 + 0x83b], this);\n                                                }\n                                            )['_v'] = [_0x281ec0, _0x1fc1ed, _0x4444cf],\n                                            _0x5c0f33['_u'] = _0x970e7,\n                                            _0x27fcf3[++_0x12cd72] = _0x5c0f33) : (_0x1fc1ed = _0x26f45f[_0x3e87c6++],\n                                            _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                            (_0xd55c82 = [_0x5c0f33 = function _0x465123() {\n                                                var _0x2f6d57 = _0x465123['_u']\n                                                    , _0x399ae1 = _0x465123['_v'];\n                                                return _0x2f6d57(_0x399ae1[-0x113b + 0xb * 0x71 + 0xc60], arguments, _0x399ae1[0xa13 + 0x24b0 + -0x9 * 0x532], _0x399ae1[0x1 * 0x463 + -0x56 * -0x49 + -0x1ce7], this);\n                                            }\n                                            ])['p'] = _0x4444cf,\n                                            _0x5c0f33['_v'] = [_0x281ec0, _0x1fc1ed, _0xd55c82],\n                                            _0x5c0f33['_u'] = _0x970e7,\n                                            _0x27fcf3[++_0x12cd72] = _0x5c0f33);\n                                    else {\n                                        if (_0x5cd5b9 < 0x62 * -0xd + 0xae3 + -0x5a9)\n                                            0x9d1 * -0x1 + 0x2425 + -0x1 * 0x1a17 === _0x5cd5b9 ? (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0xd1 * 0x2 + -0xe5 * 0x7 + 0x4a9) + _0x26f45f[_0x3e87c6 + (0x33a + -0xb14 + 0x7db * 0x1)]) << -0xb * -0xde + 0x1199 + -0x1b13 >> -0xa3d + 0xc * 0x2aa + -0x15ab,\n                                                _0x3e87c6 += -0x2f * 0x3 + 0x2 * 0x9a3 + -0x12b7,\n                                                (_0x281ec0 = _0x4b7ccd[_0x4b7ccd['length'] - (0x427 + 0xa54 + -0xda * 0x11)])[0x5d4 + 0x14f2 + -0x4d * 0x59] = _0x3e87c6 + _0x1fc1ed) : (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x349 * -0x2 + 0xa4 * -0x17 + 0x1556) + _0x26f45f[_0x3e87c6 + (-0x86 * -0x2 + -0x1c9 + -0xbe * -0x1)]) << 0x14bf + -0x1aec + -0x1 * -0x63d >> 0x2 * 0x17b + -0x1e3c + 0x1b56,\n                                                _0x3e87c6 += -0x1 * -0x1052 + 0x10 * -0x17e + 0x790,\n                                                (_0x281ec0 = _0x4b7ccd[_0x4b7ccd['length'] - (-0x1ad2 + 0x1b9 * 0x2 + 0x39 * 0x69)]) && !_0x281ec0[-0x3 * 0xe8 + -0x5 * -0x142 + -0x1 * 0x391] ? (_0x281ec0[0x25 * -0x7a + 0x21ec + -0x104a] = 0x7bf + -0x3 * -0xa43 + -0x2685,\n                                                    _0x281ec0[_0x261736(0x36e)](_0x3e87c6)) : _0x4b7ccd[_0x261736(0x36e)]([-0x1d * 0x82 + -0x11f4 + 0x20af, 0x15ac + -0x399 * -0x9 + -0x360d, _0x3e87c6]),\n                                                _0x3e87c6 += _0x1fc1ed);\n                                        else {\n                                            if (0x2263 * -0x1 + -0x689 + 0x292c === _0x5cd5b9)\n                                                throw _0x281ec0 = _0x27fcf3[_0x12cd72--];\n                                            if (_0x5c0f33 = (_0x281ec0 = _0x4b7ccd['pop']())[0x1 * 0x6a1 + 0x1ceb + -0x238c],\n                                                _0xd55c82 = _0x42ef1a[-0x1b8 + 0x1d25 + -0x3eb * 0x7],\n                                            0x751 * 0x1 + -0xa4b + 0x7 * 0x6d === _0x5c0f33)\n                                                _0x3e87c6 = _0x281ec0[0x1 * 0x8e + 0x128c + -0x1319];\n                                            else {\n                                                if (0x11f4 + 0x3 * 0x95 + -0x13b3 === _0x5c0f33) {\n                                                    if (-0x2607 + -0xdc8 + -0x1145 * -0x3 === _0xd55c82)\n                                                        _0x3e87c6 = _0x281ec0[-0x262 + -0x12bf * -0x2 + 0x13 * -0x1d9];\n                                                    else {\n                                                        if (0x6d * 0x2 + 0x2ff * -0x9 + 0x1a1e !== _0xd55c82)\n                                                            throw _0x42ef1a[0x3 * 0xced + 0x1dd7 + 0x16df * -0x3];\n                                                        if (!_0x428c87)\n                                                            return _0x42ef1a[0x21b7 + 0x20a5 * -0x1 + -0x5b * 0x3];\n                                                        _0x3e87c6 = _0x428c87[-0x4bd + -0x3 * -0x353 + 0x53b * -0x1],\n                                                            _0x560641 = _0x428c87[0x149e + 0x1 * -0x751 + -0xd4b],\n                                                            _0x4444cf = _0x428c87[-0x2 * 0x94d + -0x7bf * -0x1 + 0x2 * 0x56f],\n                                                            _0x4b7ccd = _0x428c87[0x15c3 * 0x1 + -0x4 * 0x82e + -0x35 * -0x35],\n                                                            _0x27fcf3[++_0x12cd72] = _0x42ef1a[0x3 * 0xaf3 + -0x983 + -0x1755],\n                                                            _0x42ef1a = [-0x1c1c + -0x14c * 0x1a + 0x3dd4, null],\n                                                            _0x428c87 = _0x428c87[0x1a3 + 0x1 * -0x1e23 + 0x1c80];\n                                                    }\n                                                } else\n                                                    _0x3e87c6 = _0x281ec0[-0x1 * -0x953 + 0x159 * 0x1 + -0xaaa],\n                                                        _0x281ec0[0x26ad * -0x1 + 0x2 * -0xe4b + 0x4343] = 0x100d + -0x19cc + 0x5 * 0x1f3,\n                                                        _0x4b7ccd[_0x261736(0x36e)](_0x281ec0);\n                                            }\n                                        }\n                                    }\n                                } else {\n                                    if (_0x5cd5b9 < 0x195 + -0x3b * -0x9d + -0x3 * 0xc7f) {\n                                        if (_0x5cd5b9 < 0xd * -0x1 + 0x229 + -0x1d8) {\n                                            if (-0x949 + 0x13f8 + -0xa6d === _0x5cd5b9) {\n                                                for (_0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                         _0x5c0f33 = null; _0xd55c82 = _0x4b7ccd[_0x261736(0x267)]();)\n                                                    if (0x1e97 + 0x31 * -0x5e + -0xc97 === _0xd55c82[0x150 + 0x6 * 0x645 + -0x26ee] || 0xb29 * -0x3 + -0x333 * 0x3 + 0x2b17 === _0xd55c82[0x1 * -0x22c2 + -0x187b + 0x3b3d]) {\n                                                        _0x5c0f33 = _0xd55c82;\n                                                        break;\n                                                    }\n                                                if (_0x5c0f33)\n                                                    _0x42ef1a = [-0x11 * 0x14d + 0x1492 * 0x1 + 0x18c, _0x281ec0],\n                                                        _0x3e87c6 = _0x5c0f33[0xc28 * -0x3 + -0x8 * 0x4e1 + 0x4b82],\n                                                        _0x5c0f33[0x51e * 0x1 + 0x755 * -0x5 + 0x1f8b] = 0x1875 * 0x1 + 0x146 + -0x19bb,\n                                                        _0x4b7ccd[_0x261736(0x36e)](_0x5c0f33);\n                                                else {\n                                                    if (!_0x428c87)\n                                                        return _0x281ec0;\n                                                    _0x3e87c6 = _0x428c87[0x1 * 0x15be + -0x2639 + 0x107c],\n                                                        _0x560641 = _0x428c87[-0x1 * 0xe1e + 0x2042 + 0x2 * -0x911],\n                                                        _0x4444cf = _0x428c87[0x25fd + 0x1cfe + -0x42f8],\n                                                        _0x4b7ccd = _0x428c87[0x3 * 0xa76 + 0x17ce + -0x372c],\n                                                        _0x27fcf3[++_0x12cd72] = _0x281ec0,\n                                                        _0x42ef1a = [-0x7 * 0x4a6 + -0x12d3 + -0x3 * -0x111f, null],\n                                                        _0x428c87 = _0x428c87[-0x29 * 0x1e + 0x9d * -0x2f + 0x21a1];\n                                                }\n                                            } else\n                                                _0x12cd72 -= _0x1fc1ed = _0x26f45f[_0x3e87c6++],\n                                                    _0x5c0f33 = _0x27fcf3['slice'](_0x12cd72 + (0xf4f * -0x1 + 0x1af9 * 0x1 + -0xba9), _0x12cd72 + _0x1fc1ed + (0x230 + 0x1e17 * -0x1 + 0x6fa * 0x4)),\n                                                    _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                                    _0xd55c82 = _0x27fcf3[_0x12cd72--],\n                                                    _0x281ec0['_u'] === _0x970e7 ? (_0x281ec0 = _0x281ec0['_v'],\n                                                        _0x428c87 = [_0x428c87, _0x3e87c6, _0x560641, _0x4444cf, _0x4b7ccd],\n                                                        _0x3e87c6 = _0x281ec0[0x190c + 0x3 * 0x89b + 0x32dd * -0x1],\n                                                    null == _0xd55c82 && (_0xd55c82 = (function () {\n                                                        return this;\n                                                    }())),\n                                                        _0x560641 = _0xd55c82,\n                                                        (_0x4444cf = [_0x5c0f33]['concat'](_0x5c0f33))[_0x261736(0x259)] = Math[_0x261736(0x20c)](_0x281ec0[-0x1 * 0x170b + -0x936 + 0x1 * 0x2042], _0x1fc1ed) + (0x3 * -0x4fa + 0x21ed + -0x12fe),\n                                                        _0x4444cf['p'] = _0x281ec0[-0x16 * -0x1af + 0x35f * 0x1 + 0x2867 * -0x1],\n                                                        _0x4b7ccd = []) : _0x27fcf3[++_0x12cd72] = _0x281ec0[_0x261736(0x207)](_0xd55c82, _0x5c0f33);\n                                        } else {\n                                            if (0x60a + -0xf05 * -0x1 + 0x14cb * -0x1 === _0x5cd5b9) {\n                                                for (_0x1fc1ed = _0x26f45f[_0x3e87c6++],\n                                                         _0xd55c82 = [void (-0x1b5d + 0x22a1 + 0x26c * -0x3)],\n                                                         _0x37b70b = _0x1fc1ed; _0x37b70b > 0x1 * 0xd7e + -0x25f1 + 0x1873; --_0x37b70b)\n                                                    _0xd55c82[_0x37b70b] = _0x27fcf3[_0x12cd72--];\n                                                _0x5c0f33 = _0x27fcf3[_0x12cd72--],\n                                                    _0x281ec0 = Function['bind'][_0x261736(0x207)](_0x5c0f33, _0xd55c82),\n                                                    _0x27fcf3[++_0x12cd72] = new _0x281ec0();\n                                            } else\n                                                _0x3e87c6 += (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x1f7 + 0x1 * -0x7d0 + 0x7 * 0xd7) + _0x26f45f[_0x3e87c6 + (0x264a + 0xc3c + -0x3285)]) << 0x4 * 0x3ee + 0x45 * 0x51 + -0x15 * 0x1c9 >> 0x5 * 0x199 + -0x24f * -0x2 + -0xc8b) + (-0x1f3 * 0x6 + 0x24f7 + -0x1943);\n                                        }\n                                    } else\n                                        _0x5cd5b9 < -0x45d * -0x2 + -0x1e51 + 0x15e0 ? 0x125b + 0x198a + -0x2b9e === _0x5cd5b9 ? (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << -0x269 * -0xe + 0x1 * -0x225 + -0x1f91) + _0x26f45f[_0x3e87c6 + (-0x23bd * -0x1 + 0x1ce2 + 0x12 * -0x397)]) << 0xc61 + -0x133b + 0x6ea >> 0x10dc + -0x30a * 0x1 + -0xdc2,\n                                            _0x3e87c6 += -0xc5 * -0x9 + -0x252f + 0x1e44,\n                                        (_0x281ec0 = _0x27fcf3[_0x12cd72--]) || (_0x3e87c6 += _0x1fc1ed)) : (_0x1fc1ed = (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << 0x55 * 0x14 + 0x1 * 0x1e18 + -0x3 * 0xc3c) + _0x26f45f[_0x3e87c6 + (-0x22a3 + -0x5bf * -0x2 + 0x1726)]) << -0x98e * 0x4 + 0x8a1 * 0x1 + 0x1da7 >> -0x72 * -0x26 + 0x2b * -0x51 + -0x341,\n                                            _0x3e87c6 += 0x47 * 0x1d + 0x137 * -0x1d + 0x1b32,\n                                            _0x281ec0 = _0x27fcf3[_0x12cd72--],\n                                        _0x27fcf3[_0x12cd72] === _0x281ec0 && (--_0x12cd72,\n                                            _0x3e87c6 += _0x1fc1ed)) : -0xb * 0x33d + 0x23 * -0xf2 + 0x44fe === _0x5cd5b9 ? --_0x12cd72 : (_0x281ec0 = _0x27fcf3[_0x12cd72],\n                                            _0x27fcf3[++_0x12cd72] = _0x281ec0);\n                                }\n                            }\n                        }\n                    } catch (_0x111ea4) {\n                        for (_0x42ef1a = [-0x392 * -0x4 + 0x1a0 + -0xfe8, null]; (_0x1fc1ed = _0x4b7ccd[_0x261736(0x267)]()) && !_0x1fc1ed[0x126a + -0x1 * 0x227c + 0x1012 * 0x1];)\n                            ;\n                        if (!_0x1fc1ed) {\n                            _0x489bfb: for (; _0x428c87;) {\n                                for (_0x281ec0 = _0x428c87[0x10da * -0x1 + -0x539 + 0x1617 * 0x1]; _0x1fc1ed = _0x281ec0[_0x261736(0x267)]();)\n                                    if (_0x1fc1ed[0xaf4 * -0x2 + -0x2 * 0x132d + -0x2 * -0x1e21])\n                                        break _0x489bfb;\n                                _0x428c87 = _0x428c87[0x1381 + 0x193e + -0x4f * 0x91];\n                            }\n                            if (!_0x428c87)\n                                throw _0x111ea4;\n                            _0x3e87c6 = _0x428c87[0xb * -0x277 + 0x14ac + -0x226 * -0x3],\n                                _0x560641 = _0x428c87[0x153e + 0x1fd * -0xf + 0x897],\n                                _0x4444cf = _0x428c87[-0x1 * -0xa2e + 0xcd6 + 0x3 * -0x7ab],\n                                _0x4b7ccd = _0x428c87[-0x2 * 0x1145 + 0x2 * 0x293 + -0x3ad * -0x8],\n                                _0x428c87 = _0x428c87[-0x8e7 + 0x247f + -0x1b98];\n                        }\n                        -0xe * 0x277 + -0x3db + -0x665 * -0x6 === (_0x281ec0 = _0x1fc1ed[-0xe65 + 0x11d1 + -0x36c]) ? (_0x3e87c6 = _0x1fc1ed[-0x7 * -0x1c + 0x2fe * 0xa + -0x1eae],\n                            _0x1fc1ed[0x3f5 * 0x1 + 0x9e4 + 0x1 * -0xdd9] = -0x1622 * -0x1 + -0x1 * -0x1736 + -0x2d58,\n                            _0x4b7ccd['push'](_0x1fc1ed),\n                            _0x27fcf3[++_0x12cd72] = _0x111ea4) : 0x1a52 + -0xfc4 + 0x2d * -0x3c === _0x281ec0 ? (_0x3e87c6 = _0x1fc1ed[-0x19 * 0xfe + 0x1f98 + -0x6c8],\n                            _0x1fc1ed[0x5 * -0x33f + 0x11d * -0x1 + 0x1158] = 0x3ac * 0x1 + 0x2 * -0x1300 + 0x152 * 0x1a,\n                            _0x4b7ccd['push'](_0x1fc1ed),\n                            _0x42ef1a = [0x8f * 0x1d + -0x1c4b + 0xc1b, _0x111ea4]) : (_0x3e87c6 = _0x1fc1ed[0x31f * -0x5 + -0xae7 + -0x1 * -0x1a85],\n                            _0x1fc1ed[0x27 * -0xb3 + -0x186 * 0xa + 0x2a81] = 0xf9 + 0x164a + -0x1741,\n                            _0x4b7ccd[_0x261736(0x36e)](_0x1fc1ed),\n                            _0x27fcf3[++_0x12cd72] = _0x111ea4);\n                    }\n            }(_0x537efa, [], -0x1e + 0x2631 + -0x2613, _0x3f9548, _0x39b0b8);\n    }\n\n    !function (_0xe67213, _0x19937e) {\n        _0x19937e(window.byted_acrawler = {});\n        // var _0x40472c = w_0x25f3;\n        // 'object' == typeof exports && _0x40472c(0x384) != typeof module ? _0x19937e(exports) : _0x40472c(0x1ee) == typeof define && define['amd'] ? define([_0x40472c(0x1b8)], _0x19937e) : _0x19937e((_0xe67213 = _0x40472c(0x384) != typeof globalThis ? globalThis : _0xe67213 || self)[_0x40472c(0x1f5)] = {});\n    }(this, function (_0x1d18f2) {\n        'use strict';\n        var _0x5612de = w_0x25f3;\n\n        function _0x137ba2(_0x383b51) {\n            var _0x382940 = w_0x25f3, _0x2e23ce, _0x2c2004;\n\n            function _0x3a4f3f(_0x5a726e, _0x520718) {\n                var _0x480686 = w_0x25f3;\n                try {\n                    var _0x4a8345 = _0x383b51[_0x5a726e](_0x520718)\n                        , _0x8d9d0a = _0x4a8345[_0x480686(0x2e4)]\n                        , _0x32f534 = _0x8d9d0a instanceof _0x59d886;\n                    Promise[_0x480686(0x278)](_0x32f534 ? _0x8d9d0a['v'] : _0x8d9d0a)[_0x480686(0x1ed)](function (_0x5047be) {\n                        var _0x2a7bf3 = _0x480686;\n                        if (_0x32f534) {\n                            var _0x1c15d7 = 'return' === _0x5a726e ? _0x2a7bf3(0x2fd) : _0x2a7bf3(0x389);\n                            if (!_0x8d9d0a['k'] || _0x5047be['done'])\n                                return _0x3a4f3f(_0x1c15d7, _0x5047be);\n                            _0x5047be = _0x383b51[_0x1c15d7](_0x5047be)[_0x2a7bf3(0x2e4)];\n                        }\n                        _0x396815(_0x4a8345[_0x2a7bf3(0x1e3)] ? _0x2a7bf3(0x2fd) : _0x2a7bf3(0x2f1), _0x5047be);\n                    }, function (_0x55c002) {\n                        var _0x11b83e = _0x480686;\n                        _0x3a4f3f(_0x11b83e(0x250), _0x55c002);\n                    });\n                } catch (_0x5e07d1) {\n                    _0x396815(_0x480686(0x250), _0x5e07d1);\n                }\n            }\n\n            function _0x396815(_0x189a93, _0x2988d2) {\n                var _0x557617 = w_0x25f3;\n                switch (_0x189a93) {\n                    case _0x557617(0x2fd):\n                        _0x2e23ce[_0x557617(0x278)]({\n                            'value': _0x2988d2,\n                            'done': !(-0x252f + 0x1b60 + 0x9cf)\n                        });\n                        break;\n                    case 'throw':\n                        _0x2e23ce[_0x557617(0x39b)](_0x2988d2);\n                        break;\n                    default:\n                        _0x2e23ce[_0x557617(0x278)]({\n                            'value': _0x2988d2,\n                            'done': !(-0x18ec + -0x12dc + 0x2bc9)\n                        });\n                }\n                (_0x2e23ce = _0x2e23ce['next']) ? _0x3a4f3f(_0x2e23ce[_0x557617(0x392)], _0x2e23ce[_0x557617(0x327)]) : _0x2c2004 = null;\n            }\n\n            this['_invoke'] = function (_0xd1d2b8, _0x168b0a) {\n                return new Promise(function (_0x1a939a, _0x9b7633) {\n                        var _0x1f7808 = w_0x25f3\n                            , _0x270c76 = {\n                            'key': _0xd1d2b8,\n                            'arg': _0x168b0a,\n                            'resolve': _0x1a939a,\n                            'reject': _0x9b7633,\n                            'next': null\n                        };\n                        _0x2c2004 ? _0x2c2004 = _0x2c2004[_0x1f7808(0x389)] = _0x270c76 : (_0x2e23ce = _0x2c2004 = _0x270c76,\n                            _0x3a4f3f(_0xd1d2b8, _0x168b0a));\n                    }\n                );\n            }\n                ,\n            _0x382940(0x1ee) != typeof _0x383b51[_0x382940(0x2fd)] && (this[_0x382940(0x2fd)] = void (-0xe73 + -0xe * 0x24b + 0x2e8d));\n        }\n\n        function _0x59d886(_0x53e3a8, _0x594492) {\n            this['v'] = _0x53e3a8,\n                this['k'] = _0x594492;\n        }\n\n        function _0x1d9867(_0x38463f, _0x559d1b, _0x1b2c54, _0x595501) {\n            return {\n                'getMetadata': function (_0x397823) {\n                    var _0x2d4b6b = w_0x25f3;\n                    _0x1fca4f(_0x595501, _0x2d4b6b(0x349)),\n                        _0x525dc3(_0x397823);\n                    var _0x18296f = _0x38463f[_0x397823];\n                    if (void (-0x15d1 + 0x4d8 + -0xb * -0x18b) !== _0x18296f) {\n                        if (-0x1fa5 * -0x1 + 0x6b8 + -0x265c === _0x559d1b) {\n                            var _0x192f00 = _0x18296f[_0x2d4b6b(0x1d4)];\n                            if (void (-0x1 * 0x46d + -0x74 * 0x6 + 0x1f * 0x3b) !== _0x192f00)\n                                return _0x192f00[_0x1b2c54];\n                        } else {\n                            if (0x409 * 0x8 + 0x53 * -0x3e + -0xc2c === _0x559d1b) {\n                                var _0x6d3fe1 = _0x18296f[_0x2d4b6b(0x261)];\n                                if (void (0x1c7c + 0x8b0 + -0x7a * 0x4e) !== _0x6d3fe1)\n                                    return _0x6d3fe1[_0x2d4b6b(0x32b)](_0x1b2c54);\n                            } else {\n                                if (Object[_0x2d4b6b(0x3b8)][_0x2d4b6b(0x334)](_0x18296f, _0x2d4b6b(0x2ac)))\n                                    return _0x18296f[_0x2d4b6b(0x2ac)];\n                            }\n                        }\n                    }\n                },\n                'setMetadata': function (_0x3ee519, _0x4e53ba) {\n                    var _0x22e2d1 = w_0x25f3;\n                    _0x1fca4f(_0x595501, _0x22e2d1(0x395)),\n                        _0x525dc3(_0x3ee519);\n                    var _0x39b490 = _0x38463f[_0x3ee519];\n                    if (void (0x181 * -0x1 + 0x102 * 0x9 + -0x791) === _0x39b490 && (_0x39b490 = _0x38463f[_0x3ee519] = {}),\n                    -0x97e + -0x39 * -0x22 + 0x11 * 0x1d === _0x559d1b) {\n                        var _0x38c721 = _0x39b490[_0x22e2d1(0x1d4)];\n                        void (-0x2f9 * -0x7 + 0x8fe + -0x1dcd * 0x1) === _0x38c721 && (_0x38c721 = _0x39b490[_0x22e2d1(0x1d4)] = {}),\n                            _0x38c721[_0x1b2c54] = _0x4e53ba;\n                    } else {\n                        if (-0x4dc + 0xbb0 + -0x6d2 === _0x559d1b) {\n                            var _0x4ca087 = _0x39b490['priv'];\n                            void (0x29 * 0xb9 + -0x24a + -0x1b57) === _0x4ca087 && (_0x4ca087 = _0x39b490[_0x22e2d1(0x261)] = new Map()),\n                                _0x4ca087[_0x22e2d1(0x1e4)](_0x1b2c54, _0x4e53ba);\n                        } else\n                            _0x39b490[_0x22e2d1(0x2ac)] = _0x4e53ba;\n                    }\n                }\n            };\n        }\n\n        function _0x43bce4(_0x282431, _0x336297) {\n            var _0xd4a703 = w_0x25f3\n                , _0x2b5c4b = _0x282431[Symbol['metadata'] || Symbol[_0xd4a703(0x31e)]('Symbol.metadata')]\n                , _0x191a7e = Object[_0xd4a703(0x388)](_0x336297);\n            if (-0x22cd + -0x378 + -0x65 * -0x61 !== _0x191a7e[_0xd4a703(0x259)]) {\n                for (var _0x434093 = 0x1d66 + -0x2 * 0xa03 + -0x960; _0x434093 < _0x191a7e[_0xd4a703(0x259)]; _0x434093++) {\n                    var _0x720e9a = _0x191a7e[_0x434093]\n                        , _0x14e145 = _0x336297[_0x720e9a]\n                        , _0x2965bc = _0x2b5c4b ? _0x2b5c4b[_0x720e9a] : null\n                        , _0x530b43 = _0x14e145[_0xd4a703(0x1d4)]\n                        , _0x36f2c2 = _0x2965bc ? _0x2965bc[_0xd4a703(0x1d4)] : null;\n                    _0x530b43 && _0x36f2c2 && Object['setPrototypeOf'](_0x530b43, _0x36f2c2);\n                    var _0x1732ba = _0x14e145[_0xd4a703(0x261)];\n                    if (_0x1732ba) {\n                        var _0x550c9f = Array[_0xd4a703(0x29c)](_0x1732ba['values']())\n                            , _0x5cb426 = _0x2965bc ? _0x2965bc[_0xd4a703(0x261)] : null;\n                        _0x5cb426 && (_0x550c9f = _0x550c9f[_0xd4a703(0x2b8)](_0x5cb426)),\n                            _0x14e145[_0xd4a703(0x261)] = _0x550c9f;\n                    }\n                    _0x2965bc && Object[_0xd4a703(0x23b)](_0x14e145, _0x2965bc);\n                }\n                _0x2b5c4b && Object['setPrototypeOf'](_0x336297, _0x2b5c4b),\n                    _0x282431[Symbol[_0xd4a703(0x3a3)] || Symbol['for']('Symbol.metadata')] = _0x336297;\n            }\n        }\n\n        function _0x26f5a8(_0x4a45da, _0x3cff50) {\n            return function (_0x346098) {\n                var _0x33211b = w_0x25f3;\n                _0x1fca4f(_0x3cff50, 'addInitializer'),\n                    _0x3ccc16(_0x346098, _0x33211b(0x3ba)),\n                    _0x4a45da[_0x33211b(0x36e)](_0x346098);\n            }\n                ;\n        }\n\n        function _0x2bb58f(_0x256829, _0x48125d, _0x3ef27c, _0x2a2bd4, _0x3688dc, _0x348e43, _0x559d92, _0x5a7ba4, _0x9da1fe) {\n            var _0x2a79c7 = w_0x25f3, _0x2e3577;\n            switch (_0x348e43) {\n                case 0xf31 + -0x3 * 0x2dd + -0x699:\n                    _0x2e3577 = _0x2a79c7(0x1b9);\n                    break;\n                case 0x269d + -0x1291 + -0x140a:\n                    _0x2e3577 = _0x2a79c7(0x25a);\n                    break;\n                case 0x24f * -0x9 + 0x12b3 + 0x217:\n                    _0x2e3577 = _0x2a79c7(0x181);\n                    break;\n                case 0xee9 + -0xe3b * 0x1 + -0xaa:\n                    _0x2e3577 = _0x2a79c7(0x35d);\n                    break;\n                default:\n                    _0x2e3577 = _0x2a79c7(0x23c);\n            }\n            var _0x12a0c0, _0x433c00, _0x37f6a8 = {\n                'kind': _0x2e3577,\n                'name': _0x5a7ba4 ? '#' + _0x48125d : _0x48125d,\n                'isStatic': _0x559d92,\n                'isPrivate': _0x5a7ba4\n            }, _0x71731a = {\n                'v': !(-0x1b16 * -0x1 + 0x1 * 0x1fe1 + -0x2 * 0x1d7b)\n            };\n            if (0x15e0 + -0xdfe + -0x7e2 !== _0x348e43 && (_0x37f6a8['addInitializer'] = _0x26f5a8(_0x3688dc, _0x71731a)),\n                _0x5a7ba4) {\n                _0x12a0c0 = -0x2 * 0xd69 + 0x2a1 * 0x1 + 0x1833,\n                    _0x433c00 = Symbol(_0x48125d);\n                var _0x18857b = {};\n                0x2b + 0x9ef * 0x1 + -0x1 * 0xa1a === _0x348e43 ? (_0x18857b[_0x2a79c7(0x32b)] = _0x3ef27c[_0x2a79c7(0x32b)],\n                    _0x18857b['set'] = _0x3ef27c['set']) : -0x2 * 0xd06 + 0x1816 + 0x1f8 === _0x348e43 ? _0x18857b[_0x2a79c7(0x32b)] = function () {\n                        var _0x14604b = _0x2a79c7;\n                        return _0x3ef27c[_0x14604b(0x2e4)];\n                    }\n                    : (0x6bc + 0x1 * 0x2095 + 0x10 * -0x275 !== _0x348e43 && -0x1207 + 0x31f + 0x13 * 0xc9 !== _0x348e43 || (_0x18857b[_0x2a79c7(0x32b)] = function () {\n                            var _0x290422 = _0x2a79c7;\n                            return _0x3ef27c[_0x290422(0x32b)][_0x290422(0x334)](this);\n                        }\n                    ),\n                    0x1296 + -0x1481 + 0x1ec !== _0x348e43 && -0x1892 + -0xfa7 + 0x283d * 0x1 !== _0x348e43 || (_0x18857b[_0x2a79c7(0x1e4)] = function (_0x4e18b8) {\n                            var _0x7e7883 = _0x2a79c7;\n                            _0x3ef27c['set'][_0x7e7883(0x334)](this, _0x4e18b8);\n                        }\n                    )),\n                    _0x37f6a8[_0x2a79c7(0x1d0)] = _0x18857b;\n            } else\n                _0x12a0c0 = 0xca0 * 0x1 + 0x83 + -0x52 * 0x29,\n                    _0x433c00 = _0x48125d;\n            try {\n                return _0x256829(_0x9da1fe, Object[_0x2a79c7(0x2a0)](_0x37f6a8, _0x1d9867(_0x2a2bd4, _0x12a0c0, _0x433c00, _0x71731a)));\n            } finally {\n                _0x71731a['v'] = !(0x6ad + -0x17a9 + 0x10fc);\n            }\n        }\n\n        function _0x1fca4f(_0x322983, _0x544667) {\n            var _0x43acb9 = w_0x25f3;\n            if (_0x322983['v'])\n                throw new Error(_0x43acb9(0x214) + _0x544667 + _0x43acb9(0x168));\n        }\n\n        function _0x525dc3(_0x3ef577) {\n            var _0x42d9e9 = w_0x25f3;\n            if (_0x42d9e9(0x2ed) != typeof _0x3ef577)\n                throw new TypeError(_0x42d9e9(0x2e7) + _0x3ef577);\n        }\n\n        function _0x3ccc16(_0x56cd04, _0x56ab29) {\n            var _0x12ff08 = w_0x25f3;\n            if ('function' != typeof _0x56cd04)\n                throw new TypeError(_0x56ab29 + _0x12ff08(0x2f8));\n        }\n\n        function _0x32dfd4(_0x43869e, _0x434307) {\n            var _0x3fc8b9 = w_0x25f3\n                , _0xd7b002 = typeof _0x434307;\n            if (-0x1116 + 0x183f + 0x2 * -0x394 === _0x43869e) {\n                if (_0x3fc8b9(0x17d) !== _0xd7b002 || null === _0x434307)\n                    throw new TypeError(_0x3fc8b9(0x1fd));\n                void (-0x39e * -0x9 + -0x1 * 0x1241 + -0x7 * 0x20b) !== _0x434307[_0x3fc8b9(0x32b)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x32b)], _0x3fc8b9(0x170)),\n                void (0xeff * 0x1 + 0x2673 + 0x1 * -0x3572) !== _0x434307[_0x3fc8b9(0x1e4)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x1e4)], _0x3fc8b9(0x231)),\n                void (-0x1558 + -0x1b41 * 0x1 + 0x57 * 0x8f) !== _0x434307['init'] && _0x3ccc16(_0x434307['init'], _0x3fc8b9(0x22f)),\n                void (-0x148f + 0xfa3 * 0x1 + 0x4ec) !== _0x434307[_0x3fc8b9(0x2d0)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x2d0)], 'accessor.initializer');\n            } else {\n                if (_0x3fc8b9(0x1ee) !== _0xd7b002)\n                    throw new TypeError((0xf1a + 0xce * 0x1f + -0x280c === _0x43869e ? _0x3fc8b9(0x23c) : 0x2428 + -0x6 * -0x635 + -0x495c === _0x43869e ? _0x3fc8b9(0x19c) : _0x3fc8b9(0x25a)) + _0x3fc8b9(0x2cd));\n            }\n        }\n\n        function _0x372120(_0x40b476) {\n            var _0x3e830c = w_0x25f3, _0x49c5be;\n            return null == (_0x49c5be = _0x40b476['init']) && (_0x49c5be = _0x40b476[_0x3e830c(0x2d0)]) && _0x3e830c(0x384) != typeof console && console[_0x3e830c(0x3b0)](_0x3e830c(0x30b)),\n                _0x49c5be;\n        }\n\n        function _0x481bfe(_0x40006c, _0xdbd444, _0x2c21df, _0x2a4c98, _0x438b52, _0x13e34d, _0x5ae545, _0xa813f0, _0x4c4bfe) {\n            var _0x2ee2fe = w_0x25f3, _0x2f4463, _0x470ce0, _0x5e0119, _0x2b261c, _0x52c40b, _0x4e02cf,\n                _0x1fa0af = _0x2c21df[-0x987 + 0x27 * -0xdf + -0x40 * -0xae];\n            if (_0x5ae545 ? _0x2f4463 = -0xa89 * 0x1 + -0xd71 + 0x17fa === _0x438b52 || -0x272 * -0xd + -0x1c * 0xb2 + -0xc51 === _0x438b52 ? {\n                'get': _0x2c21df[0xefd + 0x232b + -0x3225],\n                'set': _0x2c21df[0x21b5 * -0x1 + -0x1015 + 0x31ce]\n            } : 0x17ef + -0x1d3 + 0x1619 * -0x1 === _0x438b52 ? {\n                'get': _0x2c21df[-0x1e92 + 0xff * -0xe + 0x2c87]\n            } : -0x2211 + 0x1568 + 0xcad === _0x438b52 ? {\n                'set': _0x2c21df[-0xcd2 + 0x126e + 0x1 * -0x599]\n            } : {\n                'value': _0x2c21df[0x2293 + -0x1815 + -0xa7b * 0x1]\n            } : 0x23f1 + -0x93b * -0x4 + 0x1 * -0x48dd !== _0x438b52 && (_0x2f4463 = Object[_0x2ee2fe(0x2a6)](_0xdbd444, _0x2a4c98)),\n                -0x9a5 + 0x2cc * -0x5 + -0xb * -0x226 === _0x438b52 ? _0x5e0119 = {\n                    'get': _0x2f4463['get'],\n                    'set': _0x2f4463[_0x2ee2fe(0x1e4)]\n                } : -0xb5c + 0x210d + -0x1ab * 0xd === _0x438b52 ? _0x5e0119 = _0x2f4463[_0x2ee2fe(0x2e4)] : -0x12e2 * -0x2 + 0x1 * 0x815 + -0x2dd6 === _0x438b52 ? _0x5e0119 = _0x2f4463['get'] : 0x6 * 0x182 + 0x15fd + -0x1f05 * 0x1 === _0x438b52 && (_0x5e0119 = _0x2f4463[_0x2ee2fe(0x1e4)]),\n            _0x2ee2fe(0x1ee) == typeof _0x1fa0af)\n                void (0x12b3 * -0x2 + 0x1229 * 0x1 + 0x133d) !== (_0x2b261c = _0x2bb58f(_0x1fa0af, _0x2a4c98, _0x2f4463, _0xa813f0, _0x4c4bfe, _0x438b52, _0x13e34d, _0x5ae545, _0x5e0119)) && (_0x32dfd4(_0x438b52, _0x2b261c),\n                    -0x655 + -0xb75 + 0x9 * 0x1fa === _0x438b52 ? _0x470ce0 = _0x2b261c : 0x2239 + -0x9 * -0x42b + -0x47bb === _0x438b52 ? (_0x470ce0 = _0x372120(_0x2b261c),\n                        _0x52c40b = _0x2b261c[_0x2ee2fe(0x32b)] || _0x5e0119[_0x2ee2fe(0x32b)],\n                        _0x4e02cf = _0x2b261c['set'] || _0x5e0119['set'],\n                        _0x5e0119 = {\n                            'get': _0x52c40b,\n                            'set': _0x4e02cf\n                        }) : _0x5e0119 = _0x2b261c);\n            else\n                for (var _0x5801c7 = _0x1fa0af['length'] - (0x2435 + 0x18d0 + 0x16 * -0x2c6); _0x5801c7 >= 0x3ab + 0x58e * -0x6 + 0x1da9; _0x5801c7--) {\n                    var _0x2c9ee5;\n                    void (0x11 * -0x22 + -0x29 * -0x45 + 0x8cb * -0x1) !== (_0x2b261c = _0x2bb58f(_0x1fa0af[_0x5801c7], _0x2a4c98, _0x2f4463, _0xa813f0, _0x4c4bfe, _0x438b52, _0x13e34d, _0x5ae545, _0x5e0119)) && (_0x32dfd4(_0x438b52, _0x2b261c),\n                        -0x220e + 0x3 * 0x4d5 + 0x138f === _0x438b52 ? _0x2c9ee5 = _0x2b261c : -0x2 * -0x1281 + 0x48f * 0x7 + -0x44ea === _0x438b52 ? (_0x2c9ee5 = _0x372120(_0x2b261c),\n                            _0x52c40b = _0x2b261c[_0x2ee2fe(0x32b)] || _0x5e0119[_0x2ee2fe(0x32b)],\n                            _0x4e02cf = _0x2b261c[_0x2ee2fe(0x1e4)] || _0x5e0119[_0x2ee2fe(0x1e4)],\n                            _0x5e0119 = {\n                                'get': _0x52c40b,\n                                'set': _0x4e02cf\n                            }) : _0x5e0119 = _0x2b261c,\n                    void (0x204c + -0x2618 + 0x7 * 0xd4) !== _0x2c9ee5 && (void (0x3b3 * 0x9 + -0x2709 + 0x69 * 0xe) === _0x470ce0 ? _0x470ce0 = _0x2c9ee5 : _0x2ee2fe(0x1ee) == typeof _0x470ce0 ? _0x470ce0 = [_0x470ce0, _0x2c9ee5] : _0x470ce0['push'](_0x2c9ee5)));\n                }\n            if (-0x236c + 0xbb8 + 0x17b4 === _0x438b52 || 0x1 * 0x13e5 + -0x73 * -0xd + -0x1 * 0x19bb === _0x438b52) {\n                if (void (0x213e + 0xef + -0x222d) === _0x470ce0)\n                    _0x470ce0 = function (_0x2f3a47, _0x29873e) {\n                        return _0x29873e;\n                    }\n                    ;\n                else {\n                    if (_0x2ee2fe(0x1ee) != typeof _0x470ce0) {\n                        var _0x41d3b0 = _0x470ce0;\n                        _0x470ce0 = function (_0x434b4b, _0x5f49e4) {\n                            var _0x463980 = _0x2ee2fe;\n                            for (var _0x99d6c0 = _0x5f49e4, _0x29ba97 = -0x120f * 0x1 + 0x1241 + -0x1 * 0x32; _0x29ba97 < _0x41d3b0['length']; _0x29ba97++)\n                                _0x99d6c0 = _0x41d3b0[_0x29ba97][_0x463980(0x334)](_0x434b4b, _0x99d6c0);\n                            return _0x99d6c0;\n                        }\n                        ;\n                    } else {\n                        var _0x58c0cd = _0x470ce0;\n                        _0x470ce0 = function (_0x15ad86, _0x1885c8) {\n                            return _0x58c0cd['call'](_0x15ad86, _0x1885c8);\n                        }\n                        ;\n                    }\n                }\n                _0x40006c[_0x2ee2fe(0x36e)](_0x470ce0);\n            }\n            0x1 * -0x241 + 0xf4f + -0xd0e !== _0x438b52 && (0x1 * 0x10e7 + -0x47c + -0x2 * 0x635 === _0x438b52 ? (_0x2f4463[_0x2ee2fe(0x32b)] = _0x5e0119[_0x2ee2fe(0x32b)],\n                _0x2f4463[_0x2ee2fe(0x1e4)] = _0x5e0119[_0x2ee2fe(0x1e4)]) : -0x53 * 0x6b + 0x16e * 0x8 + 0x1743 === _0x438b52 ? _0x2f4463[_0x2ee2fe(0x2e4)] = _0x5e0119 : 0x4 * -0x4cd + -0x1 * -0x211a + 0x1 * -0xde3 === _0x438b52 ? _0x2f4463['get'] = _0x5e0119 : -0x1d4b * 0x1 + 0x1853 + 0x4fc === _0x438b52 && (_0x2f4463[_0x2ee2fe(0x1e4)] = _0x5e0119),\n                _0x5ae545 ? 0x5 * -0x28 + 0xcfd + -0xc34 * 0x1 === _0x438b52 ? (_0x40006c[_0x2ee2fe(0x36e)](function (_0x21a97b, _0x5eb78e) {\n                    var _0x40880e = _0x2ee2fe;\n                    return _0x5e0119[_0x40880e(0x32b)][_0x40880e(0x334)](_0x21a97b, _0x5eb78e);\n                }),\n                    _0x40006c[_0x2ee2fe(0x36e)](function (_0x2fa7d1, _0x120ab2) {\n                        var _0x14b22a = _0x2ee2fe;\n                        return _0x5e0119[_0x14b22a(0x1e4)][_0x14b22a(0x334)](_0x2fa7d1, _0x120ab2);\n                    })) : -0x4 * 0x64c + -0x1 * 0xe54 + 0x13c3 * 0x2 === _0x438b52 ? _0x40006c['push'](_0x5e0119) : _0x40006c[_0x2ee2fe(0x36e)](function (_0xcb08af, _0x156de1) {\n                    var _0x327ef4 = _0x2ee2fe;\n                    return _0x5e0119[_0x327ef4(0x334)](_0xcb08af, _0x156de1);\n                }) : Object[_0x2ee2fe(0x175)](_0xdbd444, _0x2a4c98, _0x2f4463));\n        }\n\n        function _0xa6bc9e(_0x4ceb2c, _0x1b99e7, _0xa8afec, _0x19fdc6, _0x501635) {\n            var _0x4c0532 = w_0x25f3;\n            for (var _0xcd77fa, _0x29d8ee, _0x1865b0 = new Map(), _0x4b9277 = new Map(), _0xbb3086 = 0x8 * 0x5e + 0x1f79 + -0x17 * 0x17f; _0xbb3086 < _0x501635[_0x4c0532(0x259)]; _0xbb3086++) {\n                var _0x58c865 = _0x501635[_0xbb3086];\n                if (Array['isArray'](_0x58c865)) {\n                    var _0x203b06, _0x4069ae, _0x479925, _0x2ccf6e = _0x58c865[-0x3f4 + -0x1cc4 + -0x1 * -0x20b9],\n                        _0x138f67 = _0x58c865[0x17b7 + 0x1 * 0x1525 + -0x2cda],\n                        _0xf00e58 = _0x58c865[_0x4c0532(0x259)] > -0x9f5 + -0xd * -0x103 + -0x5 * 0xa3,\n                        _0x356344 = _0x2ccf6e >= -0x14cc + -0xe02 + 0x6f7 * 0x5;\n                    if (_0x356344 ? (_0x203b06 = _0x1b99e7,\n                        _0x4069ae = _0x19fdc6,\n                    0x7 * -0x3c7 + -0x225e + 0x3ccf != (_0x2ccf6e -= -0xdf * 0x17 + -0xb0c + 0x1f1a) && (_0x479925 = _0x29d8ee = _0x29d8ee || [])) : (_0x203b06 = _0x1b99e7[_0x4c0532(0x344)],\n                        _0x4069ae = _0xa8afec,\n                    -0xc0c + 0x1a8e + -0x2 * 0x741 !== _0x2ccf6e && (_0x479925 = _0xcd77fa = _0xcd77fa || [])),\n                    -0x135b + 0xba6 + -0x7b5 * -0x1 !== _0x2ccf6e && !_0xf00e58) {\n                        var _0x5ef9f5 = _0x356344 ? _0x4b9277 : _0x1865b0\n                            ,\n                            _0x4ff161 = _0x5ef9f5[_0x4c0532(0x32b)](_0x138f67) || 0x2 * 0x27b + 0x137 * 0x1d + -0x2831;\n                        if (!(-0xea4 + 0x2178 + 0x96a * -0x2) === _0x4ff161 || -0x1dce + 0x245d + -0x346 * 0x2 === _0x4ff161 && -0x6 * -0x38f + -0x4 * 0x179 + 0xf72 * -0x1 !== _0x2ccf6e || 0x1265 + -0x40 * 0x6a + -0x21 * -0x3f === _0x4ff161 && -0x14bf + -0x1fa6 + 0x3468 !== _0x2ccf6e)\n                            throw new Error(_0x4c0532(0x351) + _0x138f67);\n                        !_0x4ff161 && _0x2ccf6e > -0x895 * 0x1 + 0x9fa + -0x163 ? _0x5ef9f5[_0x4c0532(0x1e4)](_0x138f67, _0x2ccf6e) : _0x5ef9f5['set'](_0x138f67, !(-0x1a * 0x12 + 0xa1 * 0x1d + -0x1069 * 0x1));\n                    }\n                    _0x481bfe(_0x4ceb2c, _0x203b06, _0x58c865, _0x138f67, _0x2ccf6e, _0x356344, _0xf00e58, _0x4069ae, _0x479925);\n                }\n            }\n            _0x3657e2(_0x4ceb2c, _0xcd77fa),\n                _0x3657e2(_0x4ceb2c, _0x29d8ee);\n        }\n\n        function _0x3657e2(_0x27f72c, _0x8206e1) {\n            var _0x4690f1 = w_0x25f3;\n            _0x8206e1 && _0x27f72c[_0x4690f1(0x36e)](function (_0x5a459a) {\n                var _0x25d832 = _0x4690f1;\n                for (var _0x3abe8d = -0x2d8 + -0x38c + 0x664; _0x3abe8d < _0x8206e1['length']; _0x3abe8d++)\n                    _0x8206e1[_0x3abe8d][_0x25d832(0x334)](_0x5a459a);\n                return _0x5a459a;\n            });\n        }\n\n        function _0x5f3676(_0x5c13b5, _0x4779ee, _0x3479c8, _0x3cb840) {\n            var _0x5df6f5 = w_0x25f3;\n            if (_0x3cb840['length'] > -0x1744 + -0xfb * 0xd + 0x2403) {\n                for (var _0x3c4c21 = [], _0x504436 = _0x4779ee, _0x1b5d8b = _0x4779ee['name'], _0x38689d = _0x3cb840[_0x5df6f5(0x259)] - (-0x1f5e + 0x1e2c * 0x1 + 0x133); _0x38689d >= 0x878 + -0x1269 * 0x2 + 0x1c5a; _0x38689d--) {\n                    var _0x2bbf37 = {\n                        'v': !(0x1 * -0x17dc + -0x1f4 * -0x10 + -0x3d * 0x1f)\n                    };\n                    try {\n                        var _0x175a61 = Object['assign']({\n                            'kind': _0x5df6f5(0x19c),\n                            'name': _0x1b5d8b,\n                            'addInitializer': _0x26f5a8(_0x3c4c21, _0x2bbf37)\n                        }, _0x1d9867(_0x3479c8, -0x1dfa + -0x1517 + 0x3311, _0x1b5d8b, _0x2bbf37))\n                            , _0x23fff7 = _0x3cb840[_0x38689d](_0x504436, _0x175a61);\n                    } finally {\n                        _0x2bbf37['v'] = !(0x1 * -0x1e5d + -0xba7 * 0x2 + 0x35ab);\n                    }\n                    void (-0x2bf + -0x103d * -0x1 + -0xd7e) !== _0x23fff7 && (_0x32dfd4(0xcf3 + -0x9f8 + -0x2f1, _0x23fff7),\n                        _0x504436 = _0x23fff7);\n                }\n                _0x5c13b5[_0x5df6f5(0x36e)](_0x504436, function () {\n                    var _0x52b1c0 = _0x5df6f5;\n                    for (var _0x4f0e95 = 0x18 * 0x57 + 0x9f2 * 0x3 + -0x25fe; _0x4f0e95 < _0x3c4c21[_0x52b1c0(0x259)]; _0x4f0e95++)\n                        _0x3c4c21[_0x4f0e95][_0x52b1c0(0x334)](_0x504436);\n                });\n            }\n        }\n\n        function _0x51be3f(_0x44772e, _0x5243ca, _0x398fa6) {\n            var _0x234a54 = w_0x25f3\n                , _0x13ba59 = []\n                , _0x3f8aa9 = {}\n                , _0x129506 = {};\n            return _0xa6bc9e(_0x13ba59, _0x44772e, _0x129506, _0x3f8aa9, _0x5243ca),\n                _0x43bce4(_0x44772e[_0x234a54(0x344)], _0x129506),\n                _0x5f3676(_0x13ba59, _0x44772e, _0x3f8aa9, _0x398fa6),\n                _0x43bce4(_0x44772e, _0x3f8aa9),\n                _0x13ba59;\n        }\n\n        function _0x281b3b() {\n            function _0x556aac(_0xe6f04c, _0x2cf155) {\n                return function (_0x4ecc37) {\n                    var _0x253daa = w_0x25f3;\n                    !function (_0x109a83, _0x5991fe) {\n                        var _0x11a2fc = w_0x25f3;\n                        if (_0x109a83['v'])\n                            throw new Error(_0x11a2fc(0x257));\n                    }(_0x2cf155),\n                        _0x3020d2(_0x4ecc37, _0x253daa(0x3ba)),\n                        _0xe6f04c[_0x253daa(0x36e)](_0x4ecc37);\n                }\n                    ;\n            }\n\n            function _0x193050(_0xc0995a, _0x3ee2bb, _0x30e0b6, _0xba208c, _0x262641, _0x4fa001, _0x1bb0d5, _0xa6e531) {\n                var _0x208bac = w_0x25f3, _0x59dc77;\n                switch (_0x262641) {\n                    case 0x1af6 + -0xd13 + -0xde2:\n                        _0x59dc77 = 'accessor';\n                        break;\n                    case 0xfda + -0x760 + -0x878:\n                        _0x59dc77 = _0x208bac(0x25a);\n                        break;\n                    case 0x1a * 0xb9 + 0xc3f + -0x1f06:\n                        _0x59dc77 = 'getter';\n                        break;\n                    case -0xb42 * 0x3 + -0x12d9 + 0x34a3:\n                        _0x59dc77 = 'setter';\n                        break;\n                    default:\n                        _0x59dc77 = _0x208bac(0x23c);\n                }\n                var _0x1b169f, _0x3fad4b, _0x1050cb = {\n                    'kind': _0x59dc77,\n                    'name': _0x1bb0d5 ? '#' + _0x3ee2bb : _0x3ee2bb,\n                    'static': _0x4fa001,\n                    'private': _0x1bb0d5\n                }, _0x252772 = {\n                    'v': !(0x5 * 0x4d5 + -0x1 * 0x1d6e + 0x546)\n                };\n                -0x21ff + -0x127a + -0x3479 * -0x1 !== _0x262641 && (_0x1050cb['addInitializer'] = _0x556aac(_0xba208c, _0x252772)),\n                    -0x2c9 + -0x27 + 0x2f0 === _0x262641 ? _0x1bb0d5 ? (_0x1b169f = _0x30e0b6['get'],\n                        _0x3fad4b = _0x30e0b6[_0x208bac(0x1e4)]) : (_0x1b169f = function () {\n                            return this[_0x3ee2bb];\n                        }\n                            ,\n                            _0x3fad4b = function (_0x417555) {\n                                this[_0x3ee2bb] = _0x417555;\n                            }\n                    ) : 0x1 * -0x1d61 + -0x1 * 0x841 + -0xc8c * -0x3 === _0x262641 ? _0x1b169f = function () {\n                            var _0x195f9b = _0x208bac;\n                            return _0x30e0b6[_0x195f9b(0x2e4)];\n                        }\n                        : (0x1 * -0x1e49 + 0x1 * 0x1eef + 0x37 * -0x3 !== _0x262641 && 0x1 * 0x204a + -0x137 * -0xb + -0x2da4 !== _0x262641 || (_0x1b169f = function () {\n                                var _0x3ad118 = _0x208bac;\n                                return _0x30e0b6[_0x3ad118(0x32b)][_0x3ad118(0x334)](this);\n                            }\n                        ),\n                        0x729 + -0x7ae + 0x1 * 0x86 !== _0x262641 && -0xa * -0x161 + -0x512 + -0x2 * 0x45a !== _0x262641 || (_0x3fad4b = function (_0x37b522) {\n                                var _0x599416 = _0x208bac;\n                                _0x30e0b6[_0x599416(0x1e4)]['call'](this, _0x37b522);\n                            }\n                        )),\n                    _0x1050cb[_0x208bac(0x1d0)] = _0x1b169f && _0x3fad4b ? {\n                        'get': _0x1b169f,\n                        'set': _0x3fad4b\n                    } : _0x1b169f ? {\n                        'get': _0x1b169f\n                    } : {\n                        'set': _0x3fad4b\n                    };\n                try {\n                    return _0xc0995a(_0xa6e531, _0x1050cb);\n                } finally {\n                    _0x252772['v'] = !(-0x1 * 0x1ecf + 0x1cfc + 0x1d3);\n                }\n            }\n\n            function _0x3020d2(_0x5684cc, _0x512b77) {\n                var _0x3b7e7a = w_0x25f3;\n                if (_0x3b7e7a(0x1ee) != typeof _0x5684cc)\n                    throw new TypeError(_0x512b77 + '\\x20must\\x20be\\x20a\\x20function');\n            }\n\n            function _0x13d7df(_0x22787a, _0x4a8dfe) {\n                var _0x994eff = w_0x25f3\n                    , _0x751eff = typeof _0x4a8dfe;\n                if (-0x690 + 0x133f * -0x2 + 0x2d0f === _0x22787a) {\n                    if (_0x994eff(0x17d) !== _0x751eff || null === _0x4a8dfe)\n                        throw new TypeError(_0x994eff(0x1fd));\n                    void (-0x2af + 0x838 + -0xd * 0x6d) !== _0x4a8dfe[_0x994eff(0x32b)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x32b)], _0x994eff(0x170)),\n                    void (0x1b * -0x43 + -0x24c8 + 0x2bd9) !== _0x4a8dfe[_0x994eff(0x1e4)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x1e4)], _0x994eff(0x231)),\n                    void (-0x2a4 + 0x35 * -0x1d + 0x8a5) !== _0x4a8dfe[_0x994eff(0x3b9)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x3b9)], _0x994eff(0x22f));\n                } else {\n                    if ('function' !== _0x751eff)\n                        throw new TypeError((-0x800 + 0xd * 0x75 + 0x20f === _0x22787a ? _0x994eff(0x23c) : 0x13ad + 0x1db0 + -0x3153 === _0x22787a ? _0x994eff(0x19c) : _0x994eff(0x25a)) + '\\x20decorators\\x20must\\x20return\\x20a\\x20function\\x20or\\x20void\\x200');\n                }\n            }\n\n            function _0x3345ab(_0xc8cad8, _0x5d015f, _0x32f33f, _0x5f5169, _0x23451f, _0x2595f8, _0xb8bdee, _0x2c3fb2) {\n                var _0x1d74f6 = w_0x25f3, _0x584e33, _0x103b18, _0x5d6523, _0x2d18a1, _0x2b9fd3, _0x11479e,\n                    _0x4ef3d6 = _0x32f33f[0x23c3 + -0x1a88 + 0x1 * -0x93b];\n                if (_0xb8bdee ? _0x584e33 = 0x7ed * 0x1 + 0xac9 + -0x12b6 === _0x23451f || 0x4 * 0x7f5 + 0x11ab + 0x712 * -0x7 === _0x23451f ? {\n                    'get': _0x32f33f[0x265e * 0x1 + -0x23e1 + -0x1 * 0x27a],\n                    'set': _0x32f33f[0x108e + -0x2551 + 0x1b * 0xc5]\n                } : 0x19bc + 0x1c0d * 0x1 + 0x35c6 * -0x1 === _0x23451f ? {\n                    'get': _0x32f33f[-0x7fd * 0x4 + 0x1b6c + 0x48b]\n                } : 0x149a + 0x2522 + -0x39b8 === _0x23451f ? {\n                    'set': _0x32f33f[-0x1 * 0x3ad + -0xb4e * 0x2 + -0x9 * -0x2ec]\n                } : {\n                    'value': _0x32f33f[0x21a6 + -0x7 + -0x219c]\n                } : 0x12ab * 0x1 + -0x1f41 + 0xc96 !== _0x23451f && (_0x584e33 = Object[_0x1d74f6(0x2a6)](_0x5d015f, _0x5f5169)),\n                    0x11 * -0xf7 + -0x4 * 0x7be + 0x2f60 === _0x23451f ? _0x5d6523 = {\n                        'get': _0x584e33[_0x1d74f6(0x32b)],\n                        'set': _0x584e33['set']\n                    } : 0x1e3 + 0x2 * 0x11ef + -0x25bf === _0x23451f ? _0x5d6523 = _0x584e33[_0x1d74f6(0x2e4)] : -0x6b + 0x1ff8 + -0xfc5 * 0x2 === _0x23451f ? _0x5d6523 = _0x584e33['get'] : 0x2577 + -0x2272 + -0x301 === _0x23451f && (_0x5d6523 = _0x584e33[_0x1d74f6(0x1e4)]),\n                'function' == typeof _0x4ef3d6)\n                    void (0x1bdc * -0x1 + 0x2343 + -0x1 * 0x767) !== (_0x2d18a1 = _0x193050(_0x4ef3d6, _0x5f5169, _0x584e33, _0x2c3fb2, _0x23451f, _0x2595f8, _0xb8bdee, _0x5d6523)) && (_0x13d7df(_0x23451f, _0x2d18a1),\n                        -0x5 * -0x27e + 0x6a * 0x1e + -0x18e2 === _0x23451f ? _0x103b18 = _0x2d18a1 : 0x23f1 + -0x4 * 0x8bb + 0x14 * -0xd === _0x23451f ? (_0x103b18 = _0x2d18a1['init'],\n                            _0x2b9fd3 = _0x2d18a1[_0x1d74f6(0x32b)] || _0x5d6523[_0x1d74f6(0x32b)],\n                            _0x11479e = _0x2d18a1[_0x1d74f6(0x1e4)] || _0x5d6523[_0x1d74f6(0x1e4)],\n                            _0x5d6523 = {\n                                'get': _0x2b9fd3,\n                                'set': _0x11479e\n                            }) : _0x5d6523 = _0x2d18a1);\n                else\n                    for (var _0x4328fb = _0x4ef3d6[_0x1d74f6(0x259)] - (0xe31 + -0xc5b + -0x1d5); _0x4328fb >= 0x87a + -0xf7c + 0x702; _0x4328fb--) {\n                        var _0x5c4cc8;\n                        void (0x83b + -0x8af + 0x74) !== (_0x2d18a1 = _0x193050(_0x4ef3d6[_0x4328fb], _0x5f5169, _0x584e33, _0x2c3fb2, _0x23451f, _0x2595f8, _0xb8bdee, _0x5d6523)) && (_0x13d7df(_0x23451f, _0x2d18a1),\n                            -0x4 * 0x511 + -0xc0a * -0x1 + 0x83a === _0x23451f ? _0x5c4cc8 = _0x2d18a1 : -0x22 * -0x4d + -0x135d * -0x2 + 0x1051 * -0x3 === _0x23451f ? (_0x5c4cc8 = _0x2d18a1[_0x1d74f6(0x3b9)],\n                                _0x2b9fd3 = _0x2d18a1[_0x1d74f6(0x32b)] || _0x5d6523[_0x1d74f6(0x32b)],\n                                _0x11479e = _0x2d18a1[_0x1d74f6(0x1e4)] || _0x5d6523[_0x1d74f6(0x1e4)],\n                                _0x5d6523 = {\n                                    'get': _0x2b9fd3,\n                                    'set': _0x11479e\n                                }) : _0x5d6523 = _0x2d18a1,\n                        void (0x23b9 * 0x1 + 0x2 * -0xccb + -0x5 * 0x207) !== _0x5c4cc8 && (void (-0x15ac + 0x376 + 0x7e * 0x25) === _0x103b18 ? _0x103b18 = _0x5c4cc8 : _0x1d74f6(0x1ee) == typeof _0x103b18 ? _0x103b18 = [_0x103b18, _0x5c4cc8] : _0x103b18['push'](_0x5c4cc8)));\n                    }\n                if (-0x11a3 + 0xd * -0x2f2 + -0x67 * -0x8b === _0x23451f || 0xeab * -0x1 + 0x752 * -0x1 + -0x15fe * -0x1 === _0x23451f) {\n                    if (void (-0x4a8 * 0x1 + 0xfb0 + -0xb08) === _0x103b18)\n                        _0x103b18 = function (_0x1682da, _0x55e4de) {\n                            return _0x55e4de;\n                        }\n                        ;\n                    else {\n                        if (_0x1d74f6(0x1ee) != typeof _0x103b18) {\n                            var _0x278a7c = _0x103b18;\n                            _0x103b18 = function (_0x1c32a2, _0x442b39) {\n                                var _0x56cde3 = _0x1d74f6;\n                                for (var _0x200043 = _0x442b39, _0x52eaec = 0xc8a + 0x26f6 + 0x20 * -0x19c; _0x52eaec < _0x278a7c[_0x56cde3(0x259)]; _0x52eaec++)\n                                    _0x200043 = _0x278a7c[_0x52eaec]['call'](_0x1c32a2, _0x200043);\n                                return _0x200043;\n                            }\n                            ;\n                        } else {\n                            var _0x120537 = _0x103b18;\n                            _0x103b18 = function (_0x5a0b99, _0x523966) {\n                                var _0x2de49d = _0x1d74f6;\n                                return _0x120537[_0x2de49d(0x334)](_0x5a0b99, _0x523966);\n                            }\n                            ;\n                        }\n                    }\n                    _0xc8cad8['push'](_0x103b18);\n                }\n                0x3ac * -0x8 + 0x915 + 0x144b !== _0x23451f && (-0xcde + -0x1f3f + 0x2c1e === _0x23451f ? (_0x584e33[_0x1d74f6(0x32b)] = _0x5d6523['get'],\n                    _0x584e33[_0x1d74f6(0x1e4)] = _0x5d6523['set']) : -0x31 * -0xc1 + -0x1 * -0x2388 + -0x4877 === _0x23451f ? _0x584e33[_0x1d74f6(0x2e4)] = _0x5d6523 : -0x4 * 0x899 + 0x1944 + 0x923 === _0x23451f ? _0x584e33[_0x1d74f6(0x32b)] = _0x5d6523 : -0x64e * 0x5 + 0x152f + 0xa5b === _0x23451f && (_0x584e33[_0x1d74f6(0x1e4)] = _0x5d6523),\n                    _0xb8bdee ? 0x186b + 0x3 * 0x7e9 + -0x1ed * 0x19 === _0x23451f ? (_0xc8cad8[_0x1d74f6(0x36e)](function (_0x1c7663, _0x210e49) {\n                        var _0xb35933 = _0x1d74f6;\n                        return _0x5d6523['get'][_0xb35933(0x334)](_0x1c7663, _0x210e49);\n                    }),\n                        _0xc8cad8[_0x1d74f6(0x36e)](function (_0x9ce4a0, _0xa2a6a5) {\n                            var _0x548bf5 = _0x1d74f6;\n                            return _0x5d6523[_0x548bf5(0x1e4)][_0x548bf5(0x334)](_0x9ce4a0, _0xa2a6a5);\n                        })) : -0x2 * 0x91d + -0x226e + 0x282 * 0x15 === _0x23451f ? _0xc8cad8['push'](_0x5d6523) : _0xc8cad8[_0x1d74f6(0x36e)](function (_0x5b9e9b, _0x4ef49d) {\n                        return _0x5d6523['call'](_0x5b9e9b, _0x4ef49d);\n                    }) : Object[_0x1d74f6(0x175)](_0x5d015f, _0x5f5169, _0x584e33));\n            }\n\n            function _0xbbd38b(_0x42478e, _0x1ef3db) {\n                var _0x15d90a = w_0x25f3;\n                _0x1ef3db && _0x42478e[_0x15d90a(0x36e)](function (_0xdfc40e) {\n                    var _0x10548c = _0x15d90a;\n                    for (var _0x3e6f2c = -0x349 * -0xa + 0xe * 0x5b + -0x25d4; _0x3e6f2c < _0x1ef3db[_0x10548c(0x259)]; _0x3e6f2c++)\n                        _0x1ef3db[_0x3e6f2c][_0x10548c(0x334)](_0xdfc40e);\n                    return _0xdfc40e;\n                });\n            }\n\n            return function (_0x2327f5, _0x28ca06, _0x53ed99) {\n                var _0x253a06 = [];\n                return function (_0x1816e5, _0x29e49e, _0x48cb46) {\n                    var _0x5efef1 = w_0x25f3;\n                    for (var _0x5857a9, _0x48222e, _0x2f7979 = new Map(), _0x2e733e = new Map(), _0x4b6d1a = 0x1 * -0xec3 + 0x1 * 0x6a2 + 0x821; _0x4b6d1a < _0x48cb46[_0x5efef1(0x259)]; _0x4b6d1a++) {\n                        var _0x58c6d3 = _0x48cb46[_0x4b6d1a];\n                        if (Array['isArray'](_0x58c6d3)) {\n                            var _0x124b63, _0x4324aa, _0x8c2a39 = _0x58c6d3[-0x1d3a + -0x24ff + 0x423a],\n                                _0x8fabbd = _0x58c6d3[0x1b14 + -0x1 * -0x1f0c + -0x1d0f * 0x2],\n                                _0x249da3 = _0x58c6d3[_0x5efef1(0x259)] > 0x1 * 0xb42 + -0x1c1 * 0xe + -0x1 * -0xd4f,\n                                _0x11d04c = _0x8c2a39 >= -0x12b3 * 0x1 + 0x10e6 + 0x1d2;\n                            if (_0x11d04c ? (_0x124b63 = _0x29e49e,\n                            -0x15b * -0x5 + 0x373 + -0xa3a != (_0x8c2a39 -= -0x24b2 + -0x12b * 0x17 + 0x3f94) && (_0x4324aa = _0x48222e = _0x48222e || [])) : (_0x124b63 = _0x29e49e['prototype'],\n                            0x11fa + -0x1859 + 0x65f !== _0x8c2a39 && (_0x4324aa = _0x5857a9 = _0x5857a9 || [])),\n                            -0x11df + -0x205d * 0x1 + 0x323c !== _0x8c2a39 && !_0x249da3) {\n                                var _0x3e0748 = _0x11d04c ? _0x2e733e : _0x2f7979\n                                    ,\n                                    _0x148749 = _0x3e0748[_0x5efef1(0x32b)](_0x8fabbd) || 0x6c0 + 0x8e3 + 0x1 * -0xfa3;\n                                if (!(-0x288 + -0x1b8f + 0x1e17) === _0x148749 || 0xcae + -0x84a + -0x461 === _0x148749 && 0xebc + -0x6cf + -0x7e9 !== _0x8c2a39 || 0x132d * 0x2 + 0x1 * 0x6ab + -0x1 * 0x2d01 === _0x148749 && 0x2144 + -0xe17 * -0x1 + -0x2f58 !== _0x8c2a39)\n                                    throw new Error('Attempted\\x20to\\x20decorate\\x20a\\x20public\\x20method/accessor\\x20that\\x20has\\x20the\\x20same\\x20name\\x20as\\x20a\\x20previously\\x20decorated\\x20public\\x20method/accessor.\\x20This\\x20is\\x20not\\x20currently\\x20supported\\x20by\\x20the\\x20decorators\\x20plugin.\\x20Property\\x20name\\x20was:\\x20' + _0x8fabbd);\n                                !_0x148749 && _0x8c2a39 > -0x2ea * -0xc + 0x1 * 0x24cb + 0x1 * -0x47c1 ? _0x3e0748[_0x5efef1(0x1e4)](_0x8fabbd, _0x8c2a39) : _0x3e0748[_0x5efef1(0x1e4)](_0x8fabbd, !(0xb9e + -0xc * -0x9d + -0x12fa));\n                            }\n                            _0x3345ab(_0x1816e5, _0x124b63, _0x58c6d3, _0x8fabbd, _0x8c2a39, _0x11d04c, _0x249da3, _0x4324aa);\n                        }\n                    }\n                    _0xbbd38b(_0x1816e5, _0x5857a9),\n                        _0xbbd38b(_0x1816e5, _0x48222e);\n                }(_0x253a06, _0x2327f5, _0x28ca06),\n                    function (_0x528ea3, _0x4f695c, _0x1527df) {\n                        var _0x436c1d = w_0x25f3;\n                        if (_0x1527df[_0x436c1d(0x259)] > 0xe5 + 0x269c + -0x2781) {\n                            for (var _0x4e0e1b = [], _0x3eca99 = _0x4f695c, _0x5c69d2 = _0x4f695c[_0x436c1d(0x341)], _0x2abebb = _0x1527df[_0x436c1d(0x259)] - (0x1 * -0x1cbe + 0xa * -0x2ba + 0x3803); _0x2abebb >= 0x8c0 + -0x44d * 0x4 + 0x874; _0x2abebb--) {\n                                var _0x30122e = {\n                                    'v': !(0x26bb + 0x34c * 0x7 + 0x1 * -0x3dce)\n                                };\n                                try {\n                                    var _0x46e0b1 = _0x1527df[_0x2abebb](_0x3eca99, {\n                                        'kind': _0x436c1d(0x19c),\n                                        'name': _0x5c69d2,\n                                        'addInitializer': _0x556aac(_0x4e0e1b, _0x30122e)\n                                    });\n                                } finally {\n                                    _0x30122e['v'] = !(0x114e + 0x1f1 * -0x1 + 0x1 * -0xf5d);\n                                }\n                                void (-0x1 * -0x1c41 + 0x38d * 0x1 + -0x1fce) !== _0x46e0b1 && (_0x13d7df(0x180 + 0x6 * -0x2f + -0x5c, _0x46e0b1),\n                                    _0x3eca99 = _0x46e0b1);\n                            }\n                            _0x528ea3['push'](_0x3eca99, function () {\n                                var _0x1ef0f8 = _0x436c1d;\n                                for (var _0x337d50 = 0x1 * -0x217d + -0x1a35 + -0x2 * -0x1dd9; _0x337d50 < _0x4e0e1b[_0x1ef0f8(0x259)]; _0x337d50++)\n                                    _0x4e0e1b[_0x337d50]['call'](_0x3eca99);\n                            });\n                        }\n                    }(_0x253a06, _0x2327f5, _0x53ed99),\n                    _0x253a06;\n            }\n                ;\n        }\n\n        var _0x15b960, _0x500e9f;\n\n        function _0x4ab133(_0x538caa, _0x1dca3a, _0x362c83) {\n            return (_0x15b960 = _0x15b960 || _0x281b3b())(_0x538caa, _0x1dca3a, _0x362c83);\n        }\n\n        function _0x4591cd() {\n            function _0x135cea(_0x43f619, _0x5dfa54) {\n                return function (_0x33b776) {\n                    var _0x55feea = w_0x25f3;\n                    !function (_0x4d2467, _0x1aaab5) {\n                        var _0x188bf8 = w_0x25f3;\n                        if (_0x4d2467['v'])\n                            throw new Error(_0x188bf8(0x257));\n                    }(_0x5dfa54),\n                        _0x23bc0c(_0x33b776, _0x55feea(0x3ba)),\n                        _0x43f619[_0x55feea(0x36e)](_0x33b776);\n                }\n                    ;\n            }\n\n            function _0x39ceae(_0x5713eb, _0x3cd64b, _0x2a5e05, _0x428f9b, _0x1cd0f5, _0x386fff, _0x54211b, _0x40ee96) {\n                var _0x32bd6c = w_0x25f3, _0x43d2aa;\n                switch (_0x1cd0f5) {\n                    case -0x3 * -0x9f7 + 0x13bc + -0x31a0:\n                        _0x43d2aa = _0x32bd6c(0x1b9);\n                        break;\n                    case 0x14f5 + -0x1f56 + -0x1 * -0xa63:\n                        _0x43d2aa = _0x32bd6c(0x25a);\n                        break;\n                    case -0x1 * -0x346 + -0xe + 0x335 * -0x1:\n                        _0x43d2aa = _0x32bd6c(0x181);\n                        break;\n                    case -0x2 * -0x367 + 0x16b3 + -0x1 * 0x1d7d:\n                        _0x43d2aa = _0x32bd6c(0x35d);\n                        break;\n                    default:\n                        _0x43d2aa = _0x32bd6c(0x23c);\n                }\n                var _0x1f76cf, _0x2d3a63, _0x52dc9f = {\n                    'kind': _0x43d2aa,\n                    'name': _0x54211b ? '#' + _0x3cd64b : _0x3cd64b,\n                    'static': _0x386fff,\n                    'private': _0x54211b\n                }, _0x33b885 = {\n                    'v': !(0x1 * 0xea1 + 0x22b7 + 0x3157 * -0x1)\n                };\n                -0x948 + -0x2454 + 0x1c * 0x1a1 !== _0x1cd0f5 && (_0x52dc9f[_0x32bd6c(0x225)] = _0x135cea(_0x428f9b, _0x33b885)),\n                    0xb * 0xb1 + 0x1417 + -0x1bb2 === _0x1cd0f5 ? _0x54211b ? (_0x1f76cf = _0x2a5e05[_0x32bd6c(0x32b)],\n                        _0x2d3a63 = _0x2a5e05['set']) : (_0x1f76cf = function () {\n                            return this[_0x3cd64b];\n                        }\n                            ,\n                            _0x2d3a63 = function (_0x209e9f) {\n                                this[_0x3cd64b] = _0x209e9f;\n                            }\n                    ) : 0x240f + 0xc11 * 0x3 + -0x22 * 0x220 === _0x1cd0f5 ? _0x1f76cf = function () {\n                            var _0x446fc0 = _0x32bd6c;\n                            return _0x2a5e05[_0x446fc0(0x2e4)];\n                        }\n                        : (-0x4 * -0x1f6 + 0x1b48 + -0x231f !== _0x1cd0f5 && 0x61 * 0x1a + -0x113 * -0x11 + -0x1c1a !== _0x1cd0f5 || (_0x1f76cf = function () {\n                                var _0x447b7b = _0x32bd6c;\n                                return _0x2a5e05['get'][_0x447b7b(0x334)](this);\n                            }\n                        ),\n                        0x1e4e + 0x25b6 * -0x1 + 0x769 !== _0x1cd0f5 && 0x1397 + -0xb7e + -0x815 !== _0x1cd0f5 || (_0x2d3a63 = function (_0x4c071d) {\n                                _0x2a5e05['set']['call'](this, _0x4c071d);\n                            }\n                        )),\n                    _0x52dc9f[_0x32bd6c(0x1d0)] = _0x1f76cf && _0x2d3a63 ? {\n                        'get': _0x1f76cf,\n                        'set': _0x2d3a63\n                    } : _0x1f76cf ? {\n                        'get': _0x1f76cf\n                    } : {\n                        'set': _0x2d3a63\n                    };\n                try {\n                    return _0x5713eb(_0x40ee96, _0x52dc9f);\n                } finally {\n                    _0x33b885['v'] = !(-0x8c9 + 0x2 * -0x1189 + 0x2bdb);\n                }\n            }\n\n            function _0x23bc0c(_0x4aa0f2, _0x12640a) {\n                var _0x1b925e = w_0x25f3;\n                if (_0x1b925e(0x1ee) != typeof _0x4aa0f2)\n                    throw new TypeError(_0x12640a + _0x1b925e(0x2f8));\n            }\n\n            function _0x2de5e4(_0x3de3bb, _0xa398ec) {\n                var _0xf94308 = w_0x25f3\n                    , _0x2c8661 = typeof _0xa398ec;\n                if (-0x33 * 0x4c + 0x5 * 0x787 + -0x1 * 0x167e === _0x3de3bb) {\n                    if (_0xf94308(0x17d) !== _0x2c8661 || null === _0xa398ec)\n                        throw new TypeError(_0xf94308(0x1fd));\n                    void (-0x1e03 + -0x1eb + 0xff7 * 0x2) !== _0xa398ec[_0xf94308(0x32b)] && _0x23bc0c(_0xa398ec[_0xf94308(0x32b)], 'accessor.get'),\n                    void (0x3ba + -0x24db + -0xb0b * -0x3) !== _0xa398ec[_0xf94308(0x1e4)] && _0x23bc0c(_0xa398ec[_0xf94308(0x1e4)], _0xf94308(0x231)),\n                    void (0x7f8 + -0x1b10 + -0x1318 * -0x1) !== _0xa398ec[_0xf94308(0x3b9)] && _0x23bc0c(_0xa398ec['init'], _0xf94308(0x22f));\n                } else {\n                    if (_0xf94308(0x1ee) !== _0x2c8661)\n                        throw new TypeError((-0xf65 + 0xbd0 + 0x395 === _0x3de3bb ? _0xf94308(0x23c) : 0x48e + -0x1 * 0x1ebe + 0x1a3a === _0x3de3bb ? _0xf94308(0x19c) : _0xf94308(0x25a)) + _0xf94308(0x2cd));\n                }\n            }\n\n            function _0x343a1e(_0xc4b124, _0x1026d8, _0x47c875, _0x150a83, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x2b027d) {\n                var _0x1c87ab = w_0x25f3, _0x2f46a5, _0x5a2be0, _0x547138, _0x289168, _0x1e1872, _0xd2fd89,\n                    _0x17ee52 = _0x47c875[-0x2099 + -0x133 * 0x1 + 0x21cc];\n                if (_0x1dd313 ? _0x2f46a5 = 0xb0a + 0x2125 + -0x2c2f === _0x4cdf11 || 0x12ea + 0x5ba + 0x385 * -0x7 === _0x4cdf11 ? {\n                    'get': _0x47c875[0x1cf3 + 0x7 * -0x57d + 0x97b],\n                    'set': _0x47c875[0x6 * 0x210 + -0x2b3 * 0x3 + 0x1 * -0x443]\n                } : 0x1f7b + -0x2 * 0x1253 + 0x52e * 0x1 === _0x4cdf11 ? {\n                    'get': _0x47c875[0x1476 + 0x23 * -0xb5 + 0x44c]\n                } : 0x2290 + -0x20e6 + -0x1a6 === _0x4cdf11 ? {\n                    'set': _0x47c875[0x1465 * -0x1 + -0x1 * 0x7d9 + -0x1 * -0x1c41]\n                } : {\n                    'value': _0x47c875[-0x1550 + 0xb0f + 0xa44]\n                } : 0x8bb + 0x37b + 0x1 * -0xc36 !== _0x4cdf11 && (_0x2f46a5 = Object[_0x1c87ab(0x2a6)](_0x1026d8, _0x150a83)),\n                    -0xf * -0x49 + -0x8c3 * -0x1 + 0xd09 * -0x1 === _0x4cdf11 ? _0x547138 = {\n                        'get': _0x2f46a5[_0x1c87ab(0x32b)],\n                        'set': _0x2f46a5['set']\n                    } : -0x7c4 + 0x1da9 + -0x15e3 === _0x4cdf11 ? _0x547138 = _0x2f46a5[_0x1c87ab(0x2e4)] : 0x7e1 + -0x159a + 0xdbc === _0x4cdf11 ? _0x547138 = _0x2f46a5[_0x1c87ab(0x32b)] : 0x105 + 0x177d * 0x1 + 0xbe * -0x21 === _0x4cdf11 && (_0x547138 = _0x2f46a5['set']),\n                _0x1c87ab(0x1ee) == typeof _0x17ee52)\n                    void (-0x12c9 + 0x3 * -0x2f + 0x1e * 0xa5) !== (_0x289168 = _0x39ceae(_0x17ee52, _0x150a83, _0x2f46a5, _0x2b027d, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x547138)) && (_0x2de5e4(_0x4cdf11, _0x289168),\n                        -0x1cc9 + -0x2 * 0xb5d + 0x1 * 0x3383 === _0x4cdf11 ? _0x5a2be0 = _0x289168 : -0x1 * 0x1517 + 0x25 * 0x44 + 0xb44 === _0x4cdf11 ? (_0x5a2be0 = _0x289168[_0x1c87ab(0x3b9)],\n                            _0x1e1872 = _0x289168[_0x1c87ab(0x32b)] || _0x547138['get'],\n                            _0xd2fd89 = _0x289168[_0x1c87ab(0x1e4)] || _0x547138[_0x1c87ab(0x1e4)],\n                            _0x547138 = {\n                                'get': _0x1e1872,\n                                'set': _0xd2fd89\n                            }) : _0x547138 = _0x289168);\n                else\n                    for (var _0x5a46d9 = _0x17ee52[_0x1c87ab(0x259)] - (-0x49 * 0x19 + 0x4a2 + 0x280); _0x5a46d9 >= -0x225b + 0x1562 + 0xcf9; _0x5a46d9--) {\n                        var _0x60a0d7;\n                        void (-0xffd + 0x7 * -0x293 + 0x2202) !== (_0x289168 = _0x39ceae(_0x17ee52[_0x5a46d9], _0x150a83, _0x2f46a5, _0x2b027d, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x547138)) && (_0x2de5e4(_0x4cdf11, _0x289168),\n                            0x52 * -0x59 + 0x9 * -0x104 + 0x2 * 0x12d3 === _0x4cdf11 ? _0x60a0d7 = _0x289168 : -0x1689 + 0x1e96 + -0x80c === _0x4cdf11 ? (_0x60a0d7 = _0x289168['init'],\n                                _0x1e1872 = _0x289168[_0x1c87ab(0x32b)] || _0x547138['get'],\n                                _0xd2fd89 = _0x289168[_0x1c87ab(0x1e4)] || _0x547138[_0x1c87ab(0x1e4)],\n                                _0x547138 = {\n                                    'get': _0x1e1872,\n                                    'set': _0xd2fd89\n                                }) : _0x547138 = _0x289168,\n                        void (-0x1a77 + -0x136f + -0xeb * -0x32) !== _0x60a0d7 && (void (-0x519 + -0x1 * -0x1245 + -0x2 * 0x696) === _0x5a2be0 ? _0x5a2be0 = _0x60a0d7 : _0x1c87ab(0x1ee) == typeof _0x5a2be0 ? _0x5a2be0 = [_0x5a2be0, _0x60a0d7] : _0x5a2be0[_0x1c87ab(0x36e)](_0x60a0d7)));\n                    }\n                if (0x78c + 0x1d71 * -0x1 + 0x15e5 * 0x1 === _0x4cdf11 || -0x49 * 0x6 + 0x1e * 0xd2 + -0x1 * 0x16e5 === _0x4cdf11) {\n                    if (void (0x21db + 0x22d * 0xd + -0x3e24) === _0x5a2be0)\n                        _0x5a2be0 = function (_0x5345b0, _0x1a659b) {\n                            return _0x1a659b;\n                        }\n                        ;\n                    else {\n                        if ('function' != typeof _0x5a2be0) {\n                            var _0x336daa = _0x5a2be0;\n                            _0x5a2be0 = function (_0x30e05d, _0xf3b4df) {\n                                var _0x4d9e7f = _0x1c87ab;\n                                for (var _0x362c52 = _0xf3b4df, _0x22ed8a = 0x1 * 0x1f3c + -0x610 + -0x192c; _0x22ed8a < _0x336daa[_0x4d9e7f(0x259)]; _0x22ed8a++)\n                                    _0x362c52 = _0x336daa[_0x22ed8a]['call'](_0x30e05d, _0x362c52);\n                                return _0x362c52;\n                            }\n                            ;\n                        } else {\n                            var _0x5aed3b = _0x5a2be0;\n                            _0x5a2be0 = function (_0x5dc978, _0x5db160) {\n                                return _0x5aed3b['call'](_0x5dc978, _0x5db160);\n                            }\n                            ;\n                        }\n                    }\n                    _0xc4b124[_0x1c87ab(0x36e)](_0x5a2be0);\n                }\n                0x177a + -0xe7 * -0x1c + 0x22 * -0x16f !== _0x4cdf11 && (0x3af + 0x9 * -0x217 + 0x50b * 0x3 === _0x4cdf11 ? (_0x2f46a5[_0x1c87ab(0x32b)] = _0x547138[_0x1c87ab(0x32b)],\n                    _0x2f46a5[_0x1c87ab(0x1e4)] = _0x547138[_0x1c87ab(0x1e4)]) : 0x18a3 * -0x1 + 0x263c + -0xd97 === _0x4cdf11 ? _0x2f46a5[_0x1c87ab(0x2e4)] = _0x547138 : -0x4 * -0x31b + -0x837 * 0x4 + -0x5 * -0x417 === _0x4cdf11 ? _0x2f46a5[_0x1c87ab(0x32b)] = _0x547138 : -0x1a2e + 0x2 * 0x131d + -0xc08 === _0x4cdf11 && (_0x2f46a5[_0x1c87ab(0x1e4)] = _0x547138),\n                    _0x1dd313 ? -0x1 * -0x1757 + 0x1ada + -0x3230 === _0x4cdf11 ? (_0xc4b124[_0x1c87ab(0x36e)](function (_0xb886c1, _0x3a6bf5) {\n                        var _0x288d67 = _0x1c87ab;\n                        return _0x547138[_0x288d67(0x32b)][_0x288d67(0x334)](_0xb886c1, _0x3a6bf5);\n                    }),\n                        _0xc4b124[_0x1c87ab(0x36e)](function (_0x337452, _0x50608d) {\n                            var _0x44b896 = _0x1c87ab;\n                            return _0x547138[_0x44b896(0x1e4)][_0x44b896(0x334)](_0x337452, _0x50608d);\n                        })) : -0x2 * 0x93d + 0x297 + -0x139 * -0xd === _0x4cdf11 ? _0xc4b124['push'](_0x547138) : _0xc4b124[_0x1c87ab(0x36e)](function (_0x1e24c7, _0x120c64) {\n                        var _0x3e3294 = _0x1c87ab;\n                        return _0x547138[_0x3e3294(0x334)](_0x1e24c7, _0x120c64);\n                    }) : Object[_0x1c87ab(0x175)](_0x1026d8, _0x150a83, _0x2f46a5));\n            }\n\n            function _0x4c3a0d(_0x48207f, _0x257e35) {\n                var _0x1249e7 = w_0x25f3;\n                for (var _0x47fbbd, _0x402774, _0x333e3a = [], _0xe5fb1e = new Map(), _0x15f194 = new Map(), _0x41a1c1 = -0x1 * 0x575 + -0x13c0 + -0x1b * -0xef; _0x41a1c1 < _0x257e35[_0x1249e7(0x259)]; _0x41a1c1++) {\n                    var _0x63ddf3 = _0x257e35[_0x41a1c1];\n                    if (Array[_0x1249e7(0x2af)](_0x63ddf3)) {\n                        var _0x446366, _0x186385, _0x19186f = _0x63ddf3[-0x5bc * 0x4 + 0xf6a * -0x1 + -0x3 * -0xcc9],\n                            _0x4911c0 = _0x63ddf3[0x1 * 0x46 + -0xb73 + 0xb2f],\n                            _0x39f6a1 = _0x63ddf3['length'] > -0x4 * -0x101 + -0xe6c + 0xa6b,\n                            _0x27b8e1 = _0x19186f >= 0xb76 + 0x73 * -0x34 + 0x71 * 0x1b;\n                        if (_0x27b8e1 ? (_0x446366 = _0x48207f,\n                        0x26c + -0x157d + -0x65b * -0x3 != (_0x19186f -= 0x2324 + 0x27 * 0xbe + -0x4011) && (_0x186385 = _0x402774 = _0x402774 || [])) : (_0x446366 = _0x48207f[_0x1249e7(0x344)],\n                        -0x7 * 0x297 + 0x1b26 + -0x905 !== _0x19186f && (_0x186385 = _0x47fbbd = _0x47fbbd || [])),\n                        0x13d6 * -0x1 + 0x1 * 0xbb7 + 0x81f !== _0x19186f && !_0x39f6a1) {\n                            var _0x3f295f = _0x27b8e1 ? _0x15f194 : _0xe5fb1e\n                                ,\n                                _0x566c7b = _0x3f295f[_0x1249e7(0x32b)](_0x4911c0) || -0x188 * -0xb + 0x3e * 0x49 + -0x2286;\n                            if (!(0x903 * -0x1 + -0x1f * -0x8d + 0x1 * -0x810) === _0x566c7b || -0x43 * 0x5 + -0x1c6c + 0x2f * 0xa2 === _0x566c7b && -0x737 + -0x1ac2 + 0x21fd !== _0x19186f || 0xdd2 + -0x202b + 0x125d === _0x566c7b && -0x1 * 0x118d + -0x2b8 * -0x3 + 0x8 * 0x12d !== _0x19186f)\n                                throw new Error('Attempted\\x20to\\x20decorate\\x20a\\x20public\\x20method/accessor\\x20that\\x20has\\x20the\\x20same\\x20name\\x20as\\x20a\\x20previously\\x20decorated\\x20public\\x20method/accessor.\\x20This\\x20is\\x20not\\x20currently\\x20supported\\x20by\\x20the\\x20decorators\\x20plugin.\\x20Property\\x20name\\x20was:\\x20' + _0x4911c0);\n                            !_0x566c7b && _0x19186f > 0xf * -0x26f + 0x1 * 0x79d + 0x1ce6 * 0x1 ? _0x3f295f[_0x1249e7(0x1e4)](_0x4911c0, _0x19186f) : _0x3f295f['set'](_0x4911c0, !(0x4a * 0x71 + -0xad * 0x2 + 0x6 * -0x538));\n                        }\n                        _0x343a1e(_0x333e3a, _0x446366, _0x63ddf3, _0x4911c0, _0x19186f, _0x27b8e1, _0x39f6a1, _0x186385);\n                    }\n                }\n                return _0x45d367(_0x333e3a, _0x47fbbd),\n                    _0x45d367(_0x333e3a, _0x402774),\n                    _0x333e3a;\n            }\n\n            function _0x45d367(_0x59ffc8, _0x5ae59b) {\n                var _0x5b965e = w_0x25f3;\n                _0x5ae59b && _0x59ffc8[_0x5b965e(0x36e)](function (_0x3ed28e) {\n                    var _0x5985fb = _0x5b965e;\n                    for (var _0x5bcc94 = 0x156a + 0x18e0 + -0x2e4a; _0x5bcc94 < _0x5ae59b['length']; _0x5bcc94++)\n                        _0x5ae59b[_0x5bcc94][_0x5985fb(0x334)](_0x3ed28e);\n                    return _0x3ed28e;\n                });\n            }\n\n            return function (_0x33b4ae, _0x339d11, _0x5ebc36) {\n                return {\n                    'e': _0x4c3a0d(_0x33b4ae, _0x339d11),\n                    get 'c'() {\n                        return function (_0x92474e, _0x343c16) {\n                            var _0x3cc4d2 = w_0x25f3;\n                            if (_0x343c16['length'] > -0x271 + -0x2690 + 0x2901) {\n                                for (var _0x18f66c = [], _0x1dd6eb = _0x92474e, _0x1d8833 = _0x92474e[_0x3cc4d2(0x341)], _0x163025 = _0x343c16[_0x3cc4d2(0x259)] - (0x1 * -0x20ed + 0x1f94 + 0x2 * 0xad); _0x163025 >= 0xfba + 0x22 * 0xb6 + 0x27e6 * -0x1; _0x163025--) {\n                                    var _0x49ea6f = {\n                                        'v': !(-0x524 + 0x1a34 + -0x150f)\n                                    };\n                                    try {\n                                        var _0x181a9d = _0x343c16[_0x163025](_0x1dd6eb, {\n                                            'kind': _0x3cc4d2(0x19c),\n                                            'name': _0x1d8833,\n                                            'addInitializer': _0x135cea(_0x18f66c, _0x49ea6f)\n                                        });\n                                    } finally {\n                                        _0x49ea6f['v'] = !(-0x23e + 0x1 * -0x7fb + 0xa39);\n                                    }\n                                    void (-0x1 * -0x253d + -0x23d + -0x80 * 0x46) !== _0x181a9d && (_0x2de5e4(0x4c5 + 0xcaf + -0x2e7 * 0x6, _0x181a9d),\n                                        _0x1dd6eb = _0x181a9d);\n                                }\n                                return [_0x1dd6eb, function () {\n                                    var _0x543396 = _0x3cc4d2;\n                                    for (var _0x2a7175 = -0xe71 * -0x1 + 0x24c0 + -0xa3d * 0x5; _0x2a7175 < _0x18f66c['length']; _0x2a7175++)\n                                        _0x18f66c[_0x2a7175][_0x543396(0x334)](_0x1dd6eb);\n                                }\n                                ];\n                            }\n                        }(_0x33b4ae, _0x5ebc36);\n                    }\n                };\n            }\n                ;\n        }\n\n        function _0x49af1f(_0x3a86ea, _0x270f72, _0x219a67) {\n            return (_0x49af1f = _0x4591cd())(_0x3a86ea, _0x270f72, _0x219a67);\n        }\n\n        function _0x3e4ff5(_0x5b206b, _0xdfb3e7) {\n            return function (_0x19bdbd) {\n                var _0x1caf0f = w_0x25f3;\n                _0x15eb90(_0xdfb3e7, _0x1caf0f(0x225)),\n                    _0x45d8b1(_0x19bdbd, _0x1caf0f(0x3ba)),\n                    _0x5b206b[_0x1caf0f(0x36e)](_0x19bdbd);\n            }\n                ;\n        }\n\n        function _0x19207d(_0x45ced6, _0xcee03f) {\n            var _0x41489e = w_0x25f3;\n            if (!_0x45ced6(_0xcee03f))\n                throw new TypeError(_0x41489e(0x255));\n        }\n\n        function _0x151762(_0x535a19, _0x4e0a69, _0x270f96, _0x52f7e9, _0x23d388, _0x49094d, _0x49f620, _0x251987, _0x40c067) {\n            var _0x3b49d7 = w_0x25f3, _0x5d54d8;\n            switch (_0x23d388) {\n                case -0x14b9 + 0x1dd5 + -0x91b:\n                    _0x5d54d8 = _0x3b49d7(0x1b9);\n                    break;\n                case -0xe4a + 0x12be + -0x472:\n                    _0x5d54d8 = _0x3b49d7(0x25a);\n                    break;\n                case -0x10f1 * -0x2 + 0x179 * 0x19 + -0x46b0:\n                    _0x5d54d8 = _0x3b49d7(0x181);\n                    break;\n                case 0x3 * -0x5cf + 0x778 * 0x1 + 0x353 * 0x3:\n                    _0x5d54d8 = _0x3b49d7(0x35d);\n                    break;\n                default:\n                    _0x5d54d8 = _0x3b49d7(0x23c);\n            }\n            var _0x246ff5, _0x4e02d1, _0x45ccfd = {\n                'kind': _0x5d54d8,\n                'name': _0x49f620 ? '#' + _0x4e0a69 : _0x4e0a69,\n                'static': _0x49094d,\n                'private': _0x49f620\n            }, _0x4733a4 = {\n                'v': !(-0xad5 + 0x1f * -0x59 + -0x1f7 * -0xb)\n            };\n            if (0xcf6 + 0x1e15 + -0x3 * 0xe59 !== _0x23d388 && (_0x45ccfd[_0x3b49d7(0x225)] = _0x3e4ff5(_0x52f7e9, _0x4733a4)),\n            _0x49f620 || -0x112e + -0x23ab + 0x34d9 !== _0x23d388 && 0xa00 + -0x234a + 0x194c !== _0x23d388) {\n                if (-0x327 * -0x2 + -0xb00 + 0x4b4 === _0x23d388)\n                    _0x246ff5 = function (_0x36bc44) {\n                        var _0x2d48fd = _0x3b49d7;\n                        return _0x19207d(_0x40c067, _0x36bc44),\n                            _0x270f96[_0x2d48fd(0x2e4)];\n                    }\n                    ;\n                else {\n                    var _0x339c00 = -0x1746 + -0x1bb + 0xad * 0x25 === _0x23d388 || -0x859 + 0x4 * -0xe2 + -0x27 * -0x4e === _0x23d388;\n                    (_0x339c00 || 0x5 * -0x3bf + -0x1d90 + 0x304e === _0x23d388) && (_0x246ff5 = _0x49f620 ? function (_0x26da64) {\n                                var _0x21bb3a = _0x3b49d7;\n                                return _0x19207d(_0x40c067, _0x26da64),\n                                    _0x270f96['get'][_0x21bb3a(0x334)](_0x26da64);\n                            }\n                            : function (_0x2ac873) {\n                                var _0xa2fd4f = _0x3b49d7;\n                                return _0x270f96[_0xa2fd4f(0x32b)][_0xa2fd4f(0x334)](_0x2ac873);\n                            }\n                    ),\n                    (_0x339c00 || -0x14c4 * 0x1 + -0x231e + -0xb2e * -0x5 === _0x23d388) && (_0x4e02d1 = _0x49f620 ? function (_0x1e61ca, _0x1c77b0) {\n                                var _0x5f2230 = _0x3b49d7;\n                                _0x19207d(_0x40c067, _0x1e61ca),\n                                    _0x270f96[_0x5f2230(0x1e4)][_0x5f2230(0x334)](_0x1e61ca, _0x1c77b0);\n                            }\n                            : function (_0x4d5a08, _0x3ac6c6) {\n                                var _0x1baec7 = _0x3b49d7;\n                                _0x270f96[_0x1baec7(0x1e4)][_0x1baec7(0x334)](_0x4d5a08, _0x3ac6c6);\n                            }\n                    );\n                }\n            } else\n                _0x246ff5 = function (_0x4ff2b5) {\n                    return _0x4ff2b5[_0x4e0a69];\n                }\n                    ,\n                -0x20ec + 0x12ee * 0x2 + -0x4f0 === _0x23d388 && (_0x4e02d1 = function (_0x2f8383, _0x4a22e5) {\n                        _0x2f8383[_0x4e0a69] = _0x4a22e5;\n                    }\n                );\n            var _0x557c63 = _0x49f620 ? _0x40c067[_0x3b49d7(0x301)]() : function (_0x2f4445) {\n                    return _0x4e0a69 in _0x2f4445;\n                }\n            ;\n            _0x45ccfd[_0x3b49d7(0x1d0)] = _0x246ff5 && _0x4e02d1 ? {\n                'get': _0x246ff5,\n                'set': _0x4e02d1,\n                'has': _0x557c63\n            } : _0x246ff5 ? {\n                'get': _0x246ff5,\n                'has': _0x557c63\n            } : {\n                'set': _0x4e02d1,\n                'has': _0x557c63\n            };\n            try {\n                return _0x535a19(_0x251987, _0x45ccfd);\n            } finally {\n                _0x4733a4['v'] = !(0xea8 + -0xe9f * 0x1 + 0x1 * -0x9);\n            }\n        }\n\n        function _0x15eb90(_0x202051, _0x1c2373) {\n            var _0x51521b = w_0x25f3;\n            if (_0x202051['v'])\n                throw new Error('attempted\\x20to\\x20call\\x20' + _0x1c2373 + _0x51521b(0x168));\n        }\n\n        function _0x45d8b1(_0x2ad532, _0x423791) {\n            var _0x14562d = w_0x25f3;\n            if (_0x14562d(0x1ee) != typeof _0x2ad532)\n                throw new TypeError(_0x423791 + _0x14562d(0x2f8));\n        }\n\n        function _0xed525b(_0x522a86, _0x4177e1) {\n            var _0x442324 = w_0x25f3\n                , _0x399204 = typeof _0x4177e1;\n            if (-0x361 + 0x3 * 0x2c4 + 0x4ea * -0x1 === _0x522a86) {\n                if (_0x442324(0x17d) !== _0x399204 || null === _0x4177e1)\n                    throw new TypeError(_0x442324(0x1fd));\n                void (-0x4a0 + 0x2e8 + 0x1b8) !== _0x4177e1[_0x442324(0x32b)] && _0x45d8b1(_0x4177e1[_0x442324(0x32b)], _0x442324(0x170)),\n                void (0xc4 * -0x1d + 0x651 + 0xfe3) !== _0x4177e1['set'] && _0x45d8b1(_0x4177e1[_0x442324(0x1e4)], _0x442324(0x231)),\n                void (-0x168c + 0x16b5 * 0x1 + 0x29 * -0x1) !== _0x4177e1['init'] && _0x45d8b1(_0x4177e1[_0x442324(0x3b9)], _0x442324(0x22f));\n            } else {\n                if (_0x442324(0x1ee) !== _0x399204)\n                    throw new TypeError((0x20d7 + 0x7 * -0x362 + 0x7 * -0x14f === _0x522a86 ? _0x442324(0x23c) : 0x1 * -0x1257 + -0x2d9 + -0x26 * -0x8f === _0x522a86 ? 'class' : 'method') + '\\x20decorators\\x20must\\x20return\\x20a\\x20function\\x20or\\x20void\\x200');\n            }\n        }\n\n        function _0x244c39(_0x17683) {\n            return function () {\n                return _0x17683(this);\n            }\n                ;\n        }\n\n        function _0x48532c(_0x5503e0) {\n            return function (_0x23d6a1) {\n                _0x5503e0(this, _0x23d6a1);\n            }\n                ;\n        }\n\n        function _0x23e6b(_0x5cf198, _0x5646db, _0x26f9f9, _0x37f54b, _0x47565f, _0x2aa948, _0xccabc1, _0x5c3a48, _0x9ffbdc) {\n            var _0x3e2adf = w_0x25f3, _0x592aeb, _0x365a6e, _0x4e8d10, _0x589008, _0x17d95a, _0x11c9ab,\n                _0x9a7bbd = _0x26f9f9[0xa46 + 0xb3c + -0x1582];\n            if (_0xccabc1 ? _0x592aeb = 0x24 * 0x47 + 0xf85 + -0x1981 === _0x47565f || 0x14ca + -0x1099 + 0x218 * -0x2 === _0x47565f ? {\n                'get': _0x244c39(_0x26f9f9[0x7 * -0x2f0 + 0x227b + -0xde8]),\n                'set': _0x48532c(_0x26f9f9[-0xad * -0x19 + -0xc3c + 0x29 * -0x1d])\n            } : 0x1b99 * -0x1 + 0x367 + -0x1 * -0x1835 === _0x47565f ? {\n                'get': _0x26f9f9[0xb1 * 0x22 + 0x3 * 0xcef + -0x24 * 0x1bb]\n            } : 0x1 * -0x10f + -0x1 * -0x2023 + -0x1f10 === _0x47565f ? {\n                'set': _0x26f9f9[0x36 * -0xa6 + -0x1cb2 + 0x3fb9]\n            } : {\n                'value': _0x26f9f9[-0x7ba * 0x1 + 0x1850 + -0x1093]\n            } : -0x2 * 0x713 + 0x26fe + 0x27c * -0xa !== _0x47565f && (_0x592aeb = Object[_0x3e2adf(0x2a6)](_0x5646db, _0x37f54b)),\n                -0x1982 + 0x1947 + 0x14 * 0x3 === _0x47565f ? _0x4e8d10 = {\n                    'get': _0x592aeb[_0x3e2adf(0x32b)],\n                    'set': _0x592aeb[_0x3e2adf(0x1e4)]\n                } : 0xe9b + -0x2a3 + 0x5fb * -0x2 === _0x47565f ? _0x4e8d10 = _0x592aeb['value'] : -0x13 * -0x5b + 0x17cb + -0x1 * 0x1e89 === _0x47565f ? _0x4e8d10 = _0x592aeb[_0x3e2adf(0x32b)] : 0x7d7 * -0x1 + 0x5 * 0x81 + 0x556 === _0x47565f && (_0x4e8d10 = _0x592aeb['set']),\n            'function' == typeof _0x9a7bbd)\n                void (0x1 * 0x1ee3 + 0xd + -0x1ef0) !== (_0x589008 = _0x151762(_0x9a7bbd, _0x37f54b, _0x592aeb, _0x5c3a48, _0x47565f, _0x2aa948, _0xccabc1, _0x4e8d10, _0x9ffbdc)) && (_0xed525b(_0x47565f, _0x589008),\n                    0xc91 * -0x1 + -0x893 * -0x1 + 0x3fe === _0x47565f ? _0x365a6e = _0x589008 : -0x1 * 0x21dd + -0x109 * -0x24 + -0x366 === _0x47565f ? (_0x365a6e = _0x589008[_0x3e2adf(0x3b9)],\n                        _0x17d95a = _0x589008[_0x3e2adf(0x32b)] || _0x4e8d10[_0x3e2adf(0x32b)],\n                        _0x11c9ab = _0x589008['set'] || _0x4e8d10[_0x3e2adf(0x1e4)],\n                        _0x4e8d10 = {\n                            'get': _0x17d95a,\n                            'set': _0x11c9ab\n                        }) : _0x4e8d10 = _0x589008);\n            else\n                for (var _0x4f1458 = _0x9a7bbd['length'] - (0x204c + 0x277 * 0x7 + -0xe * 0x38a); _0x4f1458 >= -0x23c2 + 0x91 + 0x2331; _0x4f1458--) {\n                    var _0x189ac8;\n                    void (-0x18f8 * -0x1 + -0x143a + -0x1 * 0x4be) !== (_0x589008 = _0x151762(_0x9a7bbd[_0x4f1458], _0x37f54b, _0x592aeb, _0x5c3a48, _0x47565f, _0x2aa948, _0xccabc1, _0x4e8d10, _0x9ffbdc)) && (_0xed525b(_0x47565f, _0x589008),\n                        -0x22cb + -0x2043 * -0x1 + 0x288 === _0x47565f ? _0x189ac8 = _0x589008 : 0x1bd * -0x3 + 0x283 * 0x8 + 0x2 * -0x770 === _0x47565f ? (_0x189ac8 = _0x589008[_0x3e2adf(0x3b9)],\n                            _0x17d95a = _0x589008[_0x3e2adf(0x32b)] || _0x4e8d10[_0x3e2adf(0x32b)],\n                            _0x11c9ab = _0x589008[_0x3e2adf(0x1e4)] || _0x4e8d10['set'],\n                            _0x4e8d10 = {\n                                'get': _0x17d95a,\n                                'set': _0x11c9ab\n                            }) : _0x4e8d10 = _0x589008,\n                    void (-0xaeb + 0x1 * 0x1bb3 + 0x4 * -0x432) !== _0x189ac8 && (void (-0x2359 + -0x3 * -0x323 + 0x19f0) === _0x365a6e ? _0x365a6e = _0x189ac8 : _0x3e2adf(0x1ee) == typeof _0x365a6e ? _0x365a6e = [_0x365a6e, _0x189ac8] : _0x365a6e[_0x3e2adf(0x36e)](_0x189ac8)));\n                }\n            if (0x21ee + -0x129b + 0xf53 * -0x1 === _0x47565f || -0x44d * -0x7 + -0xa27 + -0x13f3 * 0x1 === _0x47565f) {\n                if (void (0x10 * -0x218 + -0x707 * 0x1 + 0x2887) === _0x365a6e)\n                    _0x365a6e = function (_0x56b70b, _0x5e4d55) {\n                        return _0x5e4d55;\n                    }\n                    ;\n                else {\n                    if (_0x3e2adf(0x1ee) != typeof _0x365a6e) {\n                        var _0x3101a1 = _0x365a6e;\n                        _0x365a6e = function (_0x449bbf, _0x5196d8) {\n                            var _0x360050 = _0x3e2adf;\n                            for (var _0x143a4f = _0x5196d8, _0x36e4b1 = -0x1ef8 + -0x3 * -0xd01 + -0x80b * 0x1; _0x36e4b1 < _0x3101a1[_0x360050(0x259)]; _0x36e4b1++)\n                                _0x143a4f = _0x3101a1[_0x36e4b1][_0x360050(0x334)](_0x449bbf, _0x143a4f);\n                            return _0x143a4f;\n                        }\n                        ;\n                    } else {\n                        var _0x1e2902 = _0x365a6e;\n                        _0x365a6e = function (_0xe6998d, _0xec7c91) {\n                            var _0x5bb1b6 = _0x3e2adf;\n                            return _0x1e2902[_0x5bb1b6(0x334)](_0xe6998d, _0xec7c91);\n                        }\n                        ;\n                    }\n                }\n                _0x5cf198['push'](_0x365a6e);\n            }\n            0x82e + 0x14c5 + -0x1cf3 !== _0x47565f && (-0x1 * -0x1d72 + 0x15b0 + 0x3 * -0x110b === _0x47565f ? (_0x592aeb[_0x3e2adf(0x32b)] = _0x4e8d10[_0x3e2adf(0x32b)],\n                _0x592aeb['set'] = _0x4e8d10['set']) : 0x1de7 + -0x16 * -0x10a + -0x34c1 === _0x47565f ? _0x592aeb[_0x3e2adf(0x2e4)] = _0x4e8d10 : -0x2508 + -0x2665 + 0x4b70 === _0x47565f ? _0x592aeb[_0x3e2adf(0x32b)] = _0x4e8d10 : 0x11 * -0x9f + -0x6a5 + 0x1138 === _0x47565f && (_0x592aeb[_0x3e2adf(0x1e4)] = _0x4e8d10),\n                _0xccabc1 ? 0x8f6 * 0x1 + -0xae9 + 0xa * 0x32 === _0x47565f ? (_0x5cf198['push'](function (_0x31015b, _0x979f27) {\n                    var _0x1938a1 = _0x3e2adf;\n                    return _0x4e8d10['get'][_0x1938a1(0x334)](_0x31015b, _0x979f27);\n                }),\n                    _0x5cf198[_0x3e2adf(0x36e)](function (_0x506584, _0x44c428) {\n                        var _0x29e7e5 = _0x3e2adf;\n                        return _0x4e8d10['set'][_0x29e7e5(0x334)](_0x506584, _0x44c428);\n                    })) : 0x27 * -0xd0 + 0x4 * -0x12d + 0x2466 === _0x47565f ? _0x5cf198[_0x3e2adf(0x36e)](_0x4e8d10) : _0x5cf198[_0x3e2adf(0x36e)](function (_0x3345b4, _0x845662) {\n                    var _0x1b7734 = _0x3e2adf;\n                    return _0x4e8d10[_0x1b7734(0x334)](_0x3345b4, _0x845662);\n                }) : Object['defineProperty'](_0x5646db, _0x37f54b, _0x592aeb));\n        }\n\n        function _0x754898(_0x2bd2c5, _0x2c3dcd, _0x119780) {\n            var _0x42b3ee = w_0x25f3;\n            for (var _0x328f7d, _0x12addf, _0x29a079, _0x3330d8 = [], _0x484293 = new Map(), _0x4a2ea8 = new Map(), _0x478e5d = 0x1 * -0x3e1 + -0x22b8 + 0x2699; _0x478e5d < _0x2c3dcd[_0x42b3ee(0x259)]; _0x478e5d++) {\n                var _0x5c7927 = _0x2c3dcd[_0x478e5d];\n                if (Array[_0x42b3ee(0x2af)](_0x5c7927)) {\n                    var _0x25ea34, _0x5b9b12, _0x35b641 = _0x5c7927[-0x33b * 0x1 + 0xebe + 0x3 * -0x3d6],\n                        _0x49a803 = _0x5c7927[-0x78a + -0x29 * 0x60 + 0xc * 0x1e9],\n                        _0x410da0 = _0x5c7927[_0x42b3ee(0x259)] > 0x1291 + -0x1e03 + 0xb75,\n                        _0x3c9168 = _0x35b641 >= -0x13e1 * 0x1 + 0x793 + -0x5 * -0x277, _0x41ada5 = _0x119780;\n                    if (_0x3c9168 ? (_0x25ea34 = _0x2bd2c5,\n                    -0x7e3 + -0x1087 * 0x2 + 0x28f1 != (_0x35b641 -= 0x867 + 0xa1b + 0x127d * -0x1) && (_0x5b9b12 = _0x12addf = _0x12addf || []),\n                    _0x410da0 && !_0x29a079 && (_0x29a079 = function (_0x106ee5) {\n                            return _0x37e1e2(_0x106ee5) === _0x2bd2c5;\n                        }\n                    ),\n                        _0x41ada5 = _0x29a079) : (_0x25ea34 = _0x2bd2c5['prototype'],\n                    0x13a3 * 0x1 + -0x2589 + 0x11e6 * 0x1 !== _0x35b641 && (_0x5b9b12 = _0x328f7d = _0x328f7d || [])),\n                    0xfad + 0x3 * -0xceb + 0x1714 !== _0x35b641 && !_0x410da0) {\n                        var _0x4430b1 = _0x3c9168 ? _0x4a2ea8 : _0x484293\n                            , _0x3a9a47 = _0x4430b1[_0x42b3ee(0x32b)](_0x49a803) || 0x139e + -0xa * 0x13d + -0x73c;\n                        if (!(-0x1 * 0x5df + 0x94b + -0x36c) === _0x3a9a47 || 0x3 * 0x38 + -0x25b * 0x7 + -0x8 * -0x1fb === _0x3a9a47 && 0x54 + 0x152e + -0x2a * 0x83 !== _0x35b641 || 0x2 * -0x1cb + 0x1e71 + -0x1ad7 * 0x1 === _0x3a9a47 && 0x6e9 + 0xa71 + 0xc1 * -0x17 !== _0x35b641)\n                            throw new Error('Attempted\\x20to\\x20decorate\\x20a\\x20public\\x20method/accessor\\x20that\\x20has\\x20the\\x20same\\x20name\\x20as\\x20a\\x20previously\\x20decorated\\x20public\\x20method/accessor.\\x20This\\x20is\\x20not\\x20currently\\x20supported\\x20by\\x20the\\x20decorators\\x20plugin.\\x20Property\\x20name\\x20was:\\x20' + _0x49a803);\n                        !_0x3a9a47 && _0x35b641 > -0x73 * -0x45 + 0x798 + -0x2695 ? _0x4430b1['set'](_0x49a803, _0x35b641) : _0x4430b1['set'](_0x49a803, !(0x1 * 0xb7c + -0x15ce * 0x1 + 0xa52));\n                    }\n                    _0x23e6b(_0x3330d8, _0x25ea34, _0x5c7927, _0x49a803, _0x35b641, _0x3c9168, _0x410da0, _0x5b9b12, _0x41ada5);\n                }\n            }\n            return _0xdfc9aa(_0x3330d8, _0x328f7d),\n                _0xdfc9aa(_0x3330d8, _0x12addf),\n                _0x3330d8;\n        }\n\n        function _0xdfc9aa(_0x18680e, _0x994303) {\n            var _0x3df611 = w_0x25f3;\n            _0x994303 && _0x18680e[_0x3df611(0x36e)](function (_0x3720d6) {\n                var _0xc905ee = _0x3df611;\n                for (var _0x400047 = 0x17dc + -0x3df * 0x6 + -0xa2; _0x400047 < _0x994303['length']; _0x400047++)\n                    _0x994303[_0x400047][_0xc905ee(0x334)](_0x3720d6);\n                return _0x3720d6;\n            });\n        }\n\n        function _0x2258b9(_0x31d7ec, _0x22dcdb) {\n            var _0x41474b = w_0x25f3;\n            if (_0x22dcdb[_0x41474b(0x259)] > 0x26a0 + -0x145f + -0x1241) {\n                for (var _0x3c54e9 = [], _0x8cb428 = _0x31d7ec, _0x2344cd = _0x31d7ec['name'], _0x16f8af = _0x22dcdb[_0x41474b(0x259)] - (0x1321 + 0x1388 + 0x1354 * -0x2); _0x16f8af >= 0x1a79 + 0x6f * 0x2a + -0x2caf; _0x16f8af--) {\n                    var _0x36735e = {\n                        'v': !(0x4 * -0x601 + 0x116d * 0x1 + -0x698 * -0x1)\n                    };\n                    try {\n                        var _0x147e7c = _0x22dcdb[_0x16f8af](_0x8cb428, {\n                            'kind': _0x41474b(0x19c),\n                            'name': _0x2344cd,\n                            'addInitializer': _0x3e4ff5(_0x3c54e9, _0x36735e)\n                        });\n                    } finally {\n                        _0x36735e['v'] = !(0x1e88 + -0x1973 + -0x515 * 0x1);\n                    }\n                    void (-0xedb + -0x5 * 0x2bf + 0x1c96) !== _0x147e7c && (_0xed525b(0x10b8 + -0xb * 0x2e1 + -0x3 * -0x4ff, _0x147e7c),\n                        _0x8cb428 = _0x147e7c);\n                }\n                return [_0x8cb428, function () {\n                    var _0x28afa7 = _0x41474b;\n                    for (var _0x4967c5 = -0x1 * 0x23b5 + -0x2 * -0x4c7 + 0x203 * 0xd; _0x4967c5 < _0x3c54e9[_0x28afa7(0x259)]; _0x4967c5++)\n                        _0x3c54e9[_0x4967c5][_0x28afa7(0x334)](_0x8cb428);\n                }\n                ];\n            }\n        }\n\n        function _0x499d65(_0x2be690, _0x428d43, _0x381e26, _0x409a13) {\n            return {\n                'e': _0x754898(_0x2be690, _0x428d43, _0x409a13),\n                get 'c'() {\n                    return _0x2258b9(_0x2be690, _0x381e26);\n                }\n            };\n        }\n\n        function _0x63f01f(_0x5fd149) {\n            var _0x2e1243 = w_0x25f3\n                , _0x111c4c = {}\n                , _0x2aa094 = !(-0x3d * -0x53 + -0x2086 * -0x1 + -0x344c);\n\n            function _0x3ad3fe(_0x4a2256, _0x3bcff1) {\n                return _0x2aa094 = !(0x160 * 0x3 + -0x4b5 * 0x1 + 0x1 * 0x95),\n                    {\n                        'done': !(0x1cd3 + 0x1 * -0xa11 + -0x12c1 * 0x1),\n                        'value': new _0x59d886(_0x3bcff1 = new Promise(function (_0x353966) {\n                                _0x353966(_0x5fd149[_0x4a2256](_0x3bcff1));\n                            }\n                        ), 0x2b * 0x44 + -0x8b3 * 0x2 + 0x1 * 0x5fb)\n                    };\n            }\n\n            return _0x111c4c[_0x2e1243(0x384) != typeof Symbol && Symbol['iterator'] || _0x2e1243(0x1dd)] = function () {\n                return this;\n            }\n                ,\n                _0x111c4c[_0x2e1243(0x389)] = function (_0x45912d) {\n                    return _0x2aa094 ? (_0x2aa094 = !(0x1569 + 0x7 * 0x314 + -0x2af4),\n                        _0x45912d) : _0x3ad3fe('next', _0x45912d);\n                }\n                ,\n            _0x2e1243(0x1ee) == typeof _0x5fd149[_0x2e1243(0x250)] && (_0x111c4c[_0x2e1243(0x250)] = function (_0xd71e81) {\n                    var _0x37886e = _0x2e1243;\n                    if (_0x2aa094)\n                        throw _0x2aa094 = !(-0x648 + -0x1eca + -0x2513 * -0x1),\n                            _0xd71e81;\n                    return _0x3ad3fe(_0x37886e(0x250), _0xd71e81);\n                }\n            ),\n            _0x2e1243(0x1ee) == typeof _0x5fd149[_0x2e1243(0x2fd)] && (_0x111c4c[_0x2e1243(0x2fd)] = function (_0xd4b711) {\n                    return _0x2aa094 ? (_0x2aa094 = !(-0x8e1 * -0x4 + -0x2194 + 0x3 * -0xa5),\n                        _0xd4b711) : _0x3ad3fe('return', _0xd4b711);\n                }\n            ),\n                _0x111c4c;\n        }\n\n        function _0x278b9f(_0x12b945) {\n            var _0x55cd1f = w_0x25f3, _0x449dfe, _0x31b182, _0x218f32, _0x2ecb8a = -0x1d9 * -0x5 + -0x5d4 + -0x367;\n            for ('undefined' != typeof Symbol && (_0x31b182 = Symbol[_0x55cd1f(0x17c)],\n                _0x218f32 = Symbol[_0x55cd1f(0x3b3)]); _0x2ecb8a--;) {\n                if (_0x31b182 && null != (_0x449dfe = _0x12b945[_0x31b182]))\n                    return _0x449dfe[_0x55cd1f(0x334)](_0x12b945);\n                if (_0x218f32 && null != (_0x449dfe = _0x12b945[_0x218f32]))\n                    return new _0x3d6fc9(_0x449dfe[_0x55cd1f(0x334)](_0x12b945));\n                _0x31b182 = _0x55cd1f(0x230),\n                    _0x218f32 = _0x55cd1f(0x1dd);\n            }\n            throw new TypeError(_0x55cd1f(0x2a9));\n        }\n\n        function _0x3d6fc9(_0x4d37b6) {\n            var _0x36b1b0 = w_0x25f3;\n\n            function _0x6c368b(_0x231d6c) {\n                var _0x3a3e78 = w_0x25f3;\n                if (Object(_0x231d6c) !== _0x231d6c)\n                    return Promise['reject'](new TypeError(_0x231d6c + _0x3a3e78(0x3a6)));\n                var _0x4cdd04 = _0x231d6c[_0x3a3e78(0x1e3)];\n                return Promise['resolve'](_0x231d6c[_0x3a3e78(0x2e4)])['then'](function (_0x468cc1) {\n                    return {\n                        'value': _0x468cc1,\n                        'done': _0x4cdd04\n                    };\n                });\n            }\n\n            return (_0x3d6fc9 = function (_0x5a83bf) {\n                    var _0x2ffee8 = w_0x25f3;\n                    this['s'] = _0x5a83bf,\n                        this['n'] = _0x5a83bf[_0x2ffee8(0x389)];\n                }\n            )[_0x36b1b0(0x344)] = {\n                's': null,\n                'n': null,\n                'next': function () {\n                    var _0x1eac7c = _0x36b1b0;\n                    return _0x6c368b(this['n'][_0x1eac7c(0x207)](this['s'], arguments));\n                },\n                'return': function (_0x379438) {\n                    var _0x45dc23 = _0x36b1b0\n                        , _0x35ef86 = this['s'][_0x45dc23(0x2fd)];\n                    return void (0x23cd + 0x6f3 * 0x1 + -0x48 * 0x98) === _0x35ef86 ? Promise[_0x45dc23(0x278)]({\n                        'value': _0x379438,\n                        'done': !(-0x220 + -0x16b0 + 0x8 * 0x31a)\n                    }) : _0x6c368b(_0x35ef86[_0x45dc23(0x207)](this['s'], arguments));\n                },\n                'throw': function (_0x2ca86a) {\n                    var _0x5812c4 = _0x36b1b0\n                        , _0x449ee5 = this['s'][_0x5812c4(0x2fd)];\n                    return void (0xe3b + 0x1 * -0x128e + 0x453) === _0x449ee5 ? Promise[_0x5812c4(0x39b)](_0x2ca86a) : _0x6c368b(_0x449ee5['apply'](this['s'], arguments));\n                }\n            },\n                new _0x3d6fc9(_0x4d37b6);\n        }\n\n        function _0x81c36b(_0x305287) {\n            return new _0x59d886(_0x305287, -0x5e + 0xf84 + -0xf26 * 0x1);\n        }\n\n        function _0x37e1e2(_0x3127ce) {\n            var _0x43b88e = w_0x25f3;\n            if (Object(_0x3127ce) !== _0x3127ce)\n                throw TypeError('right-hand\\x20side\\x20of\\x20\\x27in\\x27\\x20should\\x20be\\x20an\\x20object,\\x20got\\x20' + (null !== _0x3127ce ? typeof _0x3127ce : _0x43b88e(0x308)));\n            return _0x3127ce;\n        }\n\n        function _0x564673(_0x18bd7c, _0x51fb0f, _0x2103c5, _0x5f4619) {\n            var _0x41c64 = w_0x25f3\n                , _0xab8c16 = {\n                'configurable': !(-0x15c4 + 0x25f7 * -0x1 + 0x3bbb),\n                'enumerable': !(0x2581 + -0x121c + -0x1365)\n            };\n            return _0xab8c16[_0x18bd7c] = _0x5f4619,\n                Object[_0x41c64(0x175)](_0x51fb0f, _0x2103c5, _0xab8c16);\n        }\n\n        function _0x19d66a(_0x14c297, _0x128d38) {\n            var _0x48eab4 = w_0x25f3\n                ,\n                _0x25f943 = null == _0x14c297 ? null : _0x48eab4(0x384) != typeof Symbol && _0x14c297[Symbol[_0x48eab4(0x3b3)]] || _0x14c297[_0x48eab4(0x1dd)];\n            if (null != _0x25f943) {\n                var _0x285958, _0x5bcc9e, _0x2d4c39, _0x193c70, _0x146015 = [],\n                    _0x16efb7 = !(-0x7e * 0x36 + 0xcff * 0x1 + 0xd95),\n                    _0x5c9556 = !(-0x1d71 * -0x1 + 0x434 * -0x9 + 0x864);\n                try {\n                    if (_0x2d4c39 = (_0x25f943 = _0x25f943[_0x48eab4(0x334)](_0x14c297))['next'],\n                    -0xe3 * -0xb + -0x1f3 * 0xe + -0x43 * -0x43 === _0x128d38) {\n                        if (Object(_0x25f943) !== _0x25f943)\n                            return;\n                        _0x16efb7 = !(0x17cb + 0x18a9 + -0x4f * 0x9d);\n                    } else {\n                        for (; !(_0x16efb7 = (_0x285958 = _0x2d4c39['call'](_0x25f943))[_0x48eab4(0x1e3)]) && (_0x146015[_0x48eab4(0x36e)](_0x285958[_0x48eab4(0x2e4)]),\n                        _0x146015[_0x48eab4(0x259)] !== _0x128d38); _0x16efb7 = !(0x1 * -0x22d3 + 0x1f2e + 0x3 * 0x137))\n                            ;\n                    }\n                } catch (_0x22e14d) {\n                    _0x5c9556 = !(-0x3 * -0x69e + -0xd79 + -0x47 * 0x17),\n                        _0x5bcc9e = _0x22e14d;\n                } finally {\n                    try {\n                        if (!_0x16efb7 && null != _0x25f943[_0x48eab4(0x2fd)] && (_0x193c70 = _0x25f943['return'](),\n                        Object(_0x193c70) !== _0x193c70))\n                            return;\n                    } finally {\n                        if (_0x5c9556)\n                            throw _0x5bcc9e;\n                    }\n                }\n                return _0x146015;\n            }\n        }\n\n        function _0x376fd5(_0x233550, _0x1b337f) {\n            var _0x545ac4 = w_0x25f3\n                ,\n                _0x524438 = _0x233550 && (_0x545ac4(0x384) != typeof Symbol && _0x233550[Symbol[_0x545ac4(0x3b3)]] || _0x233550['@@iterator']);\n            if (null != _0x524438) {\n                var _0x259ce6, _0x4523ee = [];\n                for (_0x524438 = _0x524438['call'](_0x233550); _0x233550[_0x545ac4(0x259)] < _0x1b337f && !(_0x259ce6 = _0x524438['next']())[_0x545ac4(0x1e3)];)\n                    _0x4523ee[_0x545ac4(0x36e)](_0x259ce6['value']);\n                return _0x4523ee;\n            }\n        }\n\n        function _0x2e4b86(_0x760974, _0x438efa, _0x37a20b, _0x52b279) {\n            var _0x2644f8 = w_0x25f3;\n            _0x500e9f || (_0x500e9f = _0x2644f8(0x1ee) == typeof Symbol && Symbol[_0x2644f8(0x31e)] && Symbol[_0x2644f8(0x31e)](_0x2644f8(0x279)) || 0x1353f + -0x1157 + -0x3921);\n            var _0x513b54 = _0x760974 && _0x760974[_0x2644f8(0x371)]\n                , _0x5469e9 = arguments[_0x2644f8(0x259)] - (-0xcb * -0xb + -0xa * 0x137 + -0x28 * -0x16);\n            if (_0x438efa || 0x109 * -0x1c + 0xdc1 + 0xf3b === _0x5469e9 || (_0x438efa = {\n                'children': void (-0x2 * -0x1037 + 0x32f + -0x239d)\n            }),\n            -0xf69 + 0xedb + -0x8f * -0x1 === _0x5469e9)\n                _0x438efa[_0x2644f8(0x16f)] = _0x52b279;\n            else {\n                if (_0x5469e9 > -0x18e2 + -0x25af + 0x3e92) {\n                    for (var _0x5c6f82 = new Array(_0x5469e9), _0x63cb90 = -0x1 * -0xebd + -0x1a37 + 0x2 * 0x5bd; _0x63cb90 < _0x5469e9; _0x63cb90++)\n                        _0x5c6f82[_0x63cb90] = arguments[_0x63cb90 + (0x15f5 + -0x245f + -0x4cf * -0x3)];\n                    _0x438efa[_0x2644f8(0x16f)] = _0x5c6f82;\n                }\n            }\n            if (_0x438efa && _0x513b54) {\n                for (var _0xbcee2c in _0x513b54)\n                    void (-0x1091 * -0x1 + -0x3 * 0x34d + -0x6aa) === _0x438efa[_0xbcee2c] && (_0x438efa[_0xbcee2c] = _0x513b54[_0xbcee2c]);\n            } else\n                _0x438efa || (_0x438efa = _0x513b54 || {});\n            return {\n                '$$typeof': _0x500e9f,\n                'type': _0x760974,\n                'key': void (-0x7 * 0x1cd + -0x1 * -0xb38 + 0x163) === _0x37a20b ? null : '' + _0x37a20b,\n                'ref': null,\n                'props': _0x438efa,\n                '_owner': null\n            };\n        }\n\n        function _0x3a3eb5(_0x4619be, _0x3fc822) {\n            var _0x44978d = w_0x25f3\n                , _0x504f59 = Object[_0x44978d(0x17f)](_0x4619be);\n            if (Object[_0x44978d(0x388)]) {\n                var _0x4ea700 = Object['getOwnPropertySymbols'](_0x4619be);\n                _0x3fc822 && (_0x4ea700 = _0x4ea700[_0x44978d(0x164)](function (_0x2a0c03) {\n                    var _0x162328 = _0x44978d;\n                    return Object[_0x162328(0x2a6)](_0x4619be, _0x2a0c03)[_0x162328(0x23a)];\n                })),\n                    _0x504f59['push'][_0x44978d(0x207)](_0x504f59, _0x4ea700);\n            }\n            return _0x504f59;\n        }\n\n        function _0x4ee2dd(_0xf371f0) {\n            var _0x145ce6 = w_0x25f3;\n            for (var _0x5e36a1 = -0x5 * 0x1ad + 0x11e6 * -0x1 + 0x1a48; _0x5e36a1 < arguments[_0x145ce6(0x259)]; _0x5e36a1++) {\n                var _0xdb889d = null != arguments[_0x5e36a1] ? arguments[_0x5e36a1] : {};\n                _0x5e36a1 % (0x1174 + 0xeb3 + -0x2025) ? _0x3a3eb5(Object(_0xdb889d), !(-0x263c * 0x1 + 0x1 * -0xf7f + 0x7ad * 0x7))[_0x145ce6(0x254)](function (_0x328928) {\n                    _0x4a7824(_0xf371f0, _0x328928, _0xdb889d[_0x328928]);\n                }) : Object[_0x145ce6(0x1ec)] ? Object[_0x145ce6(0x36c)](_0xf371f0, Object[_0x145ce6(0x1ec)](_0xdb889d)) : _0x3a3eb5(Object(_0xdb889d))[_0x145ce6(0x254)](function (_0x593f5f) {\n                    var _0x53f055 = _0x145ce6;\n                    Object[_0x53f055(0x175)](_0xf371f0, _0x593f5f, Object[_0x53f055(0x2a6)](_0xdb889d, _0x593f5f));\n                });\n            }\n            return _0xf371f0;\n        }\n\n        function _0x385d19() {\n            var _0x44a0fc = w_0x25f3;\n            _0x385d19 = function () {\n                return _0x507b23;\n            }\n            ;\n            var _0x507b23 = {}\n                , _0x39fa01 = Object[_0x44a0fc(0x344)]\n                , _0x43238c = _0x39fa01[_0x44a0fc(0x3b8)]\n                , _0x4cf7d8 = Object['defineProperty'] || function (_0x2541c5, _0x22c938, _0x405bab) {\n                var _0x32f2ae = _0x44a0fc;\n                _0x2541c5[_0x22c938] = _0x405bab[_0x32f2ae(0x2e4)];\n            }\n                , _0x1c97cc = _0x44a0fc(0x1ee) == typeof Symbol ? Symbol : {}\n                , _0x5acd1a = _0x1c97cc[_0x44a0fc(0x3b3)] || _0x44a0fc(0x1dd)\n                , _0x52f292 = _0x1c97cc['asyncIterator'] || _0x44a0fc(0x230)\n                , _0x447ab4 = _0x1c97cc[_0x44a0fc(0x1c0)] || _0x44a0fc(0x1e0);\n\n            function _0x3baf2c(_0x30f952, _0x3ef614, _0x2d2b61) {\n                var _0x598819 = _0x44a0fc;\n                return Object[_0x598819(0x175)](_0x30f952, _0x3ef614, {\n                    'value': _0x2d2b61,\n                    'enumerable': !(0x1b1a * -0x1 + 0x1 * 0x2696 + -0x31 * 0x3c),\n                    'configurable': !(-0x1a13 + 0x5 * -0x6d + 0xa * 0x2d2),\n                    'writable': !(-0x1cd + 0x214e + 0x1f81 * -0x1)\n                }),\n                    _0x30f952[_0x3ef614];\n            }\n\n            try {\n                _0x3baf2c({}, '');\n            } catch (_0x275159) {\n                _0x3baf2c = function (_0x37fa7b, _0x2671f0, _0x45b82e) {\n                    return _0x37fa7b[_0x2671f0] = _0x45b82e;\n                }\n                ;\n            }\n\n            function _0x3e46c6(_0x50c0cc, _0x5f3c83, _0x148917, _0x2e5141) {\n                var _0x1a25db = _0x44a0fc\n                    , _0x1b0fa0 = _0x5f3c83 && _0x5f3c83['prototype'] instanceof _0x50f36d ? _0x5f3c83 : _0x50f36d\n                    , _0x4f06ab = Object[_0x1a25db(0x3b7)](_0x1b0fa0[_0x1a25db(0x344)])\n                    , _0x3e4999 = new _0x1b5db9(_0x2e5141 || []);\n                return _0x4cf7d8(_0x4f06ab, _0x1a25db(0x1b1), {\n                    'value': _0x121728(_0x50c0cc, _0x148917, _0x3e4999)\n                }),\n                    _0x4f06ab;\n            }\n\n            function _0x575dfd(_0x48fd20, _0x6545ef, _0x242936) {\n                var _0x580d50 = _0x44a0fc;\n                try {\n                    return {\n                        'type': _0x580d50(0x2f1),\n                        'arg': _0x48fd20[_0x580d50(0x334)](_0x6545ef, _0x242936)\n                    };\n                } catch (_0x5aebac) {\n                    return {\n                        'type': 'throw',\n                        'arg': _0x5aebac\n                    };\n                }\n            }\n\n            _0x507b23['wrap'] = _0x3e46c6;\n            var _0x511b05 = {};\n\n            function _0x50f36d() {\n            }\n\n            function _0x2e67e9() {\n            }\n\n            function _0x3a5ac7() {\n            }\n\n            var _0x4c3008 = {};\n            _0x3baf2c(_0x4c3008, _0x5acd1a, function () {\n                return this;\n            });\n            var _0x118945 = Object[_0x44a0fc(0x22c)]\n                , _0x5d1d04 = _0x118945 && _0x118945(_0x118945(_0x2edbf4([])));\n            _0x5d1d04 && _0x5d1d04 !== _0x39fa01 && _0x43238c[_0x44a0fc(0x334)](_0x5d1d04, _0x5acd1a) && (_0x4c3008 = _0x5d1d04);\n            var _0x42763b = _0x3a5ac7[_0x44a0fc(0x344)] = _0x50f36d['prototype'] = Object[_0x44a0fc(0x3b7)](_0x4c3008);\n\n            function _0x4e156b(_0x314ec0) {\n                var _0x1229ff = _0x44a0fc;\n                [_0x1229ff(0x389), _0x1229ff(0x250), _0x1229ff(0x2fd)][_0x1229ff(0x254)](function (_0x1cac9a) {\n                    _0x3baf2c(_0x314ec0, _0x1cac9a, function (_0x509669) {\n                        var _0x3b5587 = w_0x25f3;\n                        return this[_0x3b5587(0x1b1)](_0x1cac9a, _0x509669);\n                    });\n                });\n            }\n\n            function _0x23eb73(_0x5cb4f0, _0xfdda3) {\n                var _0x2f70bc;\n                _0x4cf7d8(this, '_invoke', {\n                    'value': function (_0x47f883, _0x34dd78) {\n                        var _0x5c5cca = w_0x25f3;\n\n                        function _0x65e836() {\n                            return new _0xfdda3(function (_0x494e99, _0x39f97a) {\n                                    !function _0x19e170(_0xd94afd, _0x7f5a3, _0x1fc978, _0x392c17) {\n                                        var _0x5108db = w_0x25f3\n                                            , _0x123c2b = _0x575dfd(_0x5cb4f0[_0xd94afd], _0x5cb4f0, _0x7f5a3);\n                                        if (_0x5108db(0x250) !== _0x123c2b[_0x5108db(0x1ab)]) {\n                                            var _0x57ff30 = _0x123c2b[_0x5108db(0x327)]\n                                                , _0x519f3c = _0x57ff30[_0x5108db(0x2e4)];\n                                            return _0x519f3c && 'object' == typeof _0x519f3c && _0x43238c[_0x5108db(0x334)](_0x519f3c, _0x5108db(0x2b1)) ? _0xfdda3[_0x5108db(0x278)](_0x519f3c[_0x5108db(0x2b1)])[_0x5108db(0x1ed)](function (_0x513ad4) {\n                                                var _0x372e8b = _0x5108db;\n                                                _0x19e170(_0x372e8b(0x389), _0x513ad4, _0x1fc978, _0x392c17);\n                                            }, function (_0x3ee973) {\n                                                _0x19e170('throw', _0x3ee973, _0x1fc978, _0x392c17);\n                                            }) : _0xfdda3[_0x5108db(0x278)](_0x519f3c)[_0x5108db(0x1ed)](function (_0xb8049c) {\n                                                var _0x3f5791 = _0x5108db;\n                                                _0x57ff30[_0x3f5791(0x2e4)] = _0xb8049c,\n                                                    _0x1fc978(_0x57ff30);\n                                            }, function (_0x163a1d) {\n                                                var _0x43e785 = _0x5108db;\n                                                return _0x19e170(_0x43e785(0x250), _0x163a1d, _0x1fc978, _0x392c17);\n                                            });\n                                        }\n                                        _0x392c17(_0x123c2b[_0x5108db(0x327)]);\n                                    }(_0x47f883, _0x34dd78, _0x494e99, _0x39f97a);\n                                }\n                            );\n                        }\n\n                        return _0x2f70bc = _0x2f70bc ? _0x2f70bc[_0x5c5cca(0x1ed)](_0x65e836, _0x65e836) : _0x65e836();\n                    }\n                });\n            }\n\n            function _0x121728(_0x39e85b, _0x26363f, _0x3838fc) {\n                var _0x4a9454 = 'suspendedStart';\n                return function (_0x33b907, _0x5c348b) {\n                    var _0x14af93 = w_0x25f3;\n                    if (_0x14af93(0x2ef) === _0x4a9454)\n                        throw new Error(_0x14af93(0x35a));\n                    if ('completed' === _0x4a9454) {\n                        if ('throw' === _0x33b907)\n                            throw _0x5c348b;\n                        return _0x159200();\n                    }\n                    for (_0x3838fc[_0x14af93(0x25a)] = _0x33b907,\n                             _0x3838fc[_0x14af93(0x327)] = _0x5c348b; ;) {\n                        var _0x43652a = _0x3838fc[_0x14af93(0x1bc)];\n                        if (_0x43652a) {\n                            var _0xc12f6f = _0x5489f3(_0x43652a, _0x3838fc);\n                            if (_0xc12f6f) {\n                                if (_0xc12f6f === _0x511b05)\n                                    continue;\n                                return _0xc12f6f;\n                            }\n                        }\n                        if (_0x14af93(0x389) === _0x3838fc[_0x14af93(0x25a)])\n                            _0x3838fc[_0x14af93(0x3b2)] = _0x3838fc[_0x14af93(0x2a2)] = _0x3838fc[_0x14af93(0x327)];\n                        else {\n                            if ('throw' === _0x3838fc[_0x14af93(0x25a)]) {\n                                if ('suspendedStart' === _0x4a9454)\n                                    throw _0x4a9454 = _0x14af93(0x16a),\n                                        _0x3838fc['arg'];\n                                _0x3838fc[_0x14af93(0x2cb)](_0x3838fc[_0x14af93(0x327)]);\n                            } else\n                                _0x14af93(0x2fd) === _0x3838fc[_0x14af93(0x25a)] && _0x3838fc['abrupt'](_0x14af93(0x2fd), _0x3838fc['arg']);\n                        }\n                        _0x4a9454 = _0x14af93(0x2ef);\n                        var _0x1a99b5 = _0x575dfd(_0x39e85b, _0x26363f, _0x3838fc);\n                        if ('normal' === _0x1a99b5['type']) {\n                            if (_0x4a9454 = _0x3838fc[_0x14af93(0x1e3)] ? _0x14af93(0x16a) : 'suspendedYield',\n                            _0x1a99b5[_0x14af93(0x327)] === _0x511b05)\n                                continue;\n                            return {\n                                'value': _0x1a99b5[_0x14af93(0x327)],\n                                'done': _0x3838fc[_0x14af93(0x1e3)]\n                            };\n                        }\n                        _0x14af93(0x250) === _0x1a99b5[_0x14af93(0x1ab)] && (_0x4a9454 = _0x14af93(0x16a),\n                            _0x3838fc[_0x14af93(0x25a)] = _0x14af93(0x250),\n                            _0x3838fc[_0x14af93(0x327)] = _0x1a99b5[_0x14af93(0x327)]);\n                    }\n                }\n                    ;\n            }\n\n            function _0x5489f3(_0x3c1e2d, _0x59877f) {\n                var _0x299ed9 = _0x44a0fc\n                    , _0x1a45fc = _0x59877f['method']\n                    , _0x116edb = _0x3c1e2d[_0x299ed9(0x3b3)][_0x1a45fc];\n                if (void (-0x15fe + 0xe93 + 0x76b) === _0x116edb)\n                    return _0x59877f[_0x299ed9(0x1bc)] = null,\n                    _0x299ed9(0x250) === _0x1a45fc && _0x3c1e2d[_0x299ed9(0x3b3)][_0x299ed9(0x2fd)] && (_0x59877f['method'] = 'return',\n                        _0x59877f[_0x299ed9(0x327)] = void (-0x78 * -0x25 + -0x2272 + 0x111a * 0x1),\n                        _0x5489f3(_0x3c1e2d, _0x59877f),\n                    _0x299ed9(0x250) === _0x59877f[_0x299ed9(0x25a)]) || 'return' !== _0x1a45fc && (_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250),\n                        _0x59877f[_0x299ed9(0x327)] = new TypeError('The\\x20iterator\\x20does\\x20not\\x20provide\\x20a\\x20\\x27' + _0x1a45fc + _0x299ed9(0x32f))),\n                        _0x511b05;\n                var _0x5be46a = _0x575dfd(_0x116edb, _0x3c1e2d[_0x299ed9(0x3b3)], _0x59877f[_0x299ed9(0x327)]);\n                if (_0x299ed9(0x250) === _0x5be46a[_0x299ed9(0x1ab)])\n                    return _0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250),\n                        _0x59877f['arg'] = _0x5be46a[_0x299ed9(0x327)],\n                        _0x59877f[_0x299ed9(0x1bc)] = null,\n                        _0x511b05;\n                var _0x44f533 = _0x5be46a[_0x299ed9(0x327)];\n                return _0x44f533 ? _0x44f533['done'] ? (_0x59877f[_0x3c1e2d[_0x299ed9(0x16e)]] = _0x44f533[_0x299ed9(0x2e4)],\n                    _0x59877f['next'] = _0x3c1e2d[_0x299ed9(0x281)],\n                _0x299ed9(0x2fd) !== _0x59877f[_0x299ed9(0x25a)] && (_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x389),\n                    _0x59877f['arg'] = void (0x1a2 * -0x17 + -0x1910 + 0x5 * 0xc86)),\n                    _0x59877f[_0x299ed9(0x1bc)] = null,\n                    _0x511b05) : _0x44f533 : (_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250),\n                    _0x59877f['arg'] = new TypeError(_0x299ed9(0x251)),\n                    _0x59877f[_0x299ed9(0x1bc)] = null,\n                    _0x511b05);\n            }\n\n            function _0x14015c(_0x5bad37) {\n                var _0x42a847 = _0x44a0fc\n                    , _0x401cb9 = {\n                    'tryLoc': _0x5bad37[-0x953 * 0x3 + 0xd3c + 0xebd]\n                };\n                -0x85b + 0x1181 + -0x925 in _0x5bad37 && (_0x401cb9['catchLoc'] = _0x5bad37[0x12b4 + -0x1d08 + 0xa55]),\n                0x4dc + 0x1b6f + 0xac3 * -0x3 in _0x5bad37 && (_0x401cb9[_0x42a847(0x220)] = _0x5bad37[-0xd0c * -0x2 + 0x914 + -0xe * 0x283],\n                    _0x401cb9[_0x42a847(0x2fb)] = _0x5bad37[0x7 * -0x216 + 0x702 + 0x79b]),\n                    this['tryEntries'][_0x42a847(0x36e)](_0x401cb9);\n            }\n\n            function _0x2f82b3(_0x43fd78) {\n                var _0x38de29 = _0x44a0fc\n                    , _0x2f1d6c = _0x43fd78[_0x38de29(0x387)] || {};\n                _0x2f1d6c['type'] = _0x38de29(0x2f1),\n                    delete _0x2f1d6c[_0x38de29(0x327)],\n                    _0x43fd78['completion'] = _0x2f1d6c;\n            }\n\n            function _0x1b5db9(_0x53b843) {\n                var _0x2569b6 = _0x44a0fc;\n                this[_0x2569b6(0x337)] = [{\n                    'tryLoc': _0x2569b6(0x1c3)\n                }],\n                    _0x53b843[_0x2569b6(0x254)](_0x14015c, this),\n                    this[_0x2569b6(0x2aa)](!(0x1bba + 0x132e + -0x4c * 0x9e));\n            }\n\n            function _0x2edbf4(_0xe32b16) {\n                var _0x3a0ecf = _0x44a0fc;\n                if (_0xe32b16) {\n                    var _0x3f503a = _0xe32b16[_0x5acd1a];\n                    if (_0x3f503a)\n                        return _0x3f503a['call'](_0xe32b16);\n                    if (_0x3a0ecf(0x1ee) == typeof _0xe32b16[_0x3a0ecf(0x389)])\n                        return _0xe32b16;\n                    if (!isNaN(_0xe32b16['length'])) {\n                        var _0x1ff1cf = -(-0x254c + 0xc7 * 0x11 + -0x2 * -0xc0b)\n                            , _0x4f1000 = function _0x136bfc() {\n                            var _0x10b933 = _0x3a0ecf;\n                            for (; ++_0x1ff1cf < _0xe32b16[_0x10b933(0x259)];)\n                                if (_0x43238c[_0x10b933(0x334)](_0xe32b16, _0x1ff1cf))\n                                    return _0x136bfc[_0x10b933(0x2e4)] = _0xe32b16[_0x1ff1cf],\n                                        _0x136bfc[_0x10b933(0x1e3)] = !(-0x1f79 + -0x22d2 + 0x424c),\n                                        _0x136bfc;\n                            return _0x136bfc['value'] = void (-0x639 + -0x115f + 0xa * 0x25c),\n                                _0x136bfc[_0x10b933(0x1e3)] = !(0x14ad + -0x1 * 0xa1b + -0xa92),\n                                _0x136bfc;\n                        };\n                        return _0x4f1000[_0x3a0ecf(0x389)] = _0x4f1000;\n                    }\n                }\n                return {\n                    'next': _0x159200\n                };\n            }\n\n            function _0x159200() {\n                return {\n                    'value': void (-0x540 + -0x12 * -0x60 + -0x8 * 0x30),\n                    'done': !(-0x526 + -0x6d4 * 0x2 + -0x2 * -0x967)\n                };\n            }\n\n            return _0x2e67e9[_0x44a0fc(0x344)] = _0x3a5ac7,\n                _0x4cf7d8(_0x42763b, _0x44a0fc(0x2ac), {\n                    'value': _0x3a5ac7,\n                    'configurable': !(-0x2414 + 0x1307 + 0x110d)\n                }),\n                _0x4cf7d8(_0x3a5ac7, _0x44a0fc(0x2ac), {\n                    'value': _0x2e67e9,\n                    'configurable': !(0x117d + -0x12aa + 0x12d)\n                }),\n                _0x2e67e9[_0x44a0fc(0x18c)] = _0x3baf2c(_0x3a5ac7, _0x447ab4, _0x44a0fc(0x311)),\n                _0x507b23[_0x44a0fc(0x386)] = function (_0x54fdc6) {\n                    var _0x2c4038 = _0x44a0fc\n                        , _0x29797b = _0x2c4038(0x1ee) == typeof _0x54fdc6 && _0x54fdc6[_0x2c4038(0x2ac)];\n                    return !!_0x29797b && (_0x29797b === _0x2e67e9 || _0x2c4038(0x311) === (_0x29797b['displayName'] || _0x29797b['name']));\n                }\n                ,\n                _0x507b23[_0x44a0fc(0x3a5)] = function (_0x41ff3c) {\n                    var _0x286ce7 = _0x44a0fc;\n                    return Object[_0x286ce7(0x23b)] ? Object[_0x286ce7(0x23b)](_0x41ff3c, _0x3a5ac7) : (_0x41ff3c[_0x286ce7(0x2ea)] = _0x3a5ac7,\n                        _0x3baf2c(_0x41ff3c, _0x447ab4, 'GeneratorFunction')),\n                        _0x41ff3c[_0x286ce7(0x344)] = Object['create'](_0x42763b),\n                        _0x41ff3c;\n                }\n                ,\n                _0x507b23[_0x44a0fc(0x2d1)] = function (_0x4d3173) {\n                    return {\n                        '__await': _0x4d3173\n                    };\n                }\n                ,\n                _0x4e156b(_0x23eb73[_0x44a0fc(0x344)]),\n                _0x3baf2c(_0x23eb73[_0x44a0fc(0x344)], _0x52f292, function () {\n                    return this;\n                }),\n                _0x507b23[_0x44a0fc(0x273)] = _0x23eb73,\n                _0x507b23[_0x44a0fc(0x1e7)] = function (_0x1403cf, _0xb864ce, _0x191461, _0x3aafb7, _0x4bc5ca) {\n                    var _0x225b19 = _0x44a0fc;\n                    void (-0x1 * 0x1145 + -0x239 + -0x3e6 * -0x5) === _0x4bc5ca && (_0x4bc5ca = Promise);\n                    var _0x1e23c5 = new _0x23eb73(_0x3e46c6(_0x1403cf, _0xb864ce, _0x191461, _0x3aafb7), _0x4bc5ca);\n                    return _0x507b23[_0x225b19(0x386)](_0xb864ce) ? _0x1e23c5 : _0x1e23c5[_0x225b19(0x389)]()[_0x225b19(0x1ed)](function (_0x3bf8a0) {\n                        var _0x1af03c = _0x225b19;\n                        return _0x3bf8a0[_0x1af03c(0x1e3)] ? _0x3bf8a0[_0x1af03c(0x2e4)] : _0x1e23c5[_0x1af03c(0x389)]();\n                    });\n                }\n                ,\n                _0x4e156b(_0x42763b),\n                _0x3baf2c(_0x42763b, _0x447ab4, _0x44a0fc(0x1b5)),\n                _0x3baf2c(_0x42763b, _0x5acd1a, function () {\n                    return this;\n                }),\n                _0x3baf2c(_0x42763b, _0x44a0fc(0x3ae), function () {\n                    var _0x26f06c = _0x44a0fc;\n                    return _0x26f06c(0x176);\n                }),\n                _0x507b23['keys'] = function (_0x10e233) {\n                    var _0x515044 = _0x44a0fc\n                        , _0x184dfc = Object(_0x10e233)\n                        , _0x1ee5ea = [];\n                    for (var _0x103175 in _0x184dfc)\n                        _0x1ee5ea[_0x515044(0x36e)](_0x103175);\n                    return _0x1ee5ea[_0x515044(0x2f3)](),\n                        function _0x5c4b0b() {\n                            var _0x4f9a2b = _0x515044;\n                            for (; _0x1ee5ea[_0x4f9a2b(0x259)];) {\n                                var _0x180e64 = _0x1ee5ea[_0x4f9a2b(0x267)]();\n                                if (_0x180e64 in _0x184dfc)\n                                    return _0x5c4b0b[_0x4f9a2b(0x2e4)] = _0x180e64,\n                                        _0x5c4b0b[_0x4f9a2b(0x1e3)] = !(0x411 * -0x2 + -0x20 * 0x3c + 0x1 * 0xfa3),\n                                        _0x5c4b0b;\n                            }\n                            return _0x5c4b0b['done'] = !(-0x4d2 * -0x5 + -0x3fd + -0x13 * 0x10f),\n                                _0x5c4b0b;\n                        }\n                        ;\n                }\n                ,\n                _0x507b23[_0x44a0fc(0x38b)] = _0x2edbf4,\n                _0x1b5db9['prototype'] = {\n                    'constructor': _0x1b5db9,\n                    'reset': function (_0x3ebc58) {\n                        var _0x52c025 = _0x44a0fc;\n                        if (this[_0x52c025(0x32c)] = -0x16 * 0x181 + 0x1e6a + 0x2ac,\n                            this[_0x52c025(0x389)] = 0x1 * 0xa3f + -0x1 * 0x1fb7 + 0x1578,\n                            this[_0x52c025(0x3b2)] = this[_0x52c025(0x2a2)] = void (0x18ca + -0x52c * 0x2 + -0xe72),\n                            this[_0x52c025(0x1e3)] = !(-0x775 + -0xfe1 + -0x1757 * -0x1),\n                            this[_0x52c025(0x1bc)] = null,\n                            this[_0x52c025(0x25a)] = _0x52c025(0x389),\n                            this[_0x52c025(0x327)] = void (-0x1a0a + -0x263c + -0x2 * -0x2023),\n                            this[_0x52c025(0x337)][_0x52c025(0x254)](_0x2f82b3),\n                            !_0x3ebc58) {\n                            for (var _0x271134 in this)\n                                't' === _0x271134['charAt'](0x3 * 0x707 + 0x2132 + 0x7 * -0x7c1) && _0x43238c[_0x52c025(0x334)](this, _0x271134) && !isNaN(+_0x271134['slice'](0x2629 * 0x1 + -0x7ec + -0x1e3c)) && (this[_0x271134] = void (0x14a3 + 0x211 + -0x16b4));\n                        }\n                    },\n                    'stop': function () {\n                        var _0x5d1331 = _0x44a0fc;\n                        this[_0x5d1331(0x1e3)] = !(-0x1157 + -0x1d00 * -0x1 + -0xba9);\n                        var _0x360ca1 = this[_0x5d1331(0x337)][0x181c + 0x2252 + 0x137a * -0x3][_0x5d1331(0x387)];\n                        if (_0x5d1331(0x250) === _0x360ca1[_0x5d1331(0x1ab)])\n                            throw _0x360ca1['arg'];\n                        return this[_0x5d1331(0x29a)];\n                    },\n                    'dispatchException': function (_0x5ccdbe) {\n                        var _0x2739ee = _0x44a0fc;\n                        if (this[_0x2739ee(0x1e3)])\n                            throw _0x5ccdbe;\n                        var _0x2375b1 = this;\n\n                        function _0x5bc3f7(_0x2f8813, _0x2926a6) {\n                            var _0x19cf66 = _0x2739ee;\n                            return _0x459dde[_0x19cf66(0x1ab)] = _0x19cf66(0x250),\n                                _0x459dde[_0x19cf66(0x327)] = _0x5ccdbe,\n                                _0x2375b1[_0x19cf66(0x389)] = _0x2f8813,\n                            _0x2926a6 && (_0x2375b1[_0x19cf66(0x25a)] = _0x19cf66(0x389),\n                                _0x2375b1[_0x19cf66(0x327)] = void (-0x77f + -0x1c03 * -0x1 + -0xd * 0x194)),\n                                !!_0x2926a6;\n                        }\n\n                        for (var _0x218123 = this[_0x2739ee(0x337)][_0x2739ee(0x259)] - (-0x8ed + -0x9e5 + 0x12d3); _0x218123 >= -0x3 * -0x4ef + -0x161b * -0x1 + -0x24e8; --_0x218123) {\n                            var _0x5e4d00 = this[_0x2739ee(0x337)][_0x218123]\n                                , _0x459dde = _0x5e4d00[_0x2739ee(0x387)];\n                            if (_0x2739ee(0x1c3) === _0x5e4d00['tryLoc'])\n                                return _0x5bc3f7(_0x2739ee(0x1db));\n                            if (_0x5e4d00[_0x2739ee(0x29e)] <= this[_0x2739ee(0x32c)]) {\n                                var _0x55fd7f = _0x43238c['call'](_0x5e4d00, 'catchLoc')\n                                    , _0x47cf6c = _0x43238c[_0x2739ee(0x334)](_0x5e4d00, _0x2739ee(0x220));\n                                if (_0x55fd7f && _0x47cf6c) {\n                                    if (this[_0x2739ee(0x32c)] < _0x5e4d00[_0x2739ee(0x2c4)])\n                                        return _0x5bc3f7(_0x5e4d00['catchLoc'], !(-0x25 * 0xe9 + -0x2368 + 0x4515));\n                                    if (this['prev'] < _0x5e4d00[_0x2739ee(0x220)])\n                                        return _0x5bc3f7(_0x5e4d00[_0x2739ee(0x220)]);\n                                } else {\n                                    if (_0x55fd7f) {\n                                        if (this['prev'] < _0x5e4d00[_0x2739ee(0x2c4)])\n                                            return _0x5bc3f7(_0x5e4d00[_0x2739ee(0x2c4)], !(0xf11 + -0x1032 + -0x121 * -0x1));\n                                    } else {\n                                        if (!_0x47cf6c)\n                                            throw new Error(_0x2739ee(0x33e));\n                                        if (this[_0x2739ee(0x32c)] < _0x5e4d00['finallyLoc'])\n                                            return _0x5bc3f7(_0x5e4d00['finallyLoc']);\n                                    }\n                                }\n                            }\n                        }\n                    },\n                    'abrupt': function (_0x452b06, _0x46591d) {\n                        var _0x189350 = _0x44a0fc;\n                        for (var _0x24d9ee = this[_0x189350(0x337)][_0x189350(0x259)] - (-0x1 * -0x434 + 0xb2d * -0x1 + 0x6fa); _0x24d9ee >= 0x144c + -0x1 * 0x80f + -0xc3d; --_0x24d9ee) {\n                            var _0x3e29ca = this[_0x189350(0x337)][_0x24d9ee];\n                            if (_0x3e29ca[_0x189350(0x29e)] <= this[_0x189350(0x32c)] && _0x43238c[_0x189350(0x334)](_0x3e29ca, _0x189350(0x220)) && this[_0x189350(0x32c)] < _0x3e29ca[_0x189350(0x220)]) {\n                                var _0x35a2dc = _0x3e29ca;\n                                break;\n                            }\n                        }\n                        _0x35a2dc && (_0x189350(0x31f) === _0x452b06 || _0x189350(0x2d2) === _0x452b06) && _0x35a2dc[_0x189350(0x29e)] <= _0x46591d && _0x46591d <= _0x35a2dc[_0x189350(0x220)] && (_0x35a2dc = null);\n                        var _0x1837c0 = _0x35a2dc ? _0x35a2dc[_0x189350(0x387)] : {};\n                        return _0x1837c0['type'] = _0x452b06,\n                            _0x1837c0[_0x189350(0x327)] = _0x46591d,\n                            _0x35a2dc ? (this[_0x189350(0x25a)] = _0x189350(0x389),\n                                this[_0x189350(0x389)] = _0x35a2dc[_0x189350(0x220)],\n                                _0x511b05) : this[_0x189350(0x162)](_0x1837c0);\n                    },\n                    'complete': function (_0x4daef1, _0x152d13) {\n                        var _0x2e0c88 = _0x44a0fc;\n                        if (_0x2e0c88(0x250) === _0x4daef1[_0x2e0c88(0x1ab)])\n                            throw _0x4daef1[_0x2e0c88(0x327)];\n                        return _0x2e0c88(0x31f) === _0x4daef1[_0x2e0c88(0x1ab)] || _0x2e0c88(0x2d2) === _0x4daef1[_0x2e0c88(0x1ab)] ? this[_0x2e0c88(0x389)] = _0x4daef1[_0x2e0c88(0x327)] : _0x2e0c88(0x2fd) === _0x4daef1['type'] ? (this[_0x2e0c88(0x29a)] = this[_0x2e0c88(0x327)] = _0x4daef1[_0x2e0c88(0x327)],\n                            this[_0x2e0c88(0x25a)] = _0x2e0c88(0x2fd),\n                            this[_0x2e0c88(0x389)] = 'end') : _0x2e0c88(0x2f1) === _0x4daef1[_0x2e0c88(0x1ab)] && _0x152d13 && (this[_0x2e0c88(0x389)] = _0x152d13),\n                            _0x511b05;\n                    },\n                    'finish': function (_0x33d396) {\n                        var _0x38fc51 = _0x44a0fc;\n                        for (var _0x5abbd8 = this[_0x38fc51(0x337)][_0x38fc51(0x259)] - (0x1b6c + 0x10f1 + -0x2c5c); _0x5abbd8 >= -0x106c + -0x26aa + 0x3716; --_0x5abbd8) {\n                            var _0x5eb5c4 = this[_0x38fc51(0x337)][_0x5abbd8];\n                            if (_0x5eb5c4[_0x38fc51(0x220)] === _0x33d396)\n                                return this['complete'](_0x5eb5c4[_0x38fc51(0x387)], _0x5eb5c4[_0x38fc51(0x2fb)]),\n                                    _0x2f82b3(_0x5eb5c4),\n                                    _0x511b05;\n                        }\n                    },\n                    'catch': function (_0x235ccf) {\n                        var _0x4e3345 = _0x44a0fc;\n                        for (var _0x1db840 = this['tryEntries'][_0x4e3345(0x259)] - (-0x3a * -0x4f + -0x1 * -0x12d6 + -0x24bb * 0x1); _0x1db840 >= -0x168 + 0x305 + -0x19d; --_0x1db840) {\n                            var _0x545b66 = this['tryEntries'][_0x1db840];\n                            if (_0x545b66[_0x4e3345(0x29e)] === _0x235ccf) {\n                                var _0x2d5b63 = _0x545b66[_0x4e3345(0x387)];\n                                if (_0x4e3345(0x250) === _0x2d5b63[_0x4e3345(0x1ab)]) {\n                                    var _0x13e035 = _0x2d5b63[_0x4e3345(0x327)];\n                                    _0x2f82b3(_0x545b66);\n                                }\n                                return _0x13e035;\n                            }\n                        }\n                        throw new Error(_0x4e3345(0x23f));\n                    },\n                    'delegateYield': function (_0x395df9, _0x50d973, _0x48faf1) {\n                        var _0x39919e = _0x44a0fc;\n                        return this[_0x39919e(0x1bc)] = {\n                            'iterator': _0x2edbf4(_0x395df9),\n                            'resultName': _0x50d973,\n                            'nextLoc': _0x48faf1\n                        },\n                        'next' === this['method'] && (this['arg'] = void (0x1958 + -0xaba + -0xe9e)),\n                            _0x511b05;\n                    }\n                },\n                _0x507b23;\n        }\n\n        function _0x1db123(_0x149c27) {\n            var _0x39d672 = w_0x25f3;\n            return (_0x1db123 = _0x39d672(0x1ee) == typeof Symbol && 'symbol' == typeof Symbol['iterator'] ? function (_0x4a8f2c) {\n                        return typeof _0x4a8f2c;\n                    }\n                    : function (_0x40eb64) {\n                        var _0x4f8eee = _0x39d672;\n                        return _0x40eb64 && _0x4f8eee(0x1ee) == typeof Symbol && _0x40eb64[_0x4f8eee(0x2ac)] === Symbol && _0x40eb64 !== Symbol['prototype'] ? _0x4f8eee(0x2ed) : typeof _0x40eb64;\n                    }\n            )(_0x149c27);\n        }\n\n        function _0x34d29a() {\n            var _0x4bbdba = w_0x25f3;\n            _0x34d29a = function (_0x1859fe, _0x26adf2) {\n                return new _0x3b92d4(_0x1859fe, void (-0x1f * 0x133 + 0x3 * 0x4f5 + 0x23b * 0xa), _0x26adf2);\n            }\n            ;\n            var _0x5aed6e = RegExp[_0x4bbdba(0x344)]\n                , _0x58ba91 = new WeakMap();\n\n            function _0x3b92d4(_0x2f61fd, _0x513c44, _0xaf22fc) {\n                var _0xd932c6 = _0x4bbdba\n                    , _0xd60509 = new RegExp(_0x2f61fd, _0x513c44);\n                return _0x58ba91[_0xd932c6(0x1e4)](_0xd60509, _0xaf22fc || _0x58ba91[_0xd932c6(0x32b)](_0x2f61fd)),\n                    _0x2e2f47(_0xd60509, _0x3b92d4[_0xd932c6(0x344)]);\n            }\n\n            function _0x427d42(_0x489eeb, _0x1699d8) {\n                var _0x1004fb = _0x4bbdba\n                    , _0x2ae826 = _0x58ba91[_0x1004fb(0x32b)](_0x1699d8);\n                return Object[_0x1004fb(0x17f)](_0x2ae826)[_0x1004fb(0x376)](function (_0x100f10, _0x5bfdf5) {\n                    var _0x3ad421 = _0x1004fb\n                        , _0x541568 = _0x2ae826[_0x5bfdf5];\n                    if (_0x3ad421(0x28b) == typeof _0x541568)\n                        _0x100f10[_0x5bfdf5] = _0x489eeb[_0x541568];\n                    else {\n                        for (var _0x3bc728 = 0x1 * 0x3ce + 0x3 * -0x435 + 0x8d1; void (0x2695 + 0x1ee8 + -0x457d) === _0x489eeb[_0x541568[_0x3bc728]] && _0x3bc728 + (0x3fb * -0x2 + 0x2631 + -0x2 * 0xf1d) < _0x541568['length'];)\n                            _0x3bc728++;\n                        _0x100f10[_0x5bfdf5] = _0x489eeb[_0x541568[_0x3bc728]];\n                    }\n                    return _0x100f10;\n                }, Object[_0x1004fb(0x3b7)](null));\n            }\n\n            return _0x5dda7d(_0x3b92d4, RegExp),\n                _0x3b92d4['prototype']['exec'] = function (_0x1bc796) {\n                    var _0x2a6afd = _0x4bbdba\n                        , _0x457628 = _0x5aed6e[_0x2a6afd(0x209)]['call'](this, _0x1bc796);\n                    if (_0x457628) {\n                        _0x457628['groups'] = _0x427d42(_0x457628, this);\n                        var _0x546542 = _0x457628['indices'];\n                        _0x546542 && (_0x546542['groups'] = _0x427d42(_0x546542, this));\n                    }\n                    return _0x457628;\n                }\n                ,\n                _0x3b92d4[_0x4bbdba(0x344)][Symbol[_0x4bbdba(0x377)]] = function (_0x10e2ef, _0x453a26) {\n                    var _0x226516 = _0x4bbdba;\n                    if (_0x226516(0x33c) == typeof _0x453a26) {\n                        var _0x42705a = _0x58ba91[_0x226516(0x32b)](this);\n                        return _0x5aed6e[Symbol[_0x226516(0x377)]]['call'](this, _0x10e2ef, _0x453a26[_0x226516(0x377)](/\\$<([^>]+)>/g, function (_0x4536fa, _0x53b1c5) {\n                            var _0x5db08d = _0x226516\n                                , _0x1b4f5c = _0x42705a[_0x53b1c5];\n                            return '$' + (Array[_0x5db08d(0x2af)](_0x1b4f5c) ? _0x1b4f5c[_0x5db08d(0x24f)]('$') : _0x1b4f5c);\n                        }));\n                    }\n                    if (_0x226516(0x1ee) == typeof _0x453a26) {\n                        var _0x51880e = this;\n                        return _0x5aed6e[Symbol[_0x226516(0x377)]][_0x226516(0x334)](this, _0x10e2ef, function () {\n                            var _0x3ce548 = _0x226516\n                                , _0x352e21 = arguments;\n                            return _0x3ce548(0x17d) != typeof _0x352e21[_0x352e21[_0x3ce548(0x259)] - (-0xf9 * -0x7 + 0xd4 + -0x2 * 0x3d1)] && (_0x352e21 = []['slice'][_0x3ce548(0x334)](_0x352e21))[_0x3ce548(0x36e)](_0x427d42(_0x352e21, _0x51880e)),\n                                _0x453a26[_0x3ce548(0x207)](this, _0x352e21);\n                        });\n                    }\n                    return _0x5aed6e[Symbol[_0x226516(0x377)]]['call'](this, _0x10e2ef, _0x453a26);\n                }\n                ,\n                _0x34d29a[_0x4bbdba(0x207)](this, arguments);\n        }\n\n        function _0x2772ab(_0x17b93c) {\n            var _0x2e8af4 = w_0x25f3;\n            this[_0x2e8af4(0x180)] = _0x17b93c;\n        }\n\n        function _0x125e01(_0x221f1a) {\n            return function () {\n                var _0x2db496 = w_0x25f3;\n                return new _0x137ba2(_0x221f1a[_0x2db496(0x207)](this, arguments));\n            }\n                ;\n        }\n\n        function _0x8a0370(_0x1ac7e2, _0x440b38, _0x4611ac, _0x1f79f3, _0x26eb95, _0x4af1d4, _0x2b24bc) {\n            var _0x3a480e = w_0x25f3;\n            try {\n                var _0x16d0ce = _0x1ac7e2[_0x4af1d4](_0x2b24bc)\n                    , _0x2e8eaf = _0x16d0ce[_0x3a480e(0x2e4)];\n            } catch (_0xc88fae) {\n                return void _0x4611ac(_0xc88fae);\n            }\n            _0x16d0ce[_0x3a480e(0x1e3)] ? _0x440b38(_0x2e8eaf) : Promise[_0x3a480e(0x278)](_0x2e8eaf)[_0x3a480e(0x1ed)](_0x1f79f3, _0x26eb95);\n        }\n\n        function _0x50daaa(_0x10de0d) {\n            return function () {\n                var _0x310206 = this\n                    , _0x17ad73 = arguments;\n                return new Promise(function (_0x37120b, _0x728e37) {\n                        var _0x5a819e = _0x10de0d['apply'](_0x310206, _0x17ad73);\n\n                        function _0x12466a(_0x263e68) {\n                            var _0x123e7f = w_0x25f3;\n                            _0x8a0370(_0x5a819e, _0x37120b, _0x728e37, _0x12466a, _0x191f8b, _0x123e7f(0x389), _0x263e68);\n                        }\n\n                        function _0x191f8b(_0x255ae1) {\n                            var _0x5d15ce = w_0x25f3;\n                            _0x8a0370(_0x5a819e, _0x37120b, _0x728e37, _0x12466a, _0x191f8b, _0x5d15ce(0x250), _0x255ae1);\n                        }\n\n                        _0x12466a(void (0xbdf + -0x129c + -0x19 * -0x45));\n                    }\n                );\n            }\n                ;\n        }\n\n        function _0x297d3d(_0xd86983, _0x45590a) {\n            var _0x51c357 = w_0x25f3;\n            if (!(_0xd86983 instanceof _0x45590a))\n                throw new TypeError(_0x51c357(0x2f7));\n        }\n\n        function _0x96f358(_0x217e4a, _0x156410) {\n            var _0x251198 = w_0x25f3;\n            for (var _0x336960 = 0x1613 + -0x2f * 0x3b + 0xb3e * -0x1; _0x336960 < _0x156410[_0x251198(0x259)]; _0x336960++) {\n                var _0x3d27f0 = _0x156410[_0x336960];\n                _0x3d27f0[_0x251198(0x23a)] = _0x3d27f0[_0x251198(0x23a)] || !(-0xbf7 + -0x166e + 0x2266),\n                    _0x3d27f0[_0x251198(0x2bc)] = !(-0xde + 0x1c94 + -0x1bb6),\n                _0x251198(0x2e4) in _0x3d27f0 && (_0x3d27f0['writable'] = !(-0x21 * 0x12f + -0x2 * -0x17d + 0x2415)),\n                    Object[_0x251198(0x175)](_0x217e4a, _0x32e885(_0x3d27f0[_0x251198(0x392)]), _0x3d27f0);\n            }\n        }\n\n        function _0x55cd8a(_0x174a54, _0x5e25eb, _0x465e50) {\n            var _0x4d17e4 = w_0x25f3;\n            return _0x5e25eb && _0x96f358(_0x174a54[_0x4d17e4(0x344)], _0x5e25eb),\n            _0x465e50 && _0x96f358(_0x174a54, _0x465e50),\n                Object[_0x4d17e4(0x175)](_0x174a54, _0x4d17e4(0x344), {\n                    'writable': !(-0xc19 + 0x1aa + -0x2 * -0x538)\n                }),\n                _0x174a54;\n        }\n\n        function _0x58d8c2(_0x5634d7, _0x53515c) {\n            var _0x5fc7bf = w_0x25f3;\n            for (var _0x5e7563 in _0x53515c) {\n                (_0x532356 = _0x53515c[_0x5e7563])[_0x5fc7bf(0x2bc)] = _0x532356[_0x5fc7bf(0x23a)] = !(0xb5 + 0x6 * 0x80 + -0x3b5),\n                'value' in _0x532356 && (_0x532356[_0x5fc7bf(0x2e3)] = !(0x19d * 0x11 + 0x126f + -0x2ddc)),\n                    Object[_0x5fc7bf(0x175)](_0x5634d7, _0x5e7563, _0x532356);\n            }\n            if (Object[_0x5fc7bf(0x388)])\n                for (var _0x45bcc1 = Object[_0x5fc7bf(0x388)](_0x53515c), _0x368698 = -0x11 * -0x1af + -0x1ec7 + 0x228; _0x368698 < _0x45bcc1[_0x5fc7bf(0x259)]; _0x368698++) {\n                    var _0x532356, _0x6be33e = _0x45bcc1[_0x368698];\n                    (_0x532356 = _0x53515c[_0x6be33e])['configurable'] = _0x532356[_0x5fc7bf(0x23a)] = !(-0x833 + 0x9 * -0x76 + 0x1d * 0x6d),\n                    _0x5fc7bf(0x2e4) in _0x532356 && (_0x532356[_0x5fc7bf(0x2e3)] = !(0x18bf + -0x337 * 0x5 + -0x14 * 0x6f)),\n                        Object[_0x5fc7bf(0x175)](_0x5634d7, _0x6be33e, _0x532356);\n                }\n            return _0x5634d7;\n        }\n\n        function _0x40ff51(_0x254aaa, _0x287254) {\n            var _0x77273f = w_0x25f3;\n            for (var _0x587d0b = Object[_0x77273f(0x32a)](_0x287254), _0xa5f40d = -0x2174 + 0x25a * -0x2 + 0x42 * 0x94; _0xa5f40d < _0x587d0b[_0x77273f(0x259)]; _0xa5f40d++) {\n                var _0x23b426 = _0x587d0b[_0xa5f40d]\n                    , _0x59ae3e = Object[_0x77273f(0x2a6)](_0x287254, _0x23b426);\n                _0x59ae3e && _0x59ae3e[_0x77273f(0x2bc)] && void (-0x221b * 0x1 + 0x2326 * 0x1 + -0x10b) === _0x254aaa[_0x23b426] && Object['defineProperty'](_0x254aaa, _0x23b426, _0x59ae3e);\n            }\n            return _0x254aaa;\n        }\n\n        function _0x4a7824(_0x26784f, _0x47795a, _0x26a673) {\n            var _0x1edba1 = w_0x25f3;\n            return (_0x47795a = _0x32e885(_0x47795a)) in _0x26784f ? Object[_0x1edba1(0x175)](_0x26784f, _0x47795a, {\n                'value': _0x26a673,\n                'enumerable': !(0x24eb + 0x1b2 + -0x1 * 0x269d),\n                'configurable': !(-0x472 + -0xb7 * 0x12 + 0x1150),\n                'writable': !(-0x23f8 + 0x257d + -0x185 * 0x1)\n            }) : _0x26784f[_0x47795a] = _0x26a673,\n                _0x26784f;\n        }\n\n        function _0x36f54f() {\n            var _0x472dbc = w_0x25f3;\n            return (_0x36f54f = Object['assign'] ? Object[_0x472dbc(0x2a0)]['bind']() : function (_0x3e0b52) {\n                    var _0x1eddf8 = _0x472dbc;\n                    for (var _0x16d75e = -0x645 + -0x2115 * 0x1 + -0x19 * -0x193; _0x16d75e < arguments[_0x1eddf8(0x259)]; _0x16d75e++) {\n                        var _0x5a9173 = arguments[_0x16d75e];\n                        for (var _0x145ff6 in _0x5a9173)\n                            Object[_0x1eddf8(0x344)][_0x1eddf8(0x3b8)][_0x1eddf8(0x334)](_0x5a9173, _0x145ff6) && (_0x3e0b52[_0x145ff6] = _0x5a9173[_0x145ff6]);\n                    }\n                    return _0x3e0b52;\n                }\n            )['apply'](this, arguments);\n        }\n\n        function _0x5f346f(_0x2ab8ef) {\n            var _0x39ff04 = w_0x25f3;\n            for (var _0x176101 = 0xc60 + -0x43 * -0x1f + 0x6 * -0x36a; _0x176101 < arguments[_0x39ff04(0x259)]; _0x176101++) {\n                var _0x99688c = null != arguments[_0x176101] ? Object(arguments[_0x176101]) : {}\n                    , _0xbf3314 = Object[_0x39ff04(0x17f)](_0x99688c);\n                _0x39ff04(0x1ee) == typeof Object[_0x39ff04(0x388)] && _0xbf3314[_0x39ff04(0x36e)][_0x39ff04(0x207)](_0xbf3314, Object[_0x39ff04(0x388)](_0x99688c)[_0x39ff04(0x164)](function (_0x2adc39) {\n                    var _0x23e48e = _0x39ff04;\n                    return Object[_0x23e48e(0x2a6)](_0x99688c, _0x2adc39)[_0x23e48e(0x23a)];\n                })),\n                    _0xbf3314['forEach'](function (_0x2e44e4) {\n                        _0x4a7824(_0x2ab8ef, _0x2e44e4, _0x99688c[_0x2e44e4]);\n                    });\n            }\n            return _0x2ab8ef;\n        }\n\n        function _0x5dda7d(_0x46427b, _0x4b68de) {\n            var _0x5c7f41 = w_0x25f3;\n            if ('function' != typeof _0x4b68de && null !== _0x4b68de)\n                throw new TypeError(_0x5c7f41(0x236));\n            _0x46427b[_0x5c7f41(0x344)] = Object['create'](_0x4b68de && _0x4b68de[_0x5c7f41(0x344)], {\n                'constructor': {\n                    'value': _0x46427b,\n                    'writable': !(-0x59 * -0x6d + -0x3a5 + -0x2240),\n                    'configurable': !(0xf4d * -0x2 + -0x182e + 0x1b64 * 0x2)\n                }\n            }),\n                Object[_0x5c7f41(0x175)](_0x46427b, _0x5c7f41(0x344), {\n                    'writable': !(-0x9d0 * -0x1 + 0x17a1 + -0x217 * 0x10)\n                }),\n            _0x4b68de && _0x2e2f47(_0x46427b, _0x4b68de);\n        }\n\n        function _0x3879ac(_0x40738f, _0x3ddb1f) {\n            var _0x34aaee = w_0x25f3;\n            _0x40738f[_0x34aaee(0x344)] = Object['create'](_0x3ddb1f[_0x34aaee(0x344)]),\n                _0x40738f[_0x34aaee(0x344)][_0x34aaee(0x2ac)] = _0x40738f,\n                _0x2e2f47(_0x40738f, _0x3ddb1f);\n        }\n\n        function _0x22af63(_0x26c4e4) {\n            var _0x3c9cd2 = w_0x25f3;\n            return (_0x22af63 = Object[_0x3c9cd2(0x23b)] ? Object['getPrototypeOf'][_0x3c9cd2(0x301)]() : function (_0x212968) {\n                    var _0x3a939f = _0x3c9cd2;\n                    return _0x212968['__proto__'] || Object[_0x3a939f(0x22c)](_0x212968);\n                }\n            )(_0x26c4e4);\n        }\n\n        function _0x2e2f47(_0x24c757, _0x1d9d80) {\n            var _0x5e1251 = w_0x25f3;\n            return (_0x2e2f47 = Object['setPrototypeOf'] ? Object[_0x5e1251(0x23b)][_0x5e1251(0x301)]() : function (_0x1f13b4, _0x24fdc8) {\n                    var _0x16bc1b = _0x5e1251;\n                    return _0x1f13b4[_0x16bc1b(0x2ea)] = _0x24fdc8,\n                        _0x1f13b4;\n                }\n            )(_0x24c757, _0x1d9d80);\n        }\n\n        function _0x3390dc() {\n            var _0x31b3f3 = w_0x25f3;\n            if (_0x31b3f3(0x384) == typeof Reflect || !Reflect[_0x31b3f3(0x320)])\n                return !(-0x1158 + -0x789 + 0x18e2);\n            if (Reflect[_0x31b3f3(0x320)]['sham'])\n                return !(0xec5 + 0x8 * -0x92 + -0xa34 * 0x1);\n            if (_0x31b3f3(0x1ee) == typeof Proxy)\n                return !(-0xe01 + 0xa7b + 0x386);\n            try {\n                return Boolean[_0x31b3f3(0x344)][_0x31b3f3(0x303)][_0x31b3f3(0x334)](Reflect[_0x31b3f3(0x320)](Boolean, [], function () {\n                })),\n                    !(-0xe0c + -0x2415 + 0x3221 * 0x1);\n            } catch (_0x20aa1e) {\n                return !(0xd * -0xa4 + -0xc1f + 0x1474);\n            }\n        }\n\n        function _0x920a3d(_0x35e7ab, _0x5cbd00, _0x53ced5) {\n            var _0x4ba719 = w_0x25f3;\n            return (_0x920a3d = _0x3390dc() ? Reflect['construct'][_0x4ba719(0x301)]() : function (_0x40c7ae, _0xd26edf, _0x5ecdaf) {\n                    var _0x3b4c0f = _0x4ba719\n                        , _0x55cb1f = [null];\n                    _0x55cb1f['push'][_0x3b4c0f(0x207)](_0x55cb1f, _0xd26edf);\n                    var _0x47f6fb = new (Function[_0x3b4c0f(0x301)]['apply'](_0x40c7ae, _0x55cb1f))();\n                    return _0x5ecdaf && _0x2e2f47(_0x47f6fb, _0x5ecdaf[_0x3b4c0f(0x344)]),\n                        _0x47f6fb;\n                }\n            )['apply'](null, arguments);\n        }\n\n        function _0x5cb0d7(_0x6e2f2f) {\n            var _0x26e451 = w_0x25f3;\n            return -(-0x65 * 0x35 + -0x2087 + -0x3571 * -0x1) !== Function[_0x26e451(0x3ae)]['call'](_0x6e2f2f)[_0x26e451(0x2c5)](_0x26e451(0x161));\n        }\n\n        function _0x16f283(_0x11646e) {\n            var _0x9334eb = w_0x25f3\n                ,\n                _0x551d10 = _0x9334eb(0x1ee) == typeof Map ? new Map() : void (-0xe * -0x5 + 0xd * -0x151 + 0x3 * 0x59d);\n            return (_0x16f283 = function (_0xffb48b) {\n                    var _0x30c56b = _0x9334eb;\n                    if (null === _0xffb48b || !_0x5cb0d7(_0xffb48b))\n                        return _0xffb48b;\n                    if (_0x30c56b(0x1ee) != typeof _0xffb48b)\n                        throw new TypeError(_0x30c56b(0x236));\n                    if (void (0x12 * 0xf8 + -0x41b + 0xd55 * -0x1) !== _0x551d10) {\n                        if (_0x551d10[_0x30c56b(0x2fc)](_0xffb48b))\n                            return _0x551d10[_0x30c56b(0x32b)](_0xffb48b);\n                        _0x551d10[_0x30c56b(0x1e4)](_0xffb48b, _0xfee014);\n                    }\n\n                    function _0xfee014() {\n                        var _0x10fec4 = _0x30c56b;\n                        return _0x920a3d(_0xffb48b, arguments, _0x22af63(this)[_0x10fec4(0x2ac)]);\n                    }\n\n                    return _0xfee014['prototype'] = Object[_0x30c56b(0x3b7)](_0xffb48b[_0x30c56b(0x344)], {\n                        'constructor': {\n                            'value': _0xfee014,\n                            'enumerable': !(0x829 + 0x1 * -0x1271 + 0xa49),\n                            'writable': !(0x724 + 0x15f9 + 0x1d * -0x101),\n                            'configurable': !(0x3e4 + 0x685 * 0x4 + 0x1df8 * -0x1)\n                        }\n                    }),\n                        _0x2e2f47(_0xfee014, _0xffb48b);\n                }\n            )(_0x11646e);\n        }\n\n        function _0x8f6e33(_0xca4201, _0x572889) {\n            var _0x44fa42 = w_0x25f3;\n            return null != _0x572889 && _0x44fa42(0x384) != typeof Symbol && _0x572889[Symbol[_0x44fa42(0x178)]] ? !!_0x572889[Symbol[_0x44fa42(0x178)]](_0xca4201) : _0xca4201 instanceof _0x572889;\n        }\n\n        function _0x2ea366(_0x4da731) {\n            var _0x2c9369 = w_0x25f3;\n            return _0x4da731 && _0x4da731[_0x2c9369(0x3bd)] ? _0x4da731 : {\n                'default': _0x4da731\n            };\n        }\n\n        function _0x1629e6(_0xb8ec58) {\n            var _0xd6f6f1 = w_0x25f3;\n            if (_0xd6f6f1(0x1ee) != typeof WeakMap)\n                return null;\n            var _0x2d8f39 = new WeakMap()\n                , _0x2398fe = new WeakMap();\n            return (_0x1629e6 = function (_0x164b35) {\n                    return _0x164b35 ? _0x2398fe : _0x2d8f39;\n                }\n            )(_0xb8ec58);\n        }\n\n        function _0x2c9158(_0x2f5c3e, _0x55c9ff) {\n            var _0x3d4018 = w_0x25f3;\n            if (!_0x55c9ff && _0x2f5c3e && _0x2f5c3e['__esModule'])\n                return _0x2f5c3e;\n            if (null === _0x2f5c3e || _0x3d4018(0x17d) != typeof _0x2f5c3e && 'function' != typeof _0x2f5c3e)\n                return {\n                    'default': _0x2f5c3e\n                };\n            var _0xcafe97 = _0x1629e6(_0x55c9ff);\n            if (_0xcafe97 && _0xcafe97[_0x3d4018(0x2fc)](_0x2f5c3e))\n                return _0xcafe97[_0x3d4018(0x32b)](_0x2f5c3e);\n            var _0x41e330 = {}\n                , _0x115c7f = Object[_0x3d4018(0x175)] && Object[_0x3d4018(0x2a6)];\n            for (var _0x84a510 in _0x2f5c3e)\n                if (_0x3d4018(0x1d3) !== _0x84a510 && Object[_0x3d4018(0x344)]['hasOwnProperty'][_0x3d4018(0x334)](_0x2f5c3e, _0x84a510)) {\n                    var _0x422bcd = _0x115c7f ? Object[_0x3d4018(0x2a6)](_0x2f5c3e, _0x84a510) : null;\n                    _0x422bcd && (_0x422bcd[_0x3d4018(0x32b)] || _0x422bcd[_0x3d4018(0x1e4)]) ? Object['defineProperty'](_0x41e330, _0x84a510, _0x422bcd) : _0x41e330[_0x84a510] = _0x2f5c3e[_0x84a510];\n                }\n            return _0x41e330['default'] = _0x2f5c3e,\n            _0xcafe97 && _0xcafe97[_0x3d4018(0x1e4)](_0x2f5c3e, _0x41e330),\n                _0x41e330;\n        }\n\n        function _0x374736(_0x2d130b, _0x324593) {\n            var _0x4ccff2 = w_0x25f3;\n            if (_0x2d130b !== _0x324593)\n                throw new TypeError(_0x4ccff2(0x16c));\n        }\n\n        function _0x206199(_0x607e62) {\n            var _0x5bbb21 = w_0x25f3;\n            if (null == _0x607e62)\n                throw new TypeError(_0x5bbb21(0x1cc) + _0x607e62);\n        }\n\n        function _0x2bfa3e(_0x161463, _0x2ff4d5) {\n            var _0x59d7ee = w_0x25f3;\n            if (null == _0x161463)\n                return {};\n            var _0x31fbf6, _0x50d0b6, _0x5ca1c5 = {}, _0x5b71fd = Object['keys'](_0x161463);\n            for (_0x50d0b6 = -0x763 + -0x15a + 0x1 * 0x8bd; _0x50d0b6 < _0x5b71fd[_0x59d7ee(0x259)]; _0x50d0b6++)\n                _0x31fbf6 = _0x5b71fd[_0x50d0b6],\n                _0x2ff4d5[_0x59d7ee(0x2c5)](_0x31fbf6) >= 0x8a7 + -0x21ed + 0x1946 || (_0x5ca1c5[_0x31fbf6] = _0x161463[_0x31fbf6]);\n            return _0x5ca1c5;\n        }\n\n        function _0x2a28e9(_0x2cdf2e, _0x74ac11) {\n            var _0x942c51 = w_0x25f3;\n            if (null == _0x2cdf2e)\n                return {};\n            var _0x5ef46e, _0x5acf70, _0x282df4 = _0x2bfa3e(_0x2cdf2e, _0x74ac11);\n            if (Object['getOwnPropertySymbols']) {\n                var _0x33d708 = Object[_0x942c51(0x388)](_0x2cdf2e);\n                for (_0x5acf70 = -0xd30 + 0x4a1 * 0x1 + 0x7 * 0x139; _0x5acf70 < _0x33d708[_0x942c51(0x259)]; _0x5acf70++)\n                    _0x5ef46e = _0x33d708[_0x5acf70],\n                    _0x74ac11[_0x942c51(0x2c5)](_0x5ef46e) >= -0x1f5d * 0x1 + 0x40b + 0x1b52 || Object[_0x942c51(0x344)][_0x942c51(0x1da)][_0x942c51(0x334)](_0x2cdf2e, _0x5ef46e) && (_0x282df4[_0x5ef46e] = _0x2cdf2e[_0x5ef46e]);\n            }\n            return _0x282df4;\n        }\n\n        function _0x58f550(_0x94e938) {\n            var _0x41d076 = w_0x25f3;\n            if (void (-0x6a * 0x1 + -0xf6 + 0x160) === _0x94e938)\n                throw new ReferenceError(_0x41d076(0x1bb));\n            return _0x94e938;\n        }\n\n        function _0xf3b17(_0x7b2cf6, _0x347c9f) {\n            var _0x41f350 = w_0x25f3;\n            if (_0x347c9f && (_0x41f350(0x17d) == typeof _0x347c9f || _0x41f350(0x1ee) == typeof _0x347c9f))\n                return _0x347c9f;\n            if (void (0x160d + -0x24fd + -0x8 * -0x1de) !== _0x347c9f)\n                throw new TypeError('Derived\\x20constructors\\x20may\\x20only\\x20return\\x20object\\x20or\\x20undefined');\n            return _0x58f550(_0x7b2cf6);\n        }\n\n        function _0x17b234(_0x33316f) {\n            var _0x3601f0 = _0x3390dc();\n            return function () {\n                var _0x4733d6 = w_0x25f3, _0x2848c1, _0x2d0386 = _0x22af63(_0x33316f);\n                if (_0x3601f0) {\n                    var _0x252bb3 = _0x22af63(this)[_0x4733d6(0x2ac)];\n                    _0x2848c1 = Reflect[_0x4733d6(0x320)](_0x2d0386, arguments, _0x252bb3);\n                } else\n                    _0x2848c1 = _0x2d0386[_0x4733d6(0x207)](this, arguments);\n                return _0xf3b17(this, _0x2848c1);\n            }\n                ;\n        }\n\n        function _0x2b3a8b(_0x409fbb, _0x508825) {\n            for (; !Object['prototype']['hasOwnProperty']['call'](_0x409fbb, _0x508825) && null !== (_0x409fbb = _0x22af63(_0x409fbb));)\n                ;\n            return _0x409fbb;\n        }\n\n        function _0x33bfa4() {\n            var _0x1bbf02 = w_0x25f3;\n            return (_0x33bfa4 = _0x1bbf02(0x384) != typeof Reflect && Reflect[_0x1bbf02(0x32b)] ? Reflect[_0x1bbf02(0x32b)][_0x1bbf02(0x301)]() : function (_0x45f38c, _0x4a526c, _0x482f60) {\n                    var _0xb2ad90 = _0x1bbf02\n                        , _0x53f5d7 = _0x2b3a8b(_0x45f38c, _0x4a526c);\n                    if (_0x53f5d7) {\n                        var _0x24e05f = Object[_0xb2ad90(0x2a6)](_0x53f5d7, _0x4a526c);\n                        return _0x24e05f[_0xb2ad90(0x32b)] ? _0x24e05f[_0xb2ad90(0x32b)][_0xb2ad90(0x334)](arguments[_0xb2ad90(0x259)] < 0x7f * 0x25 + 0x23f3 + -0x364b ? _0x45f38c : _0x482f60) : _0x24e05f[_0xb2ad90(0x2e4)];\n                    }\n                }\n            )['apply'](this, arguments);\n        }\n\n        function _0x5b010c(_0x878ee0, _0x27a5c4, _0x35cb40, _0x14e9ba) {\n            var _0x1c5f60 = w_0x25f3;\n            return (_0x5b010c = 'undefined' != typeof Reflect && Reflect[_0x1c5f60(0x1e4)] ? Reflect[_0x1c5f60(0x1e4)] : function (_0xc1d4d, _0x3a32f8, _0x25436d, _0x5ef6e3) {\n                    var _0x43a591 = _0x1c5f60, _0x23d91e, _0x5ac459 = _0x2b3a8b(_0xc1d4d, _0x3a32f8);\n                    if (_0x5ac459) {\n                        if ((_0x23d91e = Object[_0x43a591(0x2a6)](_0x5ac459, _0x3a32f8))[_0x43a591(0x1e4)])\n                            return _0x23d91e['set'][_0x43a591(0x334)](_0x5ef6e3, _0x25436d),\n                                !(0x4d * -0x59 + -0x1 * -0x3d6 + 0x16ef);\n                        if (!_0x23d91e[_0x43a591(0x2e3)])\n                            return !(-0x2691 + 0x9e * 0x25 + 0xfbc);\n                    }\n                    if (_0x23d91e = Object['getOwnPropertyDescriptor'](_0x5ef6e3, _0x3a32f8)) {\n                        if (!_0x23d91e[_0x43a591(0x2e3)])\n                            return !(0x14d + -0x1 * -0x29b + -0x3e7);\n                        _0x23d91e[_0x43a591(0x2e4)] = _0x25436d,\n                            Object[_0x43a591(0x175)](_0x5ef6e3, _0x3a32f8, _0x23d91e);\n                    } else\n                        _0x4a7824(_0x5ef6e3, _0x3a32f8, _0x25436d);\n                    return !(0x295 + -0xa39 * -0x2 + -0x1707);\n                }\n            )(_0x878ee0, _0x27a5c4, _0x35cb40, _0x14e9ba);\n        }\n\n        function _0x2732a4(_0x24a602, _0x194547, _0x16a7b5, _0x8913b1, _0x531d0d) {\n            var _0x16563f = w_0x25f3;\n            if (!_0x5b010c(_0x24a602, _0x194547, _0x16a7b5, _0x8913b1 || _0x24a602) && _0x531d0d)\n                throw new TypeError(_0x16563f(0x34e));\n            return _0x16a7b5;\n        }\n\n        function _0x281bf3(_0x4564b4, _0x1f4153) {\n            var _0x10b792 = w_0x25f3;\n            return _0x1f4153 || (_0x1f4153 = _0x4564b4[_0x10b792(0x2a5)](0x1017 + 0x1cb3 + 0x2 * -0x1665)),\n                Object[_0x10b792(0x198)](Object[_0x10b792(0x36c)](_0x4564b4, {\n                    'raw': {\n                        'value': Object[_0x10b792(0x198)](_0x1f4153)\n                    }\n                }));\n        }\n\n        function _0x2d5f0c(_0x18863e, _0x13e8d4) {\n            var _0x47a3d1 = w_0x25f3;\n            return _0x13e8d4 || (_0x13e8d4 = _0x18863e['slice'](0x8f1 * 0x1 + 0x1 * 0x1e1f + -0x7d * 0x50)),\n                _0x18863e[_0x47a3d1(0x2ab)] = _0x13e8d4,\n                _0x18863e;\n        }\n\n        function _0x246229(_0x5e71a0) {\n            var _0x47c977 = w_0x25f3;\n            throw new TypeError('\\x22' + _0x5e71a0 + _0x47c977(0x338));\n        }\n\n        function _0x5db7bf(_0x51f915) {\n            throw new TypeError('\\x22' + _0x51f915 + '\\x22\\x20is\\x20write-only');\n        }\n\n        function _0x2275f4(_0x42246e) {\n            var _0x2f7351 = w_0x25f3;\n            throw new ReferenceError(_0x2f7351(0x1c7) + _0x42246e + '\\x22\\x20cannot\\x20be\\x20referenced\\x20in\\x20computed\\x20property\\x20keys.');\n        }\n\n        function _0x516c2b() {\n        }\n\n        function _0xab4ac9(_0xcde017) {\n            throw new ReferenceError(_0xcde017 + '\\x20is\\x20not\\x20defined\\x20-\\x20temporal\\x20dead\\x20zone');\n        }\n\n        function _0x5b377b(_0x5f4fa5, _0x2f492b) {\n            return _0x5f4fa5 === _0x516c2b ? _0xab4ac9(_0x2f492b) : _0x5f4fa5;\n        }\n\n        function _0x5096de(_0x3b53c6, _0x3225c3) {\n            return _0x1ae312(_0x3b53c6) || _0x19d66a(_0x3b53c6, _0x3225c3) || _0x525331(_0x3b53c6, _0x3225c3) || _0x25b697();\n        }\n\n        function _0x1dff6c(_0x3a7a63, _0x147620) {\n            return _0x1ae312(_0x3a7a63) || _0x376fd5(_0x3a7a63, _0x147620) || _0x525331(_0x3a7a63, _0x147620) || _0x25b697();\n        }\n\n        function _0x5c885(_0x3953c0) {\n            return _0x1ae312(_0x3953c0) || _0x1853c6(_0x3953c0) || _0x525331(_0x3953c0) || _0x25b697();\n        }\n\n        function _0x534083(_0x3396cf) {\n            return _0x1ccd19(_0x3396cf) || _0x1853c6(_0x3396cf) || _0x525331(_0x3396cf) || _0x542337();\n        }\n\n        function _0x1ccd19(_0x15e4f0) {\n            var _0x384cbb = w_0x25f3;\n            if (Array[_0x384cbb(0x2af)](_0x15e4f0))\n                return _0x537c83(_0x15e4f0);\n        }\n\n        function _0x1ae312(_0x4bfad0) {\n            var _0x3bc5ad = w_0x25f3;\n            if (Array[_0x3bc5ad(0x2af)](_0x4bfad0))\n                return _0x4bfad0;\n        }\n\n        function _0x4bbf4b(_0x33a831, _0x181a3c, _0x135270) {\n            var _0x5bf329 = w_0x25f3;\n            if (_0x181a3c && !Array[_0x5bf329(0x2af)](_0x181a3c) && _0x5bf329(0x28b) == typeof _0x181a3c[_0x5bf329(0x259)]) {\n                var _0x43388b = _0x181a3c[_0x5bf329(0x259)];\n                return _0x537c83(_0x181a3c, void (0xb * -0x29 + 0x387 + -0x2 * 0xe2) !== _0x135270 && _0x135270 < _0x43388b ? _0x135270 : _0x43388b);\n            }\n            return _0x33a831(_0x181a3c, _0x135270);\n        }\n\n        function _0x1853c6(_0x3086ca) {\n            var _0x3e6030 = w_0x25f3;\n            if (_0x3e6030(0x384) != typeof Symbol && null != _0x3086ca[Symbol[_0x3e6030(0x3b3)]] || null != _0x3086ca[_0x3e6030(0x1dd)])\n                return Array['from'](_0x3086ca);\n        }\n\n        function _0x525331(_0x1ceb3f, _0x38a668) {\n            var _0x2b5250 = w_0x25f3;\n            if (_0x1ceb3f) {\n                if (_0x2b5250(0x33c) == typeof _0x1ceb3f)\n                    return _0x537c83(_0x1ceb3f, _0x38a668);\n                var _0x2821d9 = Object[_0x2b5250(0x344)][_0x2b5250(0x3ae)][_0x2b5250(0x334)](_0x1ceb3f)['slice'](0x2ae * -0x7 + 0x1 * 0x2181 + 0xeb7 * -0x1, -(-0x1d * -0xec + 0x2 * -0x32 + -0x1a57));\n                return _0x2b5250(0x2eb) === _0x2821d9 && _0x1ceb3f[_0x2b5250(0x2ac)] && (_0x2821d9 = _0x1ceb3f[_0x2b5250(0x2ac)]['name']),\n                    'Map' === _0x2821d9 || _0x2b5250(0x160) === _0x2821d9 ? Array[_0x2b5250(0x29c)](_0x1ceb3f) : _0x2b5250(0x27f) === _0x2821d9 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/[_0x2b5250(0x22b)](_0x2821d9) ? _0x537c83(_0x1ceb3f, _0x38a668) : void (-0x1 * 0xf34 + 0x12e6 + 0x1d9 * -0x2);\n            }\n        }\n\n        function _0x537c83(_0x1cc46a, _0xca9940) {\n            var _0x4c66e3 = w_0x25f3;\n            (null == _0xca9940 || _0xca9940 > _0x1cc46a[_0x4c66e3(0x259)]) && (_0xca9940 = _0x1cc46a[_0x4c66e3(0x259)]);\n            for (var _0x3859e4 = 0x1fe3 * 0x1 + -0x22be + 0x2db, _0x3a8ed3 = new Array(_0xca9940); _0x3859e4 < _0xca9940; _0x3859e4++)\n                _0x3a8ed3[_0x3859e4] = _0x1cc46a[_0x3859e4];\n            return _0x3a8ed3;\n        }\n\n        function _0x542337() {\n            var _0x1d894c = w_0x25f3;\n            throw new TypeError(_0x1d894c(0x3a8));\n        }\n\n        function _0x25b697() {\n            throw new TypeError('Invalid\\x20attempt\\x20to\\x20destructure\\x20non-iterable\\x20instance.\\x0aIn\\x20order\\x20to\\x20be\\x20iterable,\\x20non-array\\x20objects\\x20must\\x20have\\x20a\\x20[Symbol.iterator]()\\x20method.');\n        }\n\n        function _0x350075(_0x189dc6, _0x3f6be9) {\n            var _0x464771 = w_0x25f3\n                ,\n                _0x199147 = _0x464771(0x384) != typeof Symbol && _0x189dc6[Symbol[_0x464771(0x3b3)]] || _0x189dc6[_0x464771(0x1dd)];\n            if (!_0x199147) {\n                if (Array['isArray'](_0x189dc6) || (_0x199147 = _0x525331(_0x189dc6)) || _0x3f6be9 && _0x189dc6 && _0x464771(0x28b) == typeof _0x189dc6[_0x464771(0x259)]) {\n                    _0x199147 && (_0x189dc6 = _0x199147);\n                    var _0x544a3f = 0x1fd2 + 0x1 * -0x1ad5 + 0x4fd * -0x1\n                        , _0x5b20ae = function () {\n                    };\n                    return {\n                        's': _0x5b20ae,\n                        'n': function () {\n                            var _0x4c93f0 = _0x464771;\n                            return _0x544a3f >= _0x189dc6[_0x4c93f0(0x259)] ? {\n                                'done': !(-0x1aaa * 0x1 + -0x126e * 0x1 + 0x2d18)\n                            } : {\n                                'done': !(0x7 * -0x205 + 0x1d44 + -0xf20),\n                                'value': _0x189dc6[_0x544a3f++]\n                            };\n                        },\n                        'e': function (_0x4d8393) {\n                            throw _0x4d8393;\n                        },\n                        'f': _0x5b20ae\n                    };\n                }\n                throw new TypeError(_0x464771(0x2ae));\n            }\n            var _0x23cdd3, _0x5bcfbb = !(0x1 * -0x810 + -0xb3 * 0x2f + 0x1 * 0x28ed),\n                _0x4db4fd = !(0x221 + 0x62e * 0x5 + 0x3 * -0xb02);\n            return {\n                's': function () {\n                    _0x199147 = _0x199147['call'](_0x189dc6);\n                },\n                'n': function () {\n                    var _0x30f507 = _0x464771\n                        , _0x2382b6 = _0x199147['next']();\n                    return _0x5bcfbb = _0x2382b6[_0x30f507(0x1e3)],\n                        _0x2382b6;\n                },\n                'e': function (_0x3b0f24) {\n                    _0x4db4fd = !(0x18e0 + 0x2 * 0x214 + -0x1d08),\n                        _0x23cdd3 = _0x3b0f24;\n                },\n                'f': function () {\n                    var _0x22fdad = _0x464771;\n                    try {\n                        _0x5bcfbb || null == _0x199147[_0x22fdad(0x2fd)] || _0x199147[_0x22fdad(0x2fd)]();\n                    } finally {\n                        if (_0x4db4fd)\n                            throw _0x23cdd3;\n                    }\n                }\n            };\n        }\n\n        function _0x37af30(_0x37ea9e, _0x2388a0) {\n            var _0x3701de = w_0x25f3\n                ,\n                _0x2ac940 = 'undefined' != typeof Symbol && _0x37ea9e[Symbol[_0x3701de(0x3b3)]] || _0x37ea9e['@@iterator'];\n            if (_0x2ac940)\n                return (_0x2ac940 = _0x2ac940['call'](_0x37ea9e))[_0x3701de(0x389)][_0x3701de(0x301)](_0x2ac940);\n            if (Array[_0x3701de(0x2af)](_0x37ea9e) || (_0x2ac940 = _0x525331(_0x37ea9e)) || _0x2388a0 && _0x37ea9e && 'number' == typeof _0x37ea9e[_0x3701de(0x259)]) {\n                _0x2ac940 && (_0x37ea9e = _0x2ac940);\n                var _0x1dcac8 = 0x1d * -0x11a + -0x1f * 0xc7 + -0x380b * -0x1;\n                return function () {\n                    var _0x306ed0 = _0x3701de;\n                    return _0x1dcac8 >= _0x37ea9e[_0x306ed0(0x259)] ? {\n                        'done': !(-0x29d + 0x5fb * -0x1 + 0x898)\n                    } : {\n                        'done': !(-0x6e * 0x4f + 0x2311 + -0x11e),\n                        'value': _0x37ea9e[_0x1dcac8++]\n                    };\n                }\n                    ;\n            }\n            throw new TypeError(_0x3701de(0x2ae));\n        }\n\n        function _0x5362e1(_0x4cd55f) {\n            return function () {\n                var _0x58617f = w_0x25f3\n                    , _0x183c06 = _0x4cd55f['apply'](this, arguments);\n                return _0x183c06[_0x58617f(0x389)](),\n                    _0x183c06;\n            }\n                ;\n        }\n\n        function _0x4ad3b0(_0x460146, _0x32cf07) {\n            var _0x271683 = w_0x25f3;\n            if (_0x271683(0x17d) != typeof _0x460146 || null === _0x460146)\n                return _0x460146;\n            var _0xa9fa9c = _0x460146[Symbol['toPrimitive']];\n            if (void (0x21b4 + 0x5 * 0x4c7 + 0x3997 * -0x1) !== _0xa9fa9c) {\n                var _0x560849 = _0xa9fa9c['call'](_0x460146, _0x32cf07 || _0x271683(0x1d3));\n                if ('object' != typeof _0x560849)\n                    return _0x560849;\n                throw new TypeError(_0x271683(0x358));\n            }\n            return ('string' === _0x32cf07 ? String : Number)(_0x460146);\n        }\n\n        function _0x32e885(_0x225644) {\n            var _0x1eb479 = w_0x25f3\n                , _0x45c5d4 = _0x4ad3b0(_0x225644, _0x1eb479(0x33c));\n            return _0x1eb479(0x2ed) == typeof _0x45c5d4 ? _0x45c5d4 : String(_0x45c5d4);\n        }\n\n        function _0xf47dc3(_0x1d62a3, _0xeb8470) {\n            var _0x31107e = w_0x25f3;\n            throw new Error(_0x31107e(0x1ff));\n        }\n\n        function _0x9d8dd5(_0x238b59, _0x206a18, _0x4378c6, _0x532e73) {\n            var _0x340b07 = w_0x25f3;\n            _0x4378c6 && Object[_0x340b07(0x175)](_0x238b59, _0x206a18, {\n                'enumerable': _0x4378c6['enumerable'],\n                'configurable': _0x4378c6[_0x340b07(0x2bc)],\n                'writable': _0x4378c6[_0x340b07(0x2e3)],\n                'value': _0x4378c6[_0x340b07(0x2d0)] ? _0x4378c6['initializer'][_0x340b07(0x334)](_0x532e73) : void (-0x1ae6 + -0x1 * -0xf6b + 0xb7b * 0x1)\n            });\n        }\n\n        function _0x271739(_0xb876c5, _0x285720, _0x361de9, _0x52c079, _0x38a76d) {\n            var _0x26b61e = w_0x25f3\n                , _0x25c883 = {};\n            return Object['keys'](_0x52c079)[_0x26b61e(0x254)](function (_0xd1a198) {\n                _0x25c883[_0xd1a198] = _0x52c079[_0xd1a198];\n            }),\n                _0x25c883[_0x26b61e(0x23a)] = !!_0x25c883[_0x26b61e(0x23a)],\n                _0x25c883[_0x26b61e(0x2bc)] = !!_0x25c883[_0x26b61e(0x2bc)],\n            (_0x26b61e(0x2e4) in _0x25c883 || _0x25c883['initializer']) && (_0x25c883[_0x26b61e(0x2e3)] = !(0x21e8 + -0x7cf * -0x5 + -0x48f3)),\n                _0x25c883 = _0x361de9[_0x26b61e(0x2a5)]()[_0x26b61e(0x2f3)]()[_0x26b61e(0x376)](function (_0x490c4a, _0x3636f6) {\n                    return _0x3636f6(_0xb876c5, _0x285720, _0x490c4a) || _0x490c4a;\n                }, _0x25c883),\n            _0x38a76d && void (0x1050 + 0x1 * 0x121f + -0x226f) !== _0x25c883[_0x26b61e(0x2d0)] && (_0x25c883[_0x26b61e(0x2e4)] = _0x25c883[_0x26b61e(0x2d0)] ? _0x25c883[_0x26b61e(0x2d0)][_0x26b61e(0x334)](_0x38a76d) : void (0x1392 + -0xbe * 0x23 + -0x1 * -0x668),\n                _0x25c883[_0x26b61e(0x2d0)] = void (-0x1 * -0x1b9a + 0x7f7 + -0x2391 * 0x1)),\n            void (0x53 * 0xb + 0xa2 * -0xf + 0x5ed) === _0x25c883[_0x26b61e(0x2d0)] && (Object[_0x26b61e(0x175)](_0xb876c5, _0x285720, _0x25c883),\n                _0x25c883 = null),\n                _0x25c883;\n        }\n\n        _0x137ba2['prototype'][_0x5612de(0x1ee) == typeof Symbol && Symbol[_0x5612de(0x17c)] || _0x5612de(0x230)] = function () {\n            return this;\n        }\n            ,\n            _0x137ba2[_0x5612de(0x344)]['next'] = function (_0x4262ae) {\n                var _0x1543b4 = _0x5612de;\n                return this[_0x1543b4(0x1b1)](_0x1543b4(0x389), _0x4262ae);\n            }\n            ,\n            _0x137ba2[_0x5612de(0x344)]['throw'] = function (_0x29bafe) {\n                var _0x4c6950 = _0x5612de;\n                return this[_0x4c6950(0x1b1)]('throw', _0x29bafe);\n            }\n            ,\n            _0x137ba2[_0x5612de(0x344)][_0x5612de(0x2fd)] = function (_0x49a53d) {\n                var _0x58f790 = _0x5612de;\n                return this[_0x58f790(0x1b1)](_0x58f790(0x2fd), _0x49a53d);\n            }\n        ;\n        var _0x371360 = 0x11 * -0x20 + 0x88 * -0x1f + 0x1298, _0x4d6c78, _0x312e19, _0x2a32a1, _0x371ac2;\n\n        function _0x2ca065(_0x4c2f2d) {\n            var _0x4415ed = _0x5612de;\n            return _0x4415ed(0x365) + _0x371360++ + '_' + _0x4c2f2d;\n        }\n\n        function _0x33f649(_0x59611c, _0xb8c4c1) {\n            var _0x22f43f = _0x5612de;\n            if (!Object['prototype'][_0x22f43f(0x3b8)][_0x22f43f(0x334)](_0x59611c, _0xb8c4c1))\n                throw new TypeError(_0x22f43f(0x271));\n            return _0x59611c;\n        }\n\n        function _0x4c53b8(_0x467264, _0x1c39b3) {\n            var _0x12fb5e = _0x5612de;\n            return _0x1de0ff(_0x467264, _0x3feef3(_0x467264, _0x1c39b3, _0x12fb5e(0x32b)));\n        }\n\n        function _0xf01d58(_0x248ad, _0xd514dd, _0x4ffcbe) {\n            var _0x2a0763 = _0x5612de;\n            return _0x30760d(_0x248ad, _0x3feef3(_0x248ad, _0xd514dd, _0x2a0763(0x1e4)), _0x4ffcbe),\n                _0x4ffcbe;\n        }\n\n        function _0x3ff428(_0x59a12f, _0x2e6e68) {\n            var _0x1a4f4c = _0x5612de;\n            return _0x1af7ca(_0x59a12f, _0x3feef3(_0x59a12f, _0x2e6e68, _0x1a4f4c(0x1e4)));\n        }\n\n        function _0x3feef3(_0x76bca3, _0x49ed2b, _0xf40042) {\n            var _0x26b65c = _0x5612de;\n            if (!_0x49ed2b[_0x26b65c(0x2fc)](_0x76bca3))\n                throw new TypeError(_0x26b65c(0x2ad) + _0xf40042 + _0x26b65c(0x2bd));\n            return _0x49ed2b[_0x26b65c(0x32b)](_0x76bca3);\n        }\n\n        function _0x46f318(_0x2345ad, _0x29e732, _0x5d3874) {\n            var _0x1785a7 = _0x5612de;\n            return _0x3fbf28(_0x2345ad, _0x29e732),\n                _0x234ff5(_0x5d3874, _0x1785a7(0x32b)),\n                _0x1de0ff(_0x2345ad, _0x5d3874);\n        }\n\n        function _0x3d490a(_0x421876, _0x556ee1, _0x489ccf, _0x32c792) {\n            return _0x3fbf28(_0x421876, _0x556ee1),\n                _0x234ff5(_0x489ccf, 'set'),\n                _0x30760d(_0x421876, _0x489ccf, _0x32c792),\n                _0x32c792;\n        }\n\n        function _0x1f2159(_0x3c139e, _0xf1d93, _0xa6753b) {\n            return _0x3fbf28(_0x3c139e, _0xf1d93),\n                _0xa6753b;\n        }\n\n        function _0x2fcc7b() {\n            var _0x52da1e = _0x5612de;\n            throw new TypeError(_0x52da1e(0x1bd));\n        }\n\n        function _0x1de0ff(_0x35f1cc, _0x2cd6a2) {\n            var _0x331169 = _0x5612de;\n            return _0x2cd6a2[_0x331169(0x32b)] ? _0x2cd6a2[_0x331169(0x32b)][_0x331169(0x334)](_0x35f1cc) : _0x2cd6a2[_0x331169(0x2e4)];\n        }\n\n        function _0x30760d(_0x26c16c, _0x3bf250, _0x4bb532) {\n            var _0x4b5758 = _0x5612de;\n            if (_0x3bf250['set'])\n                _0x3bf250['set'][_0x4b5758(0x334)](_0x26c16c, _0x4bb532);\n            else {\n                if (!_0x3bf250['writable'])\n                    throw new TypeError('attempted\\x20to\\x20set\\x20read\\x20only\\x20private\\x20field');\n                _0x3bf250['value'] = _0x4bb532;\n            }\n        }\n\n        function _0x1af7ca(_0x38569e, _0x4d9da9) {\n            var _0x8504a5 = _0x5612de;\n            if (_0x4d9da9[_0x8504a5(0x1e4)])\n                return _0x8504a5(0x36f) in _0x4d9da9 || (_0x4d9da9['__destrObj'] = {\n                    set 'value'(_0xa3d23) {\n                        var _0x3d920b = _0x8504a5;\n                        _0x4d9da9[_0x3d920b(0x1e4)][_0x3d920b(0x334)](_0x38569e, _0xa3d23);\n                    }\n                }),\n                    _0x4d9da9['__destrObj'];\n            if (!_0x4d9da9[_0x8504a5(0x2e3)])\n                throw new TypeError('attempted\\x20to\\x20set\\x20read\\x20only\\x20private\\x20field');\n            return _0x4d9da9;\n        }\n\n        function _0x153ad5(_0x361a17, _0x4bf341, _0x38ef34) {\n            var _0x36fea3 = _0x5612de;\n            return _0x3fbf28(_0x361a17, _0x4bf341),\n                _0x234ff5(_0x38ef34, _0x36fea3(0x1e4)),\n                _0x1af7ca(_0x361a17, _0x38ef34);\n        }\n\n        function _0x3fbf28(_0x1609bf, _0x372dbd) {\n            if (_0x1609bf !== _0x372dbd)\n                throw new TypeError('Private\\x20static\\x20access\\x20of\\x20wrong\\x20provenance');\n        }\n\n        function _0x234ff5(_0x5dcf40, _0xa0e3be) {\n            var _0x4d5828 = _0x5612de;\n            if (void (0x9 * 0x3b9 + -0x7 * -0x2bb + -0x382 * 0xf) === _0x5dcf40)\n                throw new TypeError(_0x4d5828(0x2ad) + _0xa0e3be + '\\x20private\\x20static\\x20field\\x20before\\x20its\\x20declaration');\n        }\n\n        function _0x3cd893(_0x4d4ac2, _0x117b1a, _0x13ebad, _0x227002) {\n            var _0x404d8d = _0x5612de\n                , _0x21250e = _0xdaf8f6();\n            if (_0x227002) {\n                for (var _0x1ad96b = -0x1 * -0x109d + 0x157 + -0x11f4; _0x1ad96b < _0x227002[_0x404d8d(0x259)]; _0x1ad96b++)\n                    _0x21250e = _0x227002[_0x1ad96b](_0x21250e);\n            }\n            var _0x176094 = _0x117b1a(function (_0x32bc32) {\n                    var _0x1f970f = _0x404d8d;\n                    _0x21250e[_0x1f970f(0x313)](_0x32bc32, _0x1fa626[_0x1f970f(0x265)]);\n                }, _0x13ebad)\n                ,\n                _0x1fa626 = _0x21250e[_0x404d8d(0x2df)](_0x872852(_0x176094['d'][_0x404d8d(0x1cb)](_0x210308)), _0x4d4ac2);\n            return _0x21250e[_0x404d8d(0x217)](_0x176094['F'], _0x1fa626[_0x404d8d(0x265)]),\n                _0x21250e[_0x404d8d(0x165)](_0x176094['F'], _0x1fa626[_0x404d8d(0x39c)]);\n        }\n\n        function _0xdaf8f6() {\n            var _0x3fa41d = _0x5612de;\n            _0xdaf8f6 = function () {\n                return _0x513b0e;\n            }\n            ;\n            var _0x513b0e = {\n                'elementsDefinitionOrder': [[_0x3fa41d(0x25a)], [_0x3fa41d(0x23c)]],\n                'initializeInstanceElements': function (_0x179aa6, _0x25d5cd) {\n                    var _0x557071 = _0x3fa41d;\n                    [_0x557071(0x25a), _0x557071(0x23c)][_0x557071(0x254)](function (_0x2476e8) {\n                        var _0x9b5c0b = _0x557071;\n                        _0x25d5cd[_0x9b5c0b(0x254)](function (_0x299a4a) {\n                            var _0x53da95 = _0x9b5c0b;\n                            _0x299a4a['kind'] === _0x2476e8 && _0x53da95(0x235) === _0x299a4a[_0x53da95(0x215)] && this[_0x53da95(0x2e1)](_0x179aa6, _0x299a4a);\n                        }, this);\n                    }, this);\n                },\n                'initializeClassElements': function (_0x300a4c, _0x38031f) {\n                    var _0x450502 = _0x3fa41d\n                        , _0x4e1581 = _0x300a4c[_0x450502(0x344)];\n                    [_0x450502(0x25a), _0x450502(0x23c)]['forEach'](function (_0x2fde74) {\n                        _0x38031f['forEach'](function (_0xe5e082) {\n                            var _0x123341 = w_0x25f3\n                                , _0x174ec4 = _0xe5e082[_0x123341(0x215)];\n                            if (_0xe5e082[_0x123341(0x26f)] === _0x2fde74 && (_0x123341(0x396) === _0x174ec4 || _0x123341(0x344) === _0x174ec4)) {\n                                var _0x184ef0 = _0x123341(0x396) === _0x174ec4 ? _0x300a4c : _0x4e1581;\n                                this[_0x123341(0x2e1)](_0x184ef0, _0xe5e082);\n                            }\n                        }, this);\n                    }, this);\n                },\n                'defineClassElement': function (_0x2e2a2c, _0x5db810) {\n                    var _0x522104 = _0x3fa41d\n                        , _0x2d7321 = _0x5db810['descriptor'];\n                    if (_0x522104(0x23c) === _0x5db810[_0x522104(0x26f)]) {\n                        var _0x554ae6 = _0x5db810[_0x522104(0x2d0)];\n                        _0x2d7321 = {\n                            'enumerable': _0x2d7321[_0x522104(0x23a)],\n                            'writable': _0x2d7321[_0x522104(0x2e3)],\n                            'configurable': _0x2d7321[_0x522104(0x2bc)],\n                            'value': void (-0x1 * 0x3bd + 0x1ef9 + -0x1b3c) === _0x554ae6 ? void (0x1 * 0x1afe + 0xcd0 + 0x7f6 * -0x5) : _0x554ae6[_0x522104(0x334)](_0x2e2a2c)\n                        };\n                    }\n                    Object[_0x522104(0x175)](_0x2e2a2c, _0x5db810['key'], _0x2d7321);\n                },\n                'decorateClass': function (_0x4d5101, _0x1a7961) {\n                    var _0x129760 = _0x3fa41d\n                        , _0x1a31cc = []\n                        , _0x3f7e89 = []\n                        , _0xf8b039 = {\n                        'static': [],\n                        'prototype': [],\n                        'own': []\n                    };\n                    if (_0x4d5101[_0x129760(0x254)](function (_0x5c0ba5) {\n                        var _0x27d627 = _0x129760;\n                        this[_0x27d627(0x33d)](_0x5c0ba5, _0xf8b039);\n                    }, this),\n                        _0x4d5101[_0x129760(0x254)](function (_0x239102) {\n                            var _0x151241 = _0x129760;\n                            if (!_0x51f3b5(_0x239102))\n                                return _0x1a31cc[_0x151241(0x36e)](_0x239102);\n                            var _0x43ec40 = this[_0x151241(0x1ac)](_0x239102, _0xf8b039);\n                            _0x1a31cc[_0x151241(0x36e)](_0x43ec40[_0x151241(0x206)]),\n                                _0x1a31cc[_0x151241(0x36e)]['apply'](_0x1a31cc, _0x43ec40[_0x151241(0x3bc)]),\n                                _0x3f7e89[_0x151241(0x36e)]['apply'](_0x3f7e89, _0x43ec40[_0x151241(0x39c)]);\n                        }, this),\n                        !_0x1a7961)\n                        return {\n                            'elements': _0x1a31cc,\n                            'finishers': _0x3f7e89\n                        };\n                    var _0x857545 = this[_0x129760(0x34c)](_0x1a31cc, _0x1a7961);\n                    return _0x3f7e89['push'][_0x129760(0x207)](_0x3f7e89, _0x857545[_0x129760(0x39c)]),\n                        _0x857545[_0x129760(0x39c)] = _0x3f7e89,\n                        _0x857545;\n                },\n                'addElementPlacement': function (_0x9cedb8, _0x4c2171, _0xa6e6c8) {\n                    var _0x5d3aa1 = _0x3fa41d\n                        , _0x33e5e0 = _0x4c2171[_0x9cedb8[_0x5d3aa1(0x215)]];\n                    if (!_0xa6e6c8 && -(-0x1a83 + -0x1 * -0x16ee + 0x99 * 0x6) !== _0x33e5e0['indexOf'](_0x9cedb8['key']))\n                        throw new TypeError('Duplicated\\x20element\\x20(' + _0x9cedb8[_0x5d3aa1(0x392)] + ')');\n                    _0x33e5e0[_0x5d3aa1(0x36e)](_0x9cedb8[_0x5d3aa1(0x392)]);\n                },\n                'decorateElement': function (_0x463258, _0x11d852) {\n                    var _0x495609 = _0x3fa41d;\n                    for (var _0x4c5aa5 = [], _0x46b095 = [], _0x106243 = _0x463258['decorators'], _0x195d25 = _0x106243[_0x495609(0x259)] - (-0x1d5c * -0x1 + 0x1aa9 + 0x956 * -0x6); _0x195d25 >= 0x18ee + 0x1 * 0x1c19 + 0xf * -0x389; _0x195d25--) {\n                        var _0x425891 = _0x11d852[_0x463258[_0x495609(0x215)]];\n                        _0x425891[_0x495609(0x2ec)](_0x425891[_0x495609(0x2c5)](_0x463258[_0x495609(0x392)]), 0x1 * 0xca7 + -0xaf * -0xb + -0x142b);\n                        var _0x30722d = this[_0x495609(0x372)](_0x463258)\n                            , _0x15a14c = this[_0x495609(0x18a)]((0x61 * 0x2d + 0x1545 + -0x1 * 0x2652,\n                            _0x106243[_0x195d25])(_0x30722d) || _0x30722d);\n                        _0x463258 = _0x15a14c['element'],\n                            this['addElementPlacement'](_0x463258, _0x11d852),\n                        _0x15a14c[_0x495609(0x2f4)] && _0x46b095[_0x495609(0x36e)](_0x15a14c[_0x495609(0x2f4)]);\n                        var _0x98e9dc = _0x15a14c[_0x495609(0x3bc)];\n                        if (_0x98e9dc) {\n                            for (var _0x56dd4d = 0xb * 0x12e + -0x1f17 + -0x121d * -0x1; _0x56dd4d < _0x98e9dc[_0x495609(0x259)]; _0x56dd4d++)\n                                this[_0x495609(0x33d)](_0x98e9dc[_0x56dd4d], _0x11d852);\n                            _0x4c5aa5[_0x495609(0x36e)]['apply'](_0x4c5aa5, _0x98e9dc);\n                        }\n                    }\n                    return {\n                        'element': _0x463258,\n                        'finishers': _0x46b095,\n                        'extras': _0x4c5aa5\n                    };\n                },\n                'decorateConstructor': function (_0x2a4d32, _0x2666ea) {\n                    var _0x5e156c = _0x3fa41d;\n                    for (var _0xb2f010 = [], _0x17b2e4 = _0x2666ea[_0x5e156c(0x259)] - (0x21c0 + -0xc8e * 0x2 + -0x8a3 * 0x1); _0x17b2e4 >= -0x1c70 + -0x1 * -0x1256 + -0x1af * -0x6; _0x17b2e4--) {\n                        var _0x222759 = this[_0x5e156c(0x193)](_0x2a4d32)\n                            , _0xc41f78 = this[_0x5e156c(0x324)]((0x1f46 + 0x81d * 0x2 + -0x5f * 0x80,\n                            _0x2666ea[_0x17b2e4])(_0x222759) || _0x222759);\n                        if (void (0x1373 + 0x2b1 * -0x2 + -0x1 * 0xe11) !== _0xc41f78[_0x5e156c(0x2f4)] && _0xb2f010[_0x5e156c(0x36e)](_0xc41f78[_0x5e156c(0x2f4)]),\n                        void (0x31 * -0xb5 + -0x11 * 0x67 + 0x84c * 0x5) !== _0xc41f78['elements']) {\n                            _0x2a4d32 = _0xc41f78[_0x5e156c(0x265)];\n                            for (var _0x38c2da = -0x1 * -0xc12 + 0x7 * -0x28d + 0x5c9; _0x38c2da < _0x2a4d32[_0x5e156c(0x259)] - (0x59f * 0x6 + -0x1 * -0x1c6d + 0x25 * -0x1ae); _0x38c2da++)\n                                for (var _0x2950ed = _0x38c2da + (0x1b91 * 0x1 + -0xbc0 + -0x8 * 0x1fa); _0x2950ed < _0x2a4d32['length']; _0x2950ed++)\n                                    if (_0x2a4d32[_0x38c2da][_0x5e156c(0x392)] === _0x2a4d32[_0x2950ed][_0x5e156c(0x392)] && _0x2a4d32[_0x38c2da][_0x5e156c(0x215)] === _0x2a4d32[_0x2950ed][_0x5e156c(0x215)])\n                                        throw new TypeError(_0x5e156c(0x367) + _0x2a4d32[_0x38c2da][_0x5e156c(0x392)] + ')');\n                        }\n                    }\n                    return {\n                        'elements': _0x2a4d32,\n                        'finishers': _0xb2f010\n                    };\n                },\n                'fromElementDescriptor': function (_0x4a43c8) {\n                    var _0x302152 = _0x3fa41d\n                        , _0x406d6b = {\n                        'kind': _0x4a43c8[_0x302152(0x26f)],\n                        'key': _0x4a43c8['key'],\n                        'placement': _0x4a43c8['placement'],\n                        'descriptor': _0x4a43c8[_0x302152(0x20f)]\n                    };\n                    return Object[_0x302152(0x175)](_0x406d6b, Symbol[_0x302152(0x1c0)], {\n                        'value': _0x302152(0x1e8),\n                        'configurable': !(-0x1b3a + 0x21bb * 0x1 + -0x14d * 0x5)\n                    }),\n                    _0x302152(0x23c) === _0x4a43c8['kind'] && (_0x406d6b[_0x302152(0x2d0)] = _0x4a43c8['initializer']),\n                        _0x406d6b;\n                },\n                'toElementDescriptors': function (_0x14be66) {\n                    if (void (0x1f48 + -0x19fe + 0x2a5 * -0x2) !== _0x14be66)\n                        return _0x5c885(_0x14be66)['map'](function (_0x170c20) {\n                            var _0x5285ee = w_0x25f3\n                                , _0xf0c7ce = this[_0x5285ee(0x25e)](_0x170c20);\n                            return this['disallowProperty'](_0x170c20, _0x5285ee(0x2f4), _0x5285ee(0x21f)),\n                                this[_0x5285ee(0x21a)](_0x170c20, _0x5285ee(0x3bc), _0x5285ee(0x21f)),\n                                _0xf0c7ce;\n                        }, this);\n                },\n                'toElementDescriptor': function (_0x4c8a60) {\n                    var _0x1fc4d7 = _0x3fa41d\n                        , _0x33cfb6 = String(_0x4c8a60[_0x1fc4d7(0x26f)]);\n                    if (_0x1fc4d7(0x25a) !== _0x33cfb6 && _0x1fc4d7(0x23c) !== _0x33cfb6)\n                        throw new TypeError('An\\x20element\\x20descriptor\\x27s\\x20.kind\\x20property\\x20must\\x20be\\x20either\\x20\\x22method\\x22\\x20or\\x20\\x22field\\x22,\\x20but\\x20a\\x20decorator\\x20created\\x20an\\x20element\\x20descriptor\\x20with\\x20.kind\\x20\\x22' + _0x33cfb6 + '\\x22');\n                    var _0xebb768 = _0x32e885(_0x4c8a60[_0x1fc4d7(0x392)])\n                        , _0x52ab63 = String(_0x4c8a60[_0x1fc4d7(0x215)]);\n                    if (_0x1fc4d7(0x396) !== _0x52ab63 && _0x1fc4d7(0x344) !== _0x52ab63 && _0x1fc4d7(0x235) !== _0x52ab63)\n                        throw new TypeError(_0x1fc4d7(0x2b5) + _0x52ab63 + '\\x22');\n                    var _0x33ee46 = _0x4c8a60[_0x1fc4d7(0x20f)];\n                    this[_0x1fc4d7(0x21a)](_0x4c8a60, 'elements', _0x1fc4d7(0x21f));\n                    var _0x1ca161 = {\n                        'kind': _0x33cfb6,\n                        'key': _0xebb768,\n                        'placement': _0x52ab63,\n                        'descriptor': Object[_0x1fc4d7(0x2a0)]({}, _0x33ee46)\n                    };\n                    return _0x1fc4d7(0x23c) !== _0x33cfb6 ? this[_0x1fc4d7(0x21a)](_0x4c8a60, _0x1fc4d7(0x2d0), _0x1fc4d7(0x28d)) : (this['disallowProperty'](_0x33ee46, _0x1fc4d7(0x32b), _0x1fc4d7(0x277)),\n                        this['disallowProperty'](_0x33ee46, 'set', _0x1fc4d7(0x277)),\n                        this['disallowProperty'](_0x33ee46, _0x1fc4d7(0x2e4), _0x1fc4d7(0x277)),\n                        _0x1ca161['initializer'] = _0x4c8a60[_0x1fc4d7(0x2d0)]),\n                        _0x1ca161;\n                },\n                'toElementFinisherExtras': function (_0x53b840) {\n                    var _0x1157c0 = _0x3fa41d;\n                    return {\n                        'element': this[_0x1157c0(0x25e)](_0x53b840),\n                        'finisher': _0x22df7b(_0x53b840, _0x1157c0(0x2f4)),\n                        'extras': this[_0x1157c0(0x370)](_0x53b840['extras'])\n                    };\n                },\n                'fromClassDescriptor': function (_0x30c308) {\n                    var _0x482b04 = _0x3fa41d\n                        , _0xf231c1 = {\n                        'kind': _0x482b04(0x19c),\n                        'elements': _0x30c308['map'](this[_0x482b04(0x372)], this)\n                    };\n                    return Object[_0x482b04(0x175)](_0xf231c1, Symbol[_0x482b04(0x1c0)], {\n                        'value': _0x482b04(0x1e8),\n                        'configurable': !(0xf * -0xf1 + 0x1 * -0xcfe + -0x1b1d * -0x1)\n                    }),\n                        _0xf231c1;\n                },\n                'toClassDescriptor': function (_0x178ca0) {\n                    var _0x2520a1 = _0x3fa41d\n                        , _0x79f336 = String(_0x178ca0[_0x2520a1(0x26f)]);\n                    if ('class' !== _0x79f336)\n                        throw new TypeError('A\\x20class\\x20descriptor\\x27s\\x20.kind\\x20property\\x20must\\x20be\\x20\\x22class\\x22,\\x20but\\x20a\\x20decorator\\x20created\\x20a\\x20class\\x20descriptor\\x20with\\x20.kind\\x20\\x22' + _0x79f336 + '\\x22');\n                    this['disallowProperty'](_0x178ca0, _0x2520a1(0x392), 'A\\x20class\\x20descriptor'),\n                        this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x215), 'A\\x20class\\x20descriptor'),\n                        this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x20f), _0x2520a1(0x1a1)),\n                        this['disallowProperty'](_0x178ca0, 'initializer', _0x2520a1(0x1a1)),\n                        this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x3bc), 'A\\x20class\\x20descriptor');\n                    var _0x154e32 = _0x22df7b(_0x178ca0, _0x2520a1(0x2f4));\n                    return {\n                        'elements': this['toElementDescriptors'](_0x178ca0['elements']),\n                        'finisher': _0x154e32\n                    };\n                },\n                'runClassFinishers': function (_0x58401c, _0x3ff489) {\n                    var _0x4a8de1 = _0x3fa41d;\n                    for (var _0x5ec766 = 0x13b0 + -0xe05 + 0x1 * -0x5ab; _0x5ec766 < _0x3ff489[_0x4a8de1(0x259)]; _0x5ec766++) {\n                        var _0x176fd2 = (0x7d * -0x25 + 0x101 * 0x14 + 0x5 * -0x67,\n                            _0x3ff489[_0x5ec766])(_0x58401c);\n                        if (void (-0x1 * 0x200 + 0x1c4a + -0x1a4a) !== _0x176fd2) {\n                            if (_0x4a8de1(0x1ee) != typeof _0x176fd2)\n                                throw new TypeError('Finishers\\x20must\\x20return\\x20a\\x20constructor.');\n                            _0x58401c = _0x176fd2;\n                        }\n                    }\n                    return _0x58401c;\n                },\n                'disallowProperty': function (_0x376492, _0x1998df, _0x46cda4) {\n                    var _0x5b24b6 = _0x3fa41d;\n                    if (void (0x2239 + -0xa67 + -0x17d2) !== _0x376492[_0x1998df])\n                        throw new TypeError(_0x46cda4 + _0x5b24b6(0x232) + _0x1998df + _0x5b24b6(0x2a1));\n                }\n            };\n            return _0x513b0e;\n        }\n\n        function _0x210308(_0x5bae0) {\n            var _0x509268 = _0x5612de, _0x2061f6, _0x1daa96 = _0x32e885(_0x5bae0['key']);\n            _0x509268(0x25a) === _0x5bae0[_0x509268(0x26f)] ? _0x2061f6 = {\n                'value': _0x5bae0[_0x509268(0x2e4)],\n                'writable': !(-0x286 + -0x3 * -0x83b + -0x162b),\n                'configurable': !(-0x1 * -0x13f9 + -0x2 * -0x1127 + -0x3647),\n                'enumerable': !(-0x210 * -0x1 + 0xf43 * -0x2 + 0x1c77)\n            } : _0x509268(0x32b) === _0x5bae0[_0x509268(0x26f)] ? _0x2061f6 = {\n                'get': _0x5bae0['value'],\n                'configurable': !(-0x4 * -0x87 + 0x25b6 + -0x13e9 * 0x2),\n                'enumerable': !(0x4 * -0x105 + -0x8 * 0x3b + 0x5ed * 0x1)\n            } : 'set' === _0x5bae0[_0x509268(0x26f)] ? _0x2061f6 = {\n                'set': _0x5bae0[_0x509268(0x2e4)],\n                'configurable': !(-0x1 * -0xd7c + 0x24e2 + -0x325e),\n                'enumerable': !(0x246b * -0x1 + -0xbdc + 0x67 * 0x78)\n            } : _0x509268(0x23c) === _0x5bae0['kind'] && (_0x2061f6 = {\n                'configurable': !(-0x7 * 0x7c + 0x0 + -0x1 * -0x364),\n                'writable': !(0x10cc + 0x93a + -0x1a06),\n                'enumerable': !(-0x339 + -0xfd1 * -0x1 + -0xc98)\n            });\n            var _0x12b911 = {\n                'kind': _0x509268(0x23c) === _0x5bae0[_0x509268(0x26f)] ? _0x509268(0x23c) : 'method',\n                'key': _0x1daa96,\n                'placement': _0x5bae0[_0x509268(0x396)] ? _0x509268(0x396) : 'field' === _0x5bae0[_0x509268(0x26f)] ? 'own' : _0x509268(0x344),\n                'descriptor': _0x2061f6\n            };\n            return _0x5bae0['decorators'] && (_0x12b911[_0x509268(0x1b7)] = _0x5bae0[_0x509268(0x1b7)]),\n            _0x509268(0x23c) === _0x5bae0['kind'] && (_0x12b911['initializer'] = _0x5bae0[_0x509268(0x2e4)]),\n                _0x12b911;\n        }\n\n        function _0x3b2c5d(_0x1d2cd7, _0x5043bf) {\n            var _0x6af88f = _0x5612de;\n            void (-0x1c1e + -0x19 * -0xd9 + -0x1 * -0x6ed) !== _0x1d2cd7[_0x6af88f(0x20f)][_0x6af88f(0x32b)] ? _0x5043bf['descriptor'][_0x6af88f(0x32b)] = _0x1d2cd7['descriptor'][_0x6af88f(0x32b)] : _0x5043bf['descriptor']['set'] = _0x1d2cd7[_0x6af88f(0x20f)][_0x6af88f(0x1e4)];\n        }\n\n        function _0x872852(_0x11fd7b) {\n            var _0x45b70e = _0x5612de;\n            for (var _0x3d0947 = [], _0x1e20eb = function (_0x3c1862) {\n                var _0x56210d = w_0x25f3;\n                return _0x56210d(0x25a) === _0x3c1862[_0x56210d(0x26f)] && _0x3c1862[_0x56210d(0x392)] === _0x44502e['key'] && _0x3c1862[_0x56210d(0x215)] === _0x44502e[_0x56210d(0x215)];\n            }, _0x2773ae = -0xdd7 + 0x5 * 0x3f6 + 0x5f7 * -0x1; _0x2773ae < _0x11fd7b[_0x45b70e(0x259)]; _0x2773ae++) {\n                var _0x152571, _0x44502e = _0x11fd7b[_0x2773ae];\n                if (_0x45b70e(0x25a) === _0x44502e[_0x45b70e(0x26f)] && (_0x152571 = _0x3d0947['find'](_0x1e20eb))) {\n                    if (_0x3f9244(_0x44502e[_0x45b70e(0x20f)]) || _0x3f9244(_0x152571[_0x45b70e(0x20f)])) {\n                        if (_0x51f3b5(_0x44502e) || _0x51f3b5(_0x152571))\n                            throw new ReferenceError('Duplicated\\x20methods\\x20(' + _0x44502e[_0x45b70e(0x392)] + _0x45b70e(0x20b));\n                        _0x152571[_0x45b70e(0x20f)] = _0x44502e[_0x45b70e(0x20f)];\n                    } else {\n                        if (_0x51f3b5(_0x44502e)) {\n                            if (_0x51f3b5(_0x152571))\n                                throw new ReferenceError('Decorators\\x20can\\x27t\\x20be\\x20placed\\x20on\\x20different\\x20accessors\\x20with\\x20for\\x20the\\x20same\\x20property\\x20(' + _0x44502e['key'] + ').');\n                            _0x152571[_0x45b70e(0x1b7)] = _0x44502e[_0x45b70e(0x1b7)];\n                        }\n                        _0x3b2c5d(_0x44502e, _0x152571);\n                    }\n                } else\n                    _0x3d0947[_0x45b70e(0x36e)](_0x44502e);\n            }\n            return _0x3d0947;\n        }\n\n        function _0x51f3b5(_0x3b7753) {\n            var _0x46d225 = _0x5612de;\n            return _0x3b7753[_0x46d225(0x1b7)] && _0x3b7753['decorators']['length'];\n        }\n\n        function _0x3f9244(_0x197382) {\n            var _0x1ec41e = _0x5612de;\n            return void (0xa8 + 0x12a * -0x4 + 0x400) !== _0x197382 && !(void (-0x2 * -0x955 + -0x965 + -0x945) === _0x197382[_0x1ec41e(0x2e4)] && void (-0x403 + 0xd * 0x1e2 + -0x1477) === _0x197382[_0x1ec41e(0x2e3)]);\n        }\n\n        function _0x22df7b(_0x1a9e0b, _0x4c3aa6) {\n            var _0x2004a6 = _0x5612de\n                , _0x42d7e1 = _0x1a9e0b[_0x4c3aa6];\n            if (void (-0x1ab * -0x11 + -0x2164 + 0x1 * 0x509) !== _0x42d7e1 && _0x2004a6(0x1ee) != typeof _0x42d7e1)\n                throw new TypeError('Expected\\x20\\x27' + _0x4c3aa6 + _0x2004a6(0x200));\n            return _0x42d7e1;\n        }\n\n        function _0x44a779(_0x290bd9, _0x3c4184, _0x356c04) {\n            var _0x5e1d0b = _0x5612de;\n            if (!_0x3c4184[_0x5e1d0b(0x2fc)](_0x290bd9))\n                throw new TypeError(_0x5e1d0b(0x187));\n            return _0x356c04;\n        }\n\n        function _0x227cd9(_0x44aab6, _0x47792b) {\n            var _0x50e6e8 = _0x5612de;\n            if (_0x47792b[_0x50e6e8(0x2fc)](_0x44aab6))\n                throw new TypeError('Cannot\\x20initialize\\x20the\\x20same\\x20private\\x20elements\\x20twice\\x20on\\x20an\\x20object');\n        }\n\n        function _0x41d2eb(_0x2d54de, _0x30b42b, _0x3cc210) {\n            _0x227cd9(_0x2d54de, _0x30b42b),\n                _0x30b42b['set'](_0x2d54de, _0x3cc210);\n        }\n\n        function _0x4fd04a(_0x1b36b3, _0x1a6559) {\n            var _0x1aaac6 = _0x5612de;\n            _0x227cd9(_0x1b36b3, _0x1a6559),\n                _0x1a6559[_0x1aaac6(0x332)](_0x1b36b3);\n        }\n\n        function _0x4fb313() {\n            throw new TypeError('attempted\\x20to\\x20reassign\\x20private\\x20method');\n        }\n\n        function _0x4e4f66(_0x9f7990) {\n            return _0x9f7990;\n        }\n\n        _0x5612de(0x1ee) != typeof Object[_0x5612de(0x2a0)] && Object['defineProperty'](Object, _0x5612de(0x2a0), {\n            'value': function (_0x478fa2, _0x273756) {\n                var _0x2b8676 = _0x5612de;\n                if (null == _0x478fa2)\n                    throw new TypeError(_0x2b8676(0x2cf));\n                for (var _0x451cfb = Object(_0x478fa2), _0x5c5079 = -0xb5d + -0x15f0 + 0x214e; _0x5c5079 < arguments[_0x2b8676(0x259)]; _0x5c5079++) {\n                    var _0x3059a4 = arguments[_0x5c5079];\n                    if (null != _0x3059a4) {\n                        for (var _0x3ede90 in _0x3059a4)\n                            Object[_0x2b8676(0x344)][_0x2b8676(0x3b8)][_0x2b8676(0x334)](_0x3059a4, _0x3ede90) && (_0x451cfb[_0x3ede90] = _0x3059a4[_0x3ede90]);\n                    }\n                }\n                return _0x451cfb;\n            },\n            'writable': !(0x3d * -0x43 + 0x2368 + -0x1371),\n            'configurable': !(0x12a + -0x1692 + 0x1568)\n        }),\n        Object[_0x5612de(0x17f)] || (Object['keys'] = (_0x4d6c78 = Object[_0x5612de(0x344)][_0x5612de(0x3b8)],\n                _0x312e19 = !{\n                    'toString': null\n                }[_0x5612de(0x1da)]('toString'),\n                _0x2a32a1 = [_0x5612de(0x3ae), _0x5612de(0x2c8), _0x5612de(0x303), _0x5612de(0x3b8), 'isPrototypeOf', _0x5612de(0x1da), 'constructor'],\n                _0x371ac2 = _0x2a32a1[_0x5612de(0x259)],\n                function (_0x457a19) {\n                    var _0x2d3152 = _0x5612de;\n                    if (_0x2d3152(0x1ee) != typeof _0x457a19 && (_0x2d3152(0x17d) !== _0x1db123(_0x457a19) || null === _0x457a19))\n                        throw new TypeError(_0x2d3152(0x374));\n                    var _0x11aef0, _0x29131e, _0x4c2a63 = [];\n                    for (_0x11aef0 in _0x457a19)\n                        _0x4d6c78[_0x2d3152(0x334)](_0x457a19, _0x11aef0) && _0x4c2a63[_0x2d3152(0x36e)](_0x11aef0);\n                    if (_0x312e19) {\n                        for (_0x29131e = -0x2406 + -0x1209 + 0x1 * 0x360f; _0x29131e < _0x371ac2; _0x29131e++)\n                            _0x4d6c78['call'](_0x457a19, _0x2a32a1[_0x29131e]) && _0x4c2a63[_0x2d3152(0x36e)](_0x2a32a1[_0x29131e]);\n                    }\n                    return _0x4c2a63;\n                }\n        ));\n        var _0x45b94b = {\n            '__version__': _0x5612de(0x167),\n            'feVersion': 0x2,\n            'domNotValid': !(-0x1e27 + -0x3fa * -0x2 + 0x1634),\n            'refererKey': _0x5612de(0x318),\n            'pushVersion': _0x5612de(0x2ca),\n            'secInfoHeader': _0x5612de(0x248)\n        };\n\n        function _0x598972(_0x215b45, _0x2d7329) {\n            var _0x401595 = _0x5612de;\n            if (_0x401595(0x33c) == typeof _0x2d7329)\n                for (var _0x5d92d9, _0x112fe4 = _0x215b45 + '=', _0x28aeed = _0x2d7329[_0x401595(0x342)](/[;&]/), _0x26307f = 0x11 * -0x97 + 0x126 * -0xd + -0x1 * -0x18f5; _0x26307f < _0x28aeed[_0x401595(0x259)]; _0x26307f++) {\n                    for (_0x5d92d9 = _0x28aeed[_0x26307f]; '\\x20' === _0x5d92d9['charAt'](0x1589 + 0x5e4 + 0x7 * -0x3eb);)\n                        _0x5d92d9 = _0x5d92d9[_0x401595(0x1b0)](-0x16d9 + -0x1 * 0x99c + 0x2 * 0x103b, _0x5d92d9['length']);\n                    if (0x15cd + -0x1235 + 0x1 * -0x398 === _0x5d92d9[_0x401595(0x2c5)](_0x112fe4))\n                        return _0x5d92d9[_0x401595(0x1b0)](_0x112fe4[_0x401595(0x259)], _0x5d92d9[_0x401595(0x259)]);\n                }\n        }\n\n        function _0x24dc34(_0x3e96bb) {\n            var _0x22cc3b = _0x5612de;\n            try {\n                var _0xdacad4 = '';\n                return window['sessionStorage'] && (_0xdacad4 = window['sessionStorage'][_0x22cc3b(0x2d8)](_0x3e96bb)) || window[_0x22cc3b(0x1dc)] && (_0xdacad4 = window[_0x22cc3b(0x1dc)][_0x22cc3b(0x2d8)](_0x3e96bb)) ? _0xdacad4 : _0xdacad4 = _0x598972(_0x3e96bb, document['cookie']);\n            } catch (_0x195c1d) {\n                return '';\n            }\n        }\n\n        function _0x1f42cb(_0x247ee6, _0x28501b) {\n            var _0xfed486 = _0x5612de;\n            try {\n                window[_0xfed486(0x3be)] && window['sessionStorage']['setItem'](_0x247ee6, _0x28501b),\n                window[_0xfed486(0x1dc)] && window[_0xfed486(0x1dc)][_0xfed486(0x1c4)](_0x247ee6, _0x28501b),\n                    (document[_0xfed486(0x272)] = _0x247ee6 + _0xfed486(0x35e),\n                        document[_0xfed486(0x272)] = _0x247ee6 + '=' + _0x28501b + _0xfed486(0x1c1) + new Date(new Date()['getTime']() + (0x10 * 0x792317 + 0x37870478 + -0x2 * 0xd8658f4))[_0xfed486(0x15e)]() + _0xfed486(0x3c1));\n            } catch (_0x2bd822) {\n            }\n        }\n\n        function _0x2ecc5a(_0x5893e4) {\n            var _0x3a0d7f = _0x5612de;\n            try {\n                window[_0x3a0d7f(0x3be)] && window['sessionStorage']['removeItem'](_0x5893e4),\n                window[_0x3a0d7f(0x1dc)] && window[_0x3a0d7f(0x1dc)][_0x3a0d7f(0x2c3)](_0x5893e4),\n                    document[_0x3a0d7f(0x272)] = _0x5893e4 + _0x3a0d7f(0x35e);\n            } catch (_0x2f5b70) {\n            }\n        }\n\n        for (var _0x462335 = {\n            'boe': !(0x1e0d + -0x1093 * 0x1 + -0xd79),\n            'aid': 0x0,\n            'dfp': !(-0x1 * 0x703 + 0x1025 + 0x29 * -0x39),\n            'sdi': !(0x49 * -0x77 + -0x6da * 0x2 + -0x4 * -0xbe9),\n            'enablePathList': [],\n            '_enablePathListRegex': [],\n            'urlRewriteRules': [],\n            '_urlRewriteRules': [],\n            'initialized': !(-0x31 * 0x3d + 0x9df + 0x1cf),\n            'enableTrack': !(0x89 * -0x1a + -0x21ca + 0x2fb5),\n            'track': {\n                'unitTime': 0x0,\n                'unitAmount': 0x0,\n                'fre': 0x0\n            },\n            'triggerUnload': !(-0x3e5 * -0x5 + -0x23cb + 0x3 * 0x571),\n            'region': '',\n            'regionConf': {},\n            'umode': 0x0,\n            'v': !(-0x1155 + -0x25d4 + -0x1 * -0x372a),\n            '_enableSignature': [],\n            'perf': !(0x1 * -0x1c2e + 0xef8 + -0xc7 * -0x11),\n            'xxbg': !(-0xf75 + 0x3 * 0x4e5 + 0x12 * 0xb)\n        }, _0x3d40ff = {\n            'debug': function (_0x2cf151, _0x4acfb1) {\n                var _0x1b6639 = _0x5612de;\n                _0x462335[_0x1b6639(0x1b6)];\n            }\n        }, _0x100715 = _0x5612de(0x2d7)[_0x5612de(0x342)](''), _0x1f510e = [], _0x37750d = [], _0x1cb307 = -0xe55 + 0x1c37 + 0x2 * -0x6f1; _0x1cb307 < 0x241b + 0x10 * -0xe6 + -0x1 * 0x14bb; _0x1cb307++)\n            _0x1f510e[_0x1cb307] = _0x100715[_0x1cb307 >> 0xd03 + -0x269a + 0x1 * 0x199b & 0xa64 * 0x3 + -0xf7b + -0xfa2] + _0x100715[0x2bb + -0x3 * 0x92d + 0x18db & _0x1cb307],\n            _0x1cb307 < -0x1 * -0x82 + 0x34 * -0x3b + -0x2 * -0x5c5 && (_0x1cb307 < 0x10f1 * 0x1 + 0x86a * 0x4 + -0x328f ? _0x37750d[-0x2029 + -0x1ef1 + -0x3f4a * -0x1 + _0x1cb307] = _0x1cb307 : _0x37750d[-0x2485 + 0x1d * 0x6d + 0x1883 + _0x1cb307] = _0x1cb307);\n        var _0x55de18 = function (_0x33a277) {\n                var _0x5155ba = _0x5612de;\n                for (var _0x9eb2a1 = _0x33a277[_0x5155ba(0x259)], _0x1edfde = '', _0x2a69c4 = -0x1c39 + 0x569 + 0x16d0; _0x2a69c4 < _0x9eb2a1;)\n                    _0x1edfde += _0x1f510e[_0x33a277[_0x2a69c4++]];\n                return _0x1edfde;\n            }\n            , _0x655940 = function (_0x177456) {\n                for (var _0x1ffb9c = _0x177456['length'] >> 0x1 * 0x104b + 0x10b1 + -0x20fb, _0x3563ef = _0x1ffb9c << -0x1 * -0x263 + -0x77 * -0x21 + 0xd * -0x15d, _0x22520c = new Uint8Array(_0x1ffb9c), _0x32553 = 0x345 * 0x9 + -0x1e9a + -0x1 * -0x12d, _0x11b847 = 0x1 * 0x623 + -0x239f * -0x1 + -0x29c2; _0x11b847 < _0x3563ef;)\n                    _0x22520c[_0x32553++] = _0x37750d[_0x177456['charCodeAt'](_0x11b847++)] << -0x1551 + -0xb5a + 0x20af * 0x1 | _0x37750d[_0x177456['charCodeAt'](_0x11b847++)];\n                return _0x22520c;\n            }\n            , _0x42e709 = {\n                'encode': _0x55de18,\n                'decode': _0x655940\n            }\n            ,\n            _0x1e7721 = _0x5612de(0x384) != typeof globalThis ? globalThis : _0x5612de(0x384) != typeof window ? window : _0x5612de(0x384) != typeof global ? global : 'undefined' != typeof self ? self : {};\n\n        function _0x3bc8d3(_0x14565d) {\n            var _0x442e14 = _0x5612de;\n            return _0x14565d && _0x14565d[_0x442e14(0x3bd)] && Object[_0x442e14(0x344)][_0x442e14(0x3b8)][_0x442e14(0x334)](_0x14565d, _0x442e14(0x1d3)) ? _0x14565d[_0x442e14(0x1d3)] : _0x14565d;\n        }\n\n        function _0x3abc0b(_0x1ca7bd) {\n            var _0x292845 = _0x5612de;\n            return _0x1ca7bd && Object[_0x292845(0x344)]['hasOwnProperty'][_0x292845(0x334)](_0x1ca7bd, _0x292845(0x1d3)) ? _0x1ca7bd[_0x292845(0x1d3)] : _0x1ca7bd;\n        }\n\n        function _0x41ace1(_0x2b7455) {\n            var _0x39470d = _0x5612de;\n            return _0x2b7455 && Object[_0x39470d(0x344)][_0x39470d(0x3b8)]['call'](_0x2b7455, _0x39470d(0x1d3)) && 0x155 + 0x16f8 + -0x184c === Object[_0x39470d(0x17f)](_0x2b7455)[_0x39470d(0x259)] ? _0x2b7455[_0x39470d(0x1d3)] : _0x2b7455;\n        }\n\n        function _0x3e9554(_0x22797e) {\n            var _0x1fa97f = _0x5612de;\n            if (_0x22797e[_0x1fa97f(0x3bd)])\n                return _0x22797e;\n            var _0x21d08f = Object[_0x1fa97f(0x175)]({}, _0x1fa97f(0x3bd), {\n                'value': !(0x1f82 + -0x10d * 0x1d + 0x5 * -0x35)\n            });\n            return Object[_0x1fa97f(0x17f)](_0x22797e)['forEach'](function (_0x19f7e0) {\n                var _0x1f5a81 = _0x1fa97f\n                    , _0x3cf185 = Object[_0x1f5a81(0x2a6)](_0x22797e, _0x19f7e0);\n                Object['defineProperty'](_0x21d08f, _0x19f7e0, _0x3cf185[_0x1f5a81(0x32b)] ? _0x3cf185 : {\n                    'enumerable': !(-0x222 * -0x8 + 0x1 * -0x21ac + 0x84e * 0x2),\n                    'get': function () {\n                        return _0x22797e[_0x19f7e0];\n                    }\n                });\n            }),\n                _0x21d08f;\n        }\n\n        function _0x56409e(_0x362d96) {\n            var _0x265452 = _0x5612de\n                , _0x5870ef = {\n                'exports': {}\n            };\n            return _0x362d96(_0x5870ef, _0x5870ef[_0x265452(0x1b8)]),\n                _0x5870ef['exports'];\n        }\n\n        function _0x171dc9(_0x5983b9) {\n            var _0x32782f = _0x5612de;\n            throw new Error(_0x32782f(0x36d) + _0x5983b9 + _0x32782f(0x357));\n        }\n\n        var _0x90795 = _0x56409e(function (_0xb9c7d1) {\n            !(function () {\n                var _0x2db296 = w_0x25f3\n                    , _0x1f977a = 'input\\x20is\\x20invalid\\x20type'\n                    , _0x5a87b4 = _0x2db296(0x17d) == typeof window\n                    , _0x11d177 = _0x5a87b4 ? window : {};\n                _0x11d177[_0x2db296(0x37a)] && (_0x5a87b4 = !(-0x15c4 + 0x97d * -0x2 + 0xb7 * 0x39));\n                var _0x387fd8 = !_0x5a87b4 && _0x2db296(0x17d) == typeof self\n                    ,\n                    _0x2e1226 = !_0x11d177[_0x2db296(0x216)] && _0x2db296(0x17d) == typeof process && process[_0x2db296(0x194)] && process[_0x2db296(0x194)][_0x2db296(0x287)];\n                _0x2e1226 ? _0x11d177 = _0x1e7721 : _0x387fd8 && (_0x11d177 = self);\n                var _0x299a21 = !_0x11d177['JS_MD5_NO_COMMON_JS'] && _0xb9c7d1[_0x2db296(0x1b8)],\n                    _0x5efc8f = !(-0x8c4 + -0xc3a + -0x1 * -0x14ff),\n                    _0x1edc95 = !_0x11d177[_0x2db296(0x2e6)] && 'undefined' != typeof ArrayBuffer,\n                    _0x142491 = _0x2db296(0x2d7)[_0x2db296(0x342)](''),\n                    _0x146907 = [0x148 * 0x5 + -0x753 * 0x2 + -0x175 * -0x6, 0x1 * 0x340b + 0x460a + 0x1f9 * 0x3, 0x2766cb + -0x6327ac + 0x353 * 0x387b, -(-0xc13e2aae + -0x3aff8440 + 0x17c3daeee)],\n                    _0x4d13bd = [-0x1721 + -0x1 * 0x611 + 0x1d32, -0x390 + -0x3a5 * -0x3 + -0x757, 0x5fc + -0x64d * -0x2 + -0x1286, 0x278 + 0x3 * 0x105 + -0x56f],\n                    _0x3f581b = [_0x2db296(0x352), _0x2db296(0x238), _0x2db296(0x19b), _0x2db296(0x275), 'arrayBuffer', _0x2db296(0x25f)],\n                    _0xcb4d61 = _0x2db296(0x315)[_0x2db296(0x342)](''), _0x5c5e45 = [], _0x54b265;\n                if (_0x1edc95) {\n                    var _0x171107 = new ArrayBuffer(0xc87 + -0xcd8 + 0x95);\n                    _0x54b265 = new Uint8Array(_0x171107),\n                        _0x5c5e45 = new Uint32Array(_0x171107);\n                }\n                !_0x11d177[_0x2db296(0x216)] && Array[_0x2db296(0x2af)] || (Array['isArray'] = function (_0x263669) {\n                        var _0x1dd8cd = _0x2db296;\n                        return _0x1dd8cd(0x331) === Object['prototype']['toString']['call'](_0x263669);\n                    }\n                ),\n                !_0x1edc95 || !_0x11d177[_0x2db296(0x305)] && ArrayBuffer['isView'] || (ArrayBuffer['isView'] = function (_0x4d052f) {\n                        var _0x23ceed = _0x2db296;\n                        return _0x23ceed(0x17d) == typeof _0x4d052f && _0x4d052f[_0x23ceed(0x275)] && _0x4d052f['buffer'][_0x23ceed(0x2ac)] === ArrayBuffer;\n                    }\n                );\n                var _0x2e393f = function (_0x55b71b) {\n                    return function (_0x6901ec) {\n                        var _0x38b178 = w_0x25f3;\n                        return new _0x22f902(!(0x191d + 0x9e + -0x19bb))[_0x38b178(0x2d5)](_0x6901ec)[_0x55b71b]();\n                    }\n                        ;\n                }\n                    , _0x1edabb = function () {\n                    var _0x5664ca = _0x2db296\n                        , _0x4c275f = _0x2e393f(_0x5664ca(0x352));\n                    _0x2e1226 && (_0x4c275f = _0x4d7e2d(_0x4c275f)),\n                        _0x4c275f[_0x5664ca(0x3b7)] = function () {\n                            return new _0x22f902();\n                        }\n                        ,\n                        _0x4c275f['update'] = function (_0x5c3464) {\n                            return _0x4c275f['create']()['update'](_0x5c3464);\n                        }\n                    ;\n                    for (var _0x349d5f = -0x9d * -0x1f + 0x1 * 0x230c + -0x15 * 0x293; _0x349d5f < _0x3f581b[_0x5664ca(0x259)]; ++_0x349d5f) {\n                        var _0x1537c4 = _0x3f581b[_0x349d5f];\n                        _0x4c275f[_0x1537c4] = _0x2e393f(_0x1537c4);\n                    }\n                    return _0x4c275f;\n                }\n                    , _0x4d7e2d = function (_0x1afe1b) {\n                    var _0x3e0a6e = eval('var _0x13db80 = w_0x25f3;require(_0x13db80(628));')\n                        , _0x5bfe7e = eval('var _0x20dc8b = w_0x25f3;require(\\'buffer\\')[_0x20dc8b(424)];')\n                        , _0x3d7396 = function (_0x5142ff) {\n                        var _0x30639a = w_0x25f3;\n                        if (_0x30639a(0x33c) == typeof _0x5142ff)\n                            return _0x3e0a6e[_0x30639a(0x1ca)](_0x30639a(0x35c))[_0x30639a(0x2d5)](_0x5142ff, _0x30639a(0x2a8))[_0x30639a(0x19b)](_0x30639a(0x352));\n                        if (null == _0x5142ff)\n                            throw _0x1f977a;\n                        return _0x5142ff[_0x30639a(0x2ac)] === ArrayBuffer && (_0x5142ff = new Uint8Array(_0x5142ff)),\n                            Array[_0x30639a(0x2af)](_0x5142ff) || ArrayBuffer[_0x30639a(0x2c7)](_0x5142ff) || _0x5142ff[_0x30639a(0x2ac)] === _0x5bfe7e ? _0x3e0a6e[_0x30639a(0x1ca)](_0x30639a(0x35c))['update'](new _0x5bfe7e(_0x5142ff))[_0x30639a(0x19b)](_0x30639a(0x352)) : _0x1afe1b(_0x5142ff);\n                    };\n                    return _0x3d7396;\n                };\n\n                function _0x22f902(_0xad0da7) {\n                    var _0x68ef08 = _0x2db296;\n                    if (_0xad0da7)\n                        _0x5c5e45[-0x1b4c * 0x1 + -0x126b * 0x2 + 0x4022] = _0x5c5e45[0x143f + -0x2217 + 0xde8] = _0x5c5e45[0x16 * 0x2e + -0x1d7c + 0x1989] = _0x5c5e45[0xa0 * -0x26 + -0x3 * 0x93f + 0x337f * 0x1] = _0x5c5e45[-0xed2 + 0xe1d + 0x2e * 0x4] = _0x5c5e45[-0x10ff + -0x1 * -0x394 + 0xd6f] = _0x5c5e45[-0x36f * -0x2 + 0x1 * 0x1a5 + -0x87e] = _0x5c5e45[-0x1f81 * 0x1 + 0x25ce * -0x1 + -0x1 * -0x4555] = _0x5c5e45[0x1ae7 * 0x1 + 0x1 * -0xe3c + -0xca4 * 0x1] = _0x5c5e45[-0x583 * -0x4 + -0x5f7 * -0x5 + -0x33d7] = _0x5c5e45[0x25e + -0x1d4b * 0x1 + -0x3a * -0x77] = _0x5c5e45[0xef9 + -0x30 * -0x57 + -0x1f3f] = _0x5c5e45[0x11e + -0x18f * 0x7 + 0x9d6] = _0x5c5e45[-0x2521 * -0x1 + 0x1 * 0x1bf4 + 0x4109 * -0x1] = _0x5c5e45[0x19 * 0xa6 + 0x1f06 + -0x2f2f] = _0x5c5e45[-0x22d0 + 0x1f1 * 0xf + 0x5bf] = _0x5c5e45[0x7 * 0x549 + -0xa39 + 0x1 * -0x1ab7] = 0x1 * -0xfb + 0x1995 + 0xc4d * -0x2,\n                            this['blocks'] = _0x5c5e45,\n                            this[_0x68ef08(0x329)] = _0x54b265;\n                    else {\n                        if (_0x1edc95) {\n                            var _0x44d65b = new ArrayBuffer(0x11 * -0xb + 0xbfd + -0xafe);\n                            this[_0x68ef08(0x329)] = new Uint8Array(_0x44d65b),\n                                this[_0x68ef08(0x319)] = new Uint32Array(_0x44d65b);\n                        } else\n                            this[_0x68ef08(0x319)] = [0x45 * 0x10 + -0xd15 + 0x8c5, 0x1d70 + 0x493 + -0x2203 * 0x1, 0x46 * 0x86 + 0x8 * -0x14e + -0x1a34, 0x9bb + 0x25 * 0xdf + -0x29f6, -0x1c * -0xda + 0x188 + 0xcb * -0x20, -0x442 + -0x199a + 0x1ddc, -0x2 * -0x32d + -0x605 * -0x2 + -0x1264, 0x1af * -0x8 + -0xf3c + 0x29c * 0xb, -0x8cc + 0x1c3 + 0x709 * 0x1, 0xb53 * 0x1 + 0x18e6 + -0x3 * 0xc13, -0x2 * 0x135e + 0x444 + 0x2278, 0xe8 * 0x2b + 0x2106 + -0xa * 0x733, 0x3 * 0x449 + 0x1103 + -0x1dde, 0x30 + -0x3 * -0x95 + -0x1ef, 0x3ca * -0x3 + -0x9 * -0x1cb + -0x3 * 0x197, -0x14ce + -0x1b9 + 0x1687, -0xb2f + -0x53f * 0x3 + 0x1aec];\n                    }\n                    this['h0'] = this['h1'] = this['h2'] = this['h3'] = this[_0x68ef08(0x385)] = this[_0x68ef08(0x25b)] = this[_0x68ef08(0x1cd)] = -0x1 * 0x4f9 + 0xeb * -0xd + 0x10e8,\n                        this[_0x68ef08(0x182)] = this[_0x68ef08(0x1e9)] = !(-0x983 + -0x5b1 * -0x1 + 0x3d3),\n                        this[_0x68ef08(0x19f)] = !(-0xcdf + 0x2157 + -0x1478);\n                }\n\n                _0x22f902[_0x2db296(0x344)][_0x2db296(0x2d5)] = function (_0x36f09d) {\n                    var _0x449340 = _0x2db296;\n                    if (!this['finalized']) {\n                        var _0x462898, _0x1dd68e = typeof _0x36f09d;\n                        if (_0x449340(0x33c) !== _0x1dd68e) {\n                            if ('object' !== _0x1dd68e)\n                                throw _0x1f977a;\n                            if (null === _0x36f09d)\n                                throw _0x1f977a;\n                            if (_0x1edc95 && _0x36f09d['constructor'] === ArrayBuffer)\n                                _0x36f09d = new Uint8Array(_0x36f09d);\n                            else {\n                                if (!(Array[_0x449340(0x2af)](_0x36f09d) || _0x1edc95 && ArrayBuffer['isView'](_0x36f09d)))\n                                    throw _0x1f977a;\n                            }\n                            _0x462898 = !(-0xfea + 0x449 * 0x3 + -0x1 * -0x30f);\n                        }\n                        for (var _0x2c6513, _0x1fd15b, _0x432ef6 = 0xadd + -0x4d7 * 0x2 + 0x1 * -0x12f, _0x383058 = _0x36f09d[_0x449340(0x259)], _0x17a6ed = this[_0x449340(0x319)], _0x161a31 = this[_0x449340(0x329)]; _0x432ef6 < _0x383058;) {\n                            if (this[_0x449340(0x1e9)] && (this[_0x449340(0x1e9)] = !(-0x657 + 0x4fb + -0x15d * -0x1),\n                                _0x17a6ed[0x22e1 * -0x1 + -0xeb2 + 0x3193] = _0x17a6ed[0x283 * -0xd + -0x141e + 0x34d5],\n                                _0x17a6ed[0x1af3 * 0x1 + -0x14d1 * 0x1 + -0x15 * 0x4a] = _0x17a6ed[-0xc3 * -0x2f + -0x49 * -0x31 + 0x3 * -0x1097] = _0x17a6ed[0x1e34 + -0x1 * -0x1837 + -0x3669] = _0x17a6ed[-0x12e3 + -0x1733 * -0x1 + 0x1 * -0x44d] = _0x17a6ed[0x31 * -0x8b + 0x1643 * 0x1 + 0x45c] = _0x17a6ed[0x87 * -0xd + -0x14d5 + 0x1bb5] = _0x17a6ed[0x1d70 + 0x255a + 0x4 * -0x10b1] = _0x17a6ed[0x1312 + 0x2e6 + 0x15f1 * -0x1] = _0x17a6ed[0x1ed9 + 0x551 * -0x1 + -0x1980] = _0x17a6ed[0x269 * -0x7 + 0x1d8 + 0xf10] = _0x17a6ed[0x1134 + -0x1 * -0x15cd + -0xcfd * 0x3] = _0x17a6ed[0x1229 * 0x1 + 0x23 * -0xe3 + 0xceb] = _0x17a6ed[0x15 * 0x13a + -0x23e3 * 0x1 + 0x1 * 0xa2d] = _0x17a6ed[-0x4 * 0x8ee + -0x1d7d + 0x4142 * 0x1] = _0x17a6ed[0x9d9 + 0x1 * -0x215b + 0x34 * 0x74] = _0x17a6ed[0x1e72 + -0x9 * 0x2b + 0xa8 * -0x2c] = 0x857 + 0x1cef + -0x2546),\n                                _0x462898) {\n                                if (_0x1edc95) {\n                                    for (_0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x836 + 0x1150 + -0xce * 0xb; ++_0x432ef6)\n                                        _0x161a31[_0x1fd15b++] = _0x36f09d[_0x432ef6];\n                                } else {\n                                    for (_0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x4 * -0x4e8 + -0xedb * 0x1 + -0x485; ++_0x432ef6)\n                                        _0x17a6ed[_0x1fd15b >> 0x11 * 0x5c + 0x1378 * -0x2 + 0x3 * 0xaf2] |= _0x36f09d[_0x432ef6] << _0x4d13bd[0x1 * -0x4f + -0x2036 + -0x1044 * -0x2 & _0x1fd15b++];\n                                }\n                            } else {\n                                if (_0x1edc95) {\n                                    for (_0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < 0xc4 * -0x1 + 0x78f * -0x1 + 0x893; ++_0x432ef6)\n                                        (_0x2c6513 = _0x36f09d[_0x449340(0x195)](_0x432ef6)) < 0xd * 0x1a + 0x8f + -0x161 ? _0x161a31[_0x1fd15b++] = _0x2c6513 : _0x2c6513 < 0x1b9a + 0x1 * -0x4a9 + 0xef1 * -0x1 ? (_0x161a31[_0x1fd15b++] = -0x1aaa * -0x1 + 0x2511 * -0x1 + -0x23b * -0x5 | _0x2c6513 >> 0x1568 + 0x75a * 0x1 + -0x994 * 0x3,\n                                            _0x161a31[_0x1fd15b++] = 0x54a + -0x1 * 0x1a66 + -0x1cd * -0xc | 0x8ad * 0x4 + 0x6a3 * 0x1 + -0x2918 & _0x2c6513) : _0x2c6513 < 0x1807f + -0x1 * -0x44d4 + 0xed53 * -0x1 || _0x2c6513 >= -0x1 * -0x123e4 + 0x1be31 + -0x5 * 0x66d1 ? (_0x161a31[_0x1fd15b++] = 0x1 * 0x11f + 0xffd * -0x1 + 0xfbe | _0x2c6513 >> 0x1 * 0x65 + 0x533 + -0x11c * 0x5,\n                                            _0x161a31[_0x1fd15b++] = 0x4 * 0x72b + 0x23c9 * 0x1 + -0x3ff5 | _0x2c6513 >> 0x9 * 0x9 + 0x5 * 0x517 + -0x5 * 0x526 & 0x200b + 0x1 * 0xbe7 + -0x2bb3,\n                                            _0x161a31[_0x1fd15b++] = 0x1 * 0x128f + 0x11 * -0x6a + -0xb05 | 0x27 * 0x59 + -0x2126 + 0x1 * 0x13d6 & _0x2c6513) : (_0x2c6513 = -0xb295 + 0x185 * 0x139 + -0x2908 + ((-0x1ec2 * -0x1 + -0x183e + -0xf * 0x2b & _0x2c6513) << 0x2e * 0x3 + 0x14b + 0x1 * -0x1cb | 0x1225 * 0x1 + 0x2376 + -0x319c & _0x36f09d[_0x449340(0x195)](++_0x432ef6)),\n                                            _0x161a31[_0x1fd15b++] = -0x969 + 0xc97 + -0x23e | _0x2c6513 >> -0xc19 + -0x14f9 + 0x2124,\n                                            _0x161a31[_0x1fd15b++] = 0x202 + 0x1 * 0x187 + -0x309 | _0x2c6513 >> -0x1da3 + -0xa * 0xda + -0x379 * -0xb & 0x2 * -0x117b + -0x7c9 + 0x2afe,\n                                            _0x161a31[_0x1fd15b++] = 0x1 * -0x1043 + 0x1185 + -0xc2 | _0x2c6513 >> -0x8c6 + 0x1d87 + -0x1d * 0xb7 & 0x2a * 0xe7 + -0x1 * 0x1869 + -0xd3e,\n                                            _0x161a31[_0x1fd15b++] = -0x58e + 0x6 * -0x216 + 0x949 * 0x2 | 0x2474 * -0x1 + 0xa9 * 0xd + 0x1c1e & _0x2c6513);\n                                } else {\n                                    for (_0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x48a * 0x7 + 0x1993 + -0xd * -0x7f; ++_0x432ef6)\n                                        (_0x2c6513 = _0x36f09d[_0x449340(0x195)](_0x432ef6)) < 0x2 * -0x86 + 0x101 * 0x1f + -0x1 * 0x1d93 ? _0x17a6ed[_0x1fd15b >> -0x1297 + 0x71a + 0xb7f] |= _0x2c6513 << _0x4d13bd[-0x1f26 + 0xd17 + 0x1212 & _0x1fd15b++] : _0x2c6513 < 0x11b7 + -0x150d + 0xb56 ? (_0x17a6ed[_0x1fd15b >> -0x231f + -0x8eb + 0x2c0c] |= (0x1ae0 + 0x70b + -0x212b | _0x2c6513 >> -0x87f + -0x23f * 0x5 + -0x13c * -0x10) << _0x4d13bd[0x3fb + 0x8e1 * -0x1 + 0x4e9 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> -0x1d97 + 0x6ad + 0x16ec] |= (0x1d0e + 0xf0a + -0x2b98 | 0xf2c + 0xbb * -0x20 + 0x873 & _0x2c6513) << _0x4d13bd[0x8d9 + -0x17e0 + 0xf0a & _0x1fd15b++]) : _0x2c6513 < -0x8b7d + 0x113bf + 0x4fbe || _0x2c6513 >= -0xc9c0 + 0x16d4a * 0x1 + 0x3c76 ? (_0x17a6ed[_0x1fd15b >> 0x2 * 0x74f + 0x1533 + -0x23cf] |= (-0x7 * 0x28 + -0x2 * -0x1bb + -0x17e | _0x2c6513 >> 0x1d5c + 0x1e6c + -0x1 * 0x3bbc) << _0x4d13bd[0x12 * 0x119 + 0x4 * -0x1c6 + -0xca7 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> -0x26 * 0x2e + -0x12aa * 0x2 + -0x2c2a * -0x1] |= (0x245a + -0x1aa1 + -0x1 * 0x939 | _0x2c6513 >> 0x1fa6 + -0x735 + -0x2f * 0x85 & -0x5d3 + -0x1eb2 * -0x1 + -0x18a0) << _0x4d13bd[0xa40 + 0x1f49 + -0x84e * 0x5 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> 0x21 * -0xa4 + -0x139 * -0x5 + 0x1 * 0xf09] |= (-0x1434 + 0x5 * -0x35 + 0x15bd | -0xc2d + 0x2655 + 0x25b * -0xb & _0x2c6513) << _0x4d13bd[0x76 * 0x26 + -0x1 * 0x8ad + 0x1c4 * -0x5 & _0x1fd15b++]) : (_0x2c6513 = 0x12e * -0xbf + 0x1cc8a + 0x8c * 0x26 + ((-0x3f5 * 0x3 + -0xfe8 + 0x1fc6 & _0x2c6513) << 0x29a + 0x13a9 + -0x1639 | 0x1 * -0x1dd7 + 0x6a5 + 0x1 * 0x1b31 & _0x36f09d[_0x449340(0x195)](++_0x432ef6)),\n                                            _0x17a6ed[_0x1fd15b >> 0xd * 0x61 + 0xcb * -0x1e + 0x12df] |= (0x1 * -0xee4 + 0x2 * -0x767 + -0x6 * -0x51b | _0x2c6513 >> 0x1 * 0x1a4d + -0x3 * 0x149 + -0x1660) << _0x4d13bd[-0x1c70 + -0x1 * -0x57b + 0x1 * 0x16f8 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> 0xef1 + -0xba0 + -0x1 * 0x34f] |= (-0xa3 * -0x3 + 0x26af + 0x140c * -0x2 | _0x2c6513 >> -0x518 + 0x1 * -0xc26 + 0x114a & -0x25 * -0xd1 + -0x1130 * -0x1 + -0x2f26) << _0x4d13bd[-0x73 * -0xb + -0x17d * 0x1 + 0x1 * -0x371 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> 0x3 * -0x107 + 0x1dbd + -0x1aa6] |= (-0x151c + 0x16 * -0x191 + 0x3812 | _0x2c6513 >> 0xded * -0x1 + 0x45 + 0xdae & -0x2af * -0x7 + -0x49 + 0x1241 * -0x1) << _0x4d13bd[-0x19a2 + -0x7d2 + 0x2177 & _0x1fd15b++],\n                                            _0x17a6ed[_0x1fd15b >> -0x180e + 0x13d2 + -0x1 * -0x43e] |= (-0x9 * -0x1f5 + -0xf1 * 0xd + -0x6 * 0xd0 | 0x7f * 0x2f + 0x1 * 0x188c + -0x986 * 0x5 & _0x2c6513) << _0x4d13bd[0x1cf9 + 0xb * -0xe7 + -0x1309 & _0x1fd15b++]);\n                                }\n                            }\n                            this['lastByteIndex'] = _0x1fd15b,\n                                this[_0x449340(0x25b)] += _0x1fd15b - this['start'],\n                                _0x1fd15b >= -0xa42 + 0x2 * -0x11c3 + 0x2e08 ? (this[_0x449340(0x385)] = _0x1fd15b - (-0x2b * 0xe2 + 0xa55 + 0xd * 0x225),\n                                    this[_0x449340(0x2ba)](),\n                                    this[_0x449340(0x1e9)] = !(0xc54 + -0x1 * -0xfa3 + -0x1 * 0x1bf7)) : this[_0x449340(0x385)] = _0x1fd15b;\n                        }\n                        return this[_0x449340(0x25b)] > -0x14462193f + -0xd7facb0 + -0x2 * -0x128f0e2f7 && (this['hBytes'] += this['bytes'] / (0x73e4b4e0 * 0x3 + -0x3fc * -0x40b5a1 + -0x486a * 0x4d396) << -0x1fbb * 0x1 + -0x1623 + 0x35de,\n                            this[_0x449340(0x25b)] = this[_0x449340(0x25b)] % (0x7d756c * -0x1e1 + -0x3b6aede * -0x2 + 0x278 * 0xc42bda)),\n                            this;\n                    }\n                }\n                    ,\n                    _0x22f902[_0x2db296(0x344)][_0x2db296(0x1d9)] = function () {\n                        var _0x8b694 = _0x2db296;\n                        if (!this[_0x8b694(0x182)]) {\n                            this[_0x8b694(0x182)] = !(0x1038 + 0x1 * -0x247f + 0x1d * 0xb3);\n                            var _0x52f24a = this[_0x8b694(0x319)]\n                                , _0x21cbd8 = this[_0x8b694(0x32e)];\n                            _0x52f24a[_0x21cbd8 >> 0x4cd * 0x4 + -0x1 * -0x1511 + -0x2843] |= _0x146907[0xb2e + -0x10 * -0xbf + -0x41 * 0x5b & _0x21cbd8],\n                            _0x21cbd8 >= 0x8fe * 0x3 + -0x231c + -0x42d * -0x2 && (this['hashed'] || this['hash'](),\n                                _0x52f24a[0x666 + 0x1432 + -0x1a98] = _0x52f24a[0x24cd + 0x1e1 * 0x14 + 0x19 * -0x2f9],\n                                _0x52f24a[-0x1f46 + 0x1 * 0x1015 + 0xf41] = _0x52f24a[0xbe8 + 0x1a96 + 0xa7 * -0x3b] = _0x52f24a[-0xb * 0x14d + -0x1 * 0x59 + -0xeaa * -0x1] = _0x52f24a[-0x1f1 * -0x3 + -0x1d69 + 0x1799] = _0x52f24a[0xa7b * -0x2 + 0xbb1 * -0x1 + -0x20ab * -0x1] = _0x52f24a[-0x11dc + -0xaa + 0x2f * 0x65] = _0x52f24a[-0x1 * 0x1f99 + -0x1e53 * 0x1 + 0x3df2] = _0x52f24a[-0x103 * -0x5 + -0x2451 + 0x1f49] = _0x52f24a[0x21e6 + -0xf9 * 0x1 + -0x1 * 0x20e5] = _0x52f24a[0x88a + -0x1bea + -0x1 * -0x1369] = _0x52f24a[0xf4d + -0x177d * -0x1 + -0x26c0] = _0x52f24a[0x1e22 + 0x655 * 0x3 + -0x3116] = _0x52f24a[-0x196b + 0x19b * -0x10 + -0x2d * -0x123] = _0x52f24a[-0x1 * -0x228d + 0x1cfc + -0x3f7c] = _0x52f24a[-0x13b4 + -0x5bc + 0x197e] = _0x52f24a[0x1e68 + 0x1209 + -0x3062] = 0x26a1 + -0x124 * -0x20 + -0x4b21),\n                                _0x52f24a[0xbb3 + 0x1210 + -0x1db5] = this[_0x8b694(0x25b)] << -0x15 * -0x1d7 + 0x2 * -0xc2a + -0xe4c,\n                                _0x52f24a[-0x19e2 + 0x28 * 0x55 + 0xca9] = this[_0x8b694(0x1cd)] << -0x178 * 0x6 + 0xa67 + 0x194 * -0x1 | this[_0x8b694(0x25b)] >>> 0x1a65 + -0x18 * 0x44 + -0x16c * 0xe,\n                                this['hash']();\n                        }\n                    }\n                    ,\n                    _0x22f902[_0x2db296(0x344)][_0x2db296(0x2ba)] = function () {\n                        var _0x2f0149 = _0x2db296, _0x227f23, _0x3952af, _0x2a0c94, _0x39eb64, _0x2fd641, _0x113678,\n                            _0x128d32 = this[_0x2f0149(0x319)];\n                        this['first'] ? _0x3952af = ((_0x3952af = ((_0x227f23 = ((_0x227f23 = _0x128d32[0xe * 0xd4 + 0x18b * -0x13 + 0x11b9] - (0x1ffe472d + -0x1 * 0x229b4beb + 0x8a3acdb * 0x5)) << -0xe3 + 0x794 * 0x5 + 0x2 * -0x127d | _0x227f23 >>> -0x2125 + 0x21d4 + -0x96) - (-0xa42713c + -0x131 * -0xc4faf + 0xbc9d634) << -0x76 + -0x13ee + 0x1464) ^ (_0x2a0c94 = ((_0x2a0c94 = (-(0x1d99 * -0x236f + 0xdf * -0x44be3 + 0x18092f8b) ^ (_0x39eb64 = ((_0x39eb64 = (-(-0xfc * -0xaf0303 + 0x524d2f32 + -0xcedcd * 0xbb4) ^ 0x1 * 0x7b470ebd + 0x1 * 0x4d64e86c + -0x51347fb2 & _0x227f23) + _0x128d32[-0x2684 + 0x1f4e * -0x1 + 0x8f * 0x7d] - (0x563f0e * -0x16 + 0x59003ae + 0x46faddd * 0x2)) << -0x684 + 0xa * 0x289 + -0x1a * 0xb9 | _0x39eb64 >>> -0x1116 * -0x2 + 0xee9 * -0x1 + -0x132f * 0x1) + _0x227f23 << -0x2687 * -0x1 + 0xfe3 + -0x1 * 0x366a) & (-(0x1a9157f + 0x1e0df645 + -0xf84b74d) ^ _0x227f23)) + _0x128d32[0x144d + 0x15b * -0x18 + 0xc3d] - (-0x1 * 0x5504eeba + 0x76f3f96f * 0x1 + -0x2 * -0x109ad3b9)) << 0x1af4 + -0x12cb + -0x818 | _0x2a0c94 >>> 0x7aa * 0x1 + -0x1994 * -0x1 + -0x212f) + _0x39eb64 << -0x9fc + -0x14 * 0xfa + -0x1d84 * -0x1) & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x2a * 0x97 + 0x18c8 + 0x1 * 0x1] - (-0x992 * 0x9361 + 0x23b1c4 + 0x1 * 0x53d34a17)) << -0x7 * 0x1b1 + -0x234d + -0x136 * -0x27 | _0x3952af >>> -0x113f * 0x1 + 0x5 * -0x7f + 0x1cc * 0xb) + _0x2a0c94 << -0x4f0 + -0x1 * -0x1f3d + -0x1a4d : (_0x227f23 = this['h0'],\n                            _0x3952af = this['h1'],\n                            _0x2a0c94 = this['h2'],\n                            _0x3952af = ((_0x3952af += ((_0x227f23 = ((_0x227f23 += ((_0x39eb64 = this['h3']) ^ _0x3952af & (_0x2a0c94 ^ _0x39eb64)) + _0x128d32[0x3a5 + -0x1684 + 0x12df * 0x1] - (0x2b26bdc2 + -0x1 * -0x4468952b + -0x5773 * 0xcfc7)) << -0x1805 + -0x18cb + 0x30d7 | _0x227f23 >>> 0x21ec * -0x1 + -0x53c * -0x1 + 0x1cc9) + _0x3952af << 0xfe0 + 0x16a4 + -0x2684) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x3952af ^ (_0x39eb64 = ((_0x39eb64 += (_0x2a0c94 ^ _0x227f23 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[0x1 * -0x480 + 0x1 * 0x112f + -0xcae] - (0x1e4d0bcf + 0x1be * -0xbfe2b + 0xdd00bc5)) << -0x26fe + -0x462 + 0x2b6c | _0x39eb64 >>> -0x1 * 0x251 + -0xd16 + 0xf7b) + _0x227f23 << 0x15be * 0x1 + 0x2e3 * 0x8 + -0x2cd6) & (_0x227f23 ^ _0x3952af)) + _0x128d32[-0xa5 * -0x1d + 0x5 * -0x105 + 0x2f * -0x4a] + (0x15 * 0x27c2519 + -0x1cb83878 + 0x654cf23 * 0x2)) << -0x9d5 + -0x221e + -0xeac * -0x3 | _0x2a0c94 >>> -0x718 * 0x2 + -0x5 * -0x556 + -0x425 * 0x3) + _0x39eb64 << 0x223 * -0xb + -0x92 * 0x22 + 0x2ae5) & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x141c + 0x376 + 0x10a9] - (0x29f06346 + 0x14e90f87 * -0x3 + -0x3 * -0x1baefecb)) << 0x103a + -0x24f4 + 0x14d0 | _0x3952af >>> -0x16a5 + -0xe92 + 0xbb * 0x33) + _0x2a0c94 << 0x25a2 * 0x1 + 0x1a76 + -0x4018 * 0x1),\n                            _0x3952af = ((_0x3952af += ((_0x227f23 = ((_0x227f23 += (_0x39eb64 ^ _0x3952af & (_0x2a0c94 ^ _0x39eb64)) + _0x128d32[-0x2552 + 0x577 + 0x1fdf] - (-0xec5a4e1 + 0x23fe4 * -0x78c + -0x9e * -0x447abf)) << -0x46e + 0x19b5 + -0x8 * 0x2a8 | _0x227f23 >>> 0x100e + 0xd63 + -0x1d58) + _0x3952af << -0x237d + 0x1955 * -0x1 + 0x3cd2) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x3952af ^ (_0x39eb64 = ((_0x39eb64 += (_0x2a0c94 ^ _0x227f23 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[-0x203 + 0xd54 + -0x2d3 * 0x4] + (0x1 * -0x20e3c675 + 0x8ef8e325 + 0x4e53fd * -0x7e)) << -0x9e3 * 0x2 + 0x2 * -0x8fd + 0x25cc | _0x39eb64 >>> -0x7bd + 0x2 * -0x844 + 0x1859 * 0x1) + _0x227f23 << -0x3dc + -0x122e + 0x326 * 0x7) & (_0x227f23 ^ _0x3952af)) + _0x128d32[-0xbfd + -0x1 * 0xba3 + 0x17a6] - (-0x93f8bbe0 + -0x43dcbb55 + 0x1 * 0x12fa53122)) << 0x185 * -0x10 + -0x76c + 0x1fcd | _0x2a0c94 >>> 0x19b + 0x51 * 0x6d + 0x171 * -0x19) + _0x39eb64 << 0x971 + 0x1958 + -0x5 * 0x6f5) & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x978 * -0x3 + 0x315 + -0x2 * 0xfbb] - (-0x99026a + 0xa6ba6 * 0x47 + 0xc4927 * 0x9)) << 0x212 + 0x1 * 0x4c3 + 0xb * -0x9d | _0x3952af >>> -0x152a + 0x1 * -0x17b4 + -0x77c * -0x6) + _0x2a0c94 << -0xa7 * 0x1f + 0x2379 + -0xf40,\n                            _0x3952af = ((_0x3952af += ((_0x227f23 = ((_0x227f23 += (_0x39eb64 ^ _0x3952af & (_0x2a0c94 ^ _0x39eb64)) + _0x128d32[-0x251a + -0x14 * -0x18d + 0x61e] + (0xb19f3051 + -0xb487bda1 * 0x1 + 0x6c692628)) << 0x1cc + -0x171a + 0x1555 | _0x227f23 >>> 0x1 * -0x223b + -0x282 + 0x24d6) + _0x3952af << 0x1453 + 0x1aee + -0x2f41) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x3952af ^ (_0x39eb64 = ((_0x39eb64 += (_0x2a0c94 ^ _0x227f23 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[-0x1c63 + -0x1a88 + 0x36f4] - (0x334017ba + 0x1 * -0x90d7af8d + -0x86 * -0x191cf86)) << -0x1db2 + 0x1 * 0x10b1 + 0xd0d | _0x39eb64 >>> -0x4 * -0x20 + -0xd81 * -0x1 + -0xded) + _0x227f23 << -0x2b0 + 0x4 * -0x5b0 + -0x94 * -0x2c) & (_0x227f23 ^ _0x3952af)) + _0x128d32[-0x1 * -0xf25 + 0xe75 * 0x1 + -0x1d90] - (-0x5 * 0x4eb + 0x12ff3 * -0x1 + 0x1 * 0x1ecd9)) << -0xa43 + 0x1eed + 0x1 * -0x1499 | _0x2a0c94 >>> -0x1878 + -0x92b + 0x21b2) + _0x39eb64 << -0x1 * 0x2515 + -0x8c8 + -0x3b * -0xc7) & (_0x39eb64 ^ _0x227f23)) + _0x128d32[0x80b * -0x4 + 0xff5 + 0x1042] - (-0x2d479161 * 0x5 + -0x139 * 0x33685d + 0x197e398dc)) << -0x178 + -0x22bf + 0x1 * 0x244d | _0x3952af >>> 0x15cc + -0x26b6 + -0x5 * -0x364) + _0x2a0c94 << 0x293 * -0x2 + 0x18f7 + -0x13d1,\n                            _0x3952af = ((_0x3952af += ((_0x227f23 = ((_0x227f23 += (_0x39eb64 ^ _0x3952af & (_0x2a0c94 ^ _0x39eb64)) + _0x128d32[-0x1225 + -0xa * -0x348 + 0x13 * -0xc5] + (-0x36f3e05c + 0x4445538c + 0x5e3e9df2)) << -0x1b3 * -0x3 + 0x2702 + -0x2c14 | _0x227f23 >>> -0x2 * 0x1006 + 0x25 * 0xc5 + 0x3ac) + _0x3952af << 0x2501 + 0x18fb + 0xf7f * -0x4) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x3952af ^ (_0x39eb64 = ((_0x39eb64 += (_0x2a0c94 ^ _0x227f23 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[-0x13cb + -0xcd4 + 0x20ac] - (-0x24 * 0x1e9ae6 + -0xa0ba1 * 0x72 + -0x18cc1 * -0x737)) << 0x702 + 0x2b * -0x35 + 0x1f1 | _0x39eb64 >>> -0x15dd + -0x22eb * -0x1 + 0x1 * -0xcfa) + _0x227f23 << 0x224b * 0x1 + 0x2f * 0x33 + 0x4 * -0xaea) & (_0x227f23 ^ _0x3952af)) + _0x128d32[0xec7 * -0x1 + -0x61 * -0x25 + 0xd0] - (0x48e87164 + 0x613cb841 + -0x509e6d33)) << -0x1c0d + 0x5d0 + 0x164e | _0x2a0c94 >>> 0x156a * 0x1 + 0x16e7 + -0x2c42) + _0x39eb64 << -0x1 * -0x19ec + 0x8b4 + -0x22a0) & (_0x39eb64 ^ _0x227f23)) + _0x128d32[0x1df0 + -0x2365 + -0x1 * -0x584] + (0x34eb7 * 0x25f0 + -0x3 * -0x1a616a08 + -0x82ea7487)) << -0x3 * 0xc8c + 0x1fc2 * -0x1 + -0x457c * -0x1 | _0x3952af >>> -0x2464 + 0x2705 + -0xdd * 0x3) + _0x2a0c94 << -0x504 + 0x2 * -0x5f9 + 0x10f6,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ _0x2a0c94 & ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ _0x39eb64 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[0x1b4d + 0x2d4 * 0x5 + -0x2970] - (0x30139 * 0x8d + -0x738f7c2 + -0x1 * -0xf7325fb)) << 0x1acc + -0x13e5 + -0x6e2 | _0x227f23 >>> 0x7 * 0x1 + -0x10e9 + 0x10fd * 0x1) + _0x3952af << -0x18fd + 0x10cc + 0x831) ^ _0x3952af)) + _0x128d32[0x2 * 0x131e + -0x2511 + 0x1 * -0x125] - (-0x1f * -0x3953eea + -0x4 * -0x12786c0f + -0x793501d2)) << 0x210d + 0x11 * -0x241 + 0x54d * 0x1 | _0x39eb64 >>> -0x4 * -0x265 + -0x292 + 0xfd * -0x7) + _0x227f23 << -0x200b + -0xa * 0xff + -0x1 * -0x2a01) ^ _0x227f23 & ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ _0x3952af & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x92 * -0x13 + 0x6b0 + -0x117b] + (-0x4be8e758 + -0x1a3c * -0x1e38f + 0x40b96625)) << -0x1 * 0x13d1 + 0x22da + -0xefb | _0x2a0c94 >>> 0x166d + -0x955 + -0xd06) + _0x39eb64 << -0x13af * 0x1 + -0x1 * -0x1307 + 0xa8) ^ _0x39eb64)) + _0x128d32[-0x547 + -0x1 * 0x1c0b + -0x2152 * -0x1] - (0x7 * 0x14d828a + 0x7d4a6f4 + -0x3 * -0x1c75534)) << 0x1bb9 * -0x1 + -0x26ee + 0x42bb * 0x1 | _0x3952af >>> 0x8 * 0x296 + 0x1ce9 * 0x1 + -0x318d) + _0x2a0c94 << 0x897 * 0x4 + 0x2ca + 0x3 * -0xc62,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ _0x2a0c94 & ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ _0x39eb64 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[0x107f * -0x1 + -0x1299 + -0x59 * -0x65] - (0x1079c263 + -0x1889 * -0x11026 + -0xbe0716)) << -0x260c + -0x1c23 + 0x2 * 0x211a | _0x227f23 >>> 0x22b * 0x1 + -0x16f3 + -0x14e3 * -0x1) + _0x3952af << 0x183b + -0x5 * -0x72a + -0x3c0d * 0x1) ^ _0x3952af)) + _0x128d32[0x4 * 0x86b + 0x1064 + -0x3206] + (-0x1177f56 + -0x27de7f4 + -0x540d * -0x11d1)) << 0x167 * 0x5 + -0x5 * 0x531 + 0x12fb * 0x1 | _0x39eb64 >>> 0x244b + -0x13 * 0x139 + -0x9 * 0x171) + _0x227f23 << -0xf6d + -0x1f9e + 0x2f0b * 0x1) ^ _0x227f23 & ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ _0x3952af & (_0x39eb64 ^ _0x227f23)) + _0x128d32[0x187 * 0x4 + 0x1e69 + -0x2476] - (-0x10191ede + -0xd72a9b7 + 0x44e9e214)) << 0x90 * 0xc + -0x2 * 0x12 + -0x68e | _0x2a0c94 >>> 0x16 * 0x1c5 + 0x137b + 0x1d * -0x203) + _0x39eb64 << -0x14fa + 0x43 * -0x74 + -0x3356 * -0x1) ^ _0x39eb64)) + _0x128d32[-0xf4a + -0x1992 + 0x4 * 0xa38] - (-0xae6496c + 0x21ece5a8 + 0x12567fc)) << 0x1ac8 + -0x1ed2 + 0x3e * 0x11 | _0x3952af >>> 0x1268 + 0x100d + 0x1 * -0x2269) + _0x2a0c94 << 0x1817 * -0x1 + 0x239b + -0xb84 * 0x1,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ _0x2a0c94 & ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ _0x39eb64 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[0x5 * 0x19c + 0xef3 + -0x16f6] + (0x39d62e7 + 0xb397e9b + 0x130aec64)) << 0x11 * 0x21f + -0x1c66 + -0x7a4 | _0x227f23 >>> -0xf86 + 0x2 * -0x4e5 + 0x879 * 0x3) + _0x3952af << 0x258a + 0x19ec + -0x3f76) ^ _0x3952af)) + _0x128d32[0x914 + 0xd73 + 0x20b * -0xb] - (-0xab52d21 + -0x845d9 * 0x1f7 + 0x57bf62aa)) << -0x1 * 0x2f + -0x1280 + 0x12b8 | _0x39eb64 >>> 0x2e * -0x9 + 0x85 * 0x4b + -0x2542) + _0x227f23 << -0x151 * 0x9 + 0x20da + -0x1501) ^ _0x227f23 & ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ _0x3952af & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x84 * 0x39 + 0x57f + 0x2fd * 0x8] - (0x852a967 + 0xa4943f2 + -0x770fae0)) << -0x5 * -0x722 + 0x1 * -0x155f + -0xe3d | _0x2a0c94 >>> 0x171b + -0x2709 * 0x1 + 0x8 * 0x200) + _0x39eb64 << -0x267 + 0x6fb * -0x4 + -0x7 * -0x455) ^ _0x39eb64)) + _0x128d32[0xd73 + -0xe3f + 0xd4] + (-0x882b6c12 + 0x26ddcab5 + 0x9d1 * 0x10fa2a)) << -0x1 * -0xb31 + 0xa * -0x175 + 0x375 | _0x3952af >>> 0x106 * 0x26 + 0x2e9 + -0x29c1) + _0x2a0c94 << -0x198a + 0xb33 * -0x1 + 0x24bd,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ _0x2a0c94 & ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ _0x39eb64 & (_0x3952af ^ _0x2a0c94)) + _0x128d32[0x1d4f + -0x10ae + -0xc94] - (0x76d313f * 0xd + -0x5 * -0x7a635fc + -0x2 * 0x18573b92)) << 0x612 + -0x1 * 0x40 + -0x5cd | _0x227f23 >>> -0x12e9 * 0x2 + -0x1 * -0x19e7 + -0x1 * -0xc06) + _0x3952af << 0x10db + 0x10b5 * 0x1 + -0x3 * 0xb30) ^ _0x3952af)) + _0x128d32[-0x796 + -0x13b9 + 0x1b51] - (-0x17e5b * 0x29 + 0x48058e0 + -0x132c045)) << 0x26d * -0x2 + 0x4 * -0x34e + -0x5 * -0x39f | _0x39eb64 >>> 0x198d * -0x1 + -0x25d4 + -0xa94 * -0x6) + _0x227f23 << 0x206d + -0xd3f + -0x132e) ^ _0x227f23 & ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ _0x3952af & (_0x39eb64 ^ _0x227f23)) + _0x128d32[-0x1f * 0x95 + 0x6 * -0x3dc + -0x3 * -0xdbe] + (-0x2 * 0x5ec874bd + -0x4537c41d * -0x1 + 0xdfc82836)) << 0x1336 + -0x12bc + -0x6c | _0x2a0c94 >>> 0x119 * -0x1d + -0x3 * 0xc41 + 0x44aa * 0x1) + _0x39eb64 << 0xe * -0x29c + 0x4ea + 0x1f9e) ^ _0x39eb64)) + _0x128d32[0x985 + -0x1177 + 0x1 * 0x7fe] - (-0x3d273af + -0x1 * -0x72611590 + 0x4471195)) << 0x112 * 0x15 + -0xa30 + -0x412 * 0x3 | _0x3952af >>> 0x1 * 0xe74 + 0x6 * 0x1f7 + -0x1a32) + _0x2a0c94 << 0xf1 + -0xe43 * -0x2 + -0x1d77 * 0x1,\n                            _0x3952af = ((_0x3952af += ((_0x113678 = (_0x39eb64 = ((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0x87 * -0x1 + -0x1 * -0x1626 + -0x16a8] - (-0x3ca72 + -0xac995 + 0x145ac5)) << -0x1231 + -0x1 * -0xb05 + 0x730 | _0x227f23 >>> 0x20dd * 0x1 + -0x16b8 + -0xa09) + _0x3952af << 0x1 * 0xe63 + 0xa34 * -0x2 + 0x605)) + _0x128d32[-0x9a * -0x23 + 0x25fd + -0x3b03] - (0xb06c444e + 0x2d68c * 0x1574 + 0x9 * -0xcf8fe07)) << 0x1f60 * -0x1 + -0x1fc2 + -0x1 * -0x3f2d | _0x39eb64 >>> 0x1c0e + 0x7c * -0x3b + 0x9b * 0x1) + _0x227f23 << -0x1 * 0x7db + 0x143d * 0x1 + -0x2 * 0x631) ^ _0x227f23) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x1315 + 0x22f5 + -0x35ff] + (0x1 * -0xc1ee2861 + 0x5f64a13c + 0xd026e847)) << 0x10b * 0x15 + 0x9e2 + -0x1fb9 | _0x2a0c94 >>> 0x213e + -0x11 * -0x93 + -0x1 * 0x2af1) + _0x39eb64 << -0x4 * 0x7c8 + 0x1 * 0x33d + 0x1be3)) + _0x128d32[0x18c5 * 0x1 + 0x94d * -0x3 + 0x2 * 0x198] - (0xbbbcc3 + 0x1509 * -0x2a32 + 0x4d6a0f3)) << 0x12b5 * 0x1 + -0xc * 0xa2 + -0xb06 | _0x3952af >>> -0x596 * 0x5 + 0x2 * -0x655 + 0x28a1) + _0x2a0c94 << 0x5f * -0x36 + 0x2b1 * 0x4 + 0x946,\n                            _0x3952af = ((_0x3952af += ((_0x113678 = (_0x39eb64 = ((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0xaa9 + 0x6 * 0x54e + 0x7e * -0x2b] - (-0x1309d * -0x67b3 + -0x8e97ecd6 + 0x6e74d9cb)) << -0x1 * 0x1169 + -0x1c3f + 0x2dac | _0x227f23 >>> -0x12f * 0x1d + 0x178 + 0x20f7) + _0x3952af << -0x1554 + 0x2 * -0x136e + 0x9 * 0x6b0)) + _0x128d32[0x8bd * 0x4 + 0x993 + -0x2c83] + (-0x1ec1ce29 + 0x12d9d323 + 0x57c6caaf)) << 0x2f9 * 0x1 + 0x1a55 + -0x1d43 | _0x39eb64 >>> -0xdf6 + 0x94 * 0x2 + 0xce3) + _0x227f23 << -0xd5 + -0x197e + 0x1a53) ^ _0x227f23) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x697 * -0x1 + -0x617 + 0xcb5] - (0x2 * -0x11de459 + 0xaabba88 + 0xd4c2ca)) << -0x1198 * 0x1 + -0x42c * 0x3 + 0x2 * 0xf16 | _0x2a0c94 >>> 0x28e * 0x2 + 0x1547 + -0x125 * 0x17) + _0x39eb64 << 0x45 * 0x21 + -0x14 * -0x7 + 0x971 * -0x1)) + _0x128d32[-0x1 * -0x118b + 0x1f4 + -0x1375] - (0x2 * -0x34ed62bd + -0x6d39a445 + -0x11854ad4f * -0x1)) << -0x27f * -0x1 + -0x4 * 0x31a + 0xa00 | _0x3952af >>> -0x319 + -0x1 * -0x247d + -0x215b * 0x1) + _0x2a0c94 << -0x1bc7 * 0x1 + 0x1 * -0x4f7 + 0x20be,\n                            _0x3952af = ((_0x3952af += ((_0x113678 = (_0x39eb64 = ((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0x1 * -0x1eb5 + -0x1ba5 + -0x3 * 0x101] + (0x338d6ddd + 0x1 * 0x3db4c799 + -0x48a6b6b0)) << 0x126a + 0x1 * 0x407 + -0x166d * 0x1 | _0x227f23 >>> -0x1f97 + -0x2566 * -0x1 + 0x5b3 * -0x1) + _0x3952af << 0x2175 + 0x2187 * 0x1 + -0x42fc)) + _0x128d32[0x1701 + 0x1fb6 + 0x36b7 * -0x1] - (0x1e38ad99 + -0x3 * -0x1727b1c + -0xd3146e7)) << 0x15 * -0x18d + -0x4 * -0x75e + 0x324 | _0x39eb64 >>> -0x7f8 + 0x1 * 0xc1 + 0x74c) + _0x227f23 << -0x86 * 0x27 + -0x1 * 0x1a93 + -0x17 * -0x20b) ^ _0x227f23) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x1 * -0x1c6f + -0x10f0 + -0x4a * -0x9d] - (-0x353a5 * 0xce7 + 0x510a05c * 0xe + 0xf144056)) << 0x2c * -0x8f + -0x20 * -0x11b + 0x2af * -0x4 | _0x2a0c94 >>> -0x167c * -0x1 + 0x1bef * -0x1 + 0x583) + _0x39eb64 << -0x3 * 0x3b + 0x1555 + 0xa52 * -0x2)) + _0x128d32[0x35 * -0x27 + -0x1 * 0xdb8 + -0x1 * -0x15d1] + (0x2e39f97 * 0x1 + -0x1 * 0x58f09b4 + 0x7338722)) << 0x1d3 * -0x6 + 0x1 * 0x171b + 0x406 * -0x3 | _0x3952af >>> 0x3c1 + -0x1cbf + 0x1907) + _0x2a0c94 << 0x1b73 + 0x1d44 + 0x38b7 * -0x1,\n                            _0x3952af = ((_0x3952af += ((_0x113678 = (_0x39eb64 = ((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[0x30b * 0x2 + 0xa52 + -0x105f] - (0x131 * 0x25e655 + -0xe61e * 0x48b + 0xe5c * -0x33bb)) << 0x17a1 + -0x26 * 0x3f + 0x3 * -0x4c1 | _0x227f23 >>> 0x1079 + -0x13 * 0xf5 + 0x1d2) + _0x3952af << -0xf27 + -0x1 * -0x21d1 + 0x955 * -0x2)) + _0x128d32[0x20e * -0x3 + -0x4a7 * 0x8 + 0x2b6e] - (0x1 * 0x79f0ea3 + -0x184cea1d + -0x11d * -0x2590d9)) << 0x12e3 + 0x12b * -0x2 + -0x1082 | _0x39eb64 >>> -0x485 * 0x2 + -0x61 * 0x1a + 0x12f9) + _0x227f23 << 0x1 * -0x34c + -0x6 * 0x4dc + -0x1 * -0x2074) ^ _0x227f23) ^ (_0x2a0c94 = ((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[-0x3e3 + 0x22d * -0x2 + 0x84c] + (-0xdb8446c + -0x1 * -0x5cb3a83 + 0x278f86e1)) << -0x7 * -0x3f1 + 0x17f * 0x7 + -0x2600 | _0x2a0c94 >>> -0x47e + 0xce * 0x2 + 0x2 * 0x179) + _0x39eb64 << 0x1 * 0x9fe + 0x1 * 0x17f5 + -0x21f3)) + _0x128d32[-0x18 * -0x18e + -0x1dff + -0x74f * 0x1] - (0x12fee507 + -0x1 * 0x6a5c4769 + -0x1 * -0x92b10bfd)) << 0x5 * -0x52a + -0x1e75 + 0xde * 0x41 | _0x3952af >>> 0x116b + -0x1 * 0x9ed + 0x53 * -0x17) + _0x2a0c94 << 0x264e * -0x1 + -0x11fd + 0x384b,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[-0x1524 + 0x65 * 0x5b + 0x1 * -0xec3] - (0x63c0c3 * 0x1f + 0x11a61fd * -0xc + -0xcff1dfb * -0x1)) << 0x36c + -0x4eb * 0x5 + 0x1531 | _0x227f23 >>> -0x941 * -0x2 + -0x1b * -0x9b + -0x22c1) + _0x3952af << 0x1862 + -0x1359 + -0x509) | ~_0x2a0c94)) + _0x128d32[-0x26d + -0x6 * 0xbd + 0x6e2] + (-0x690c7 * 0xd6d + 0x2c437c8e * 0x1 + -0x3786a162 * -0x2)) << 0x54a + -0x1bd3 + 0x1693 | _0x39eb64 >>> 0x1076 + 0xa0d + -0x1a6d) + _0x227f23 << -0x1d37 + 0x1 * 0x14fb + 0x83c) ^ ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[0x190f * -0x1 + -0x1503 + 0x2e20] - (0x12aa3 * 0x80ad + 0x5 * 0x123e2fa3 + -0x9ce661fd)) << -0x204a + -0x22cf + 0x4328 | _0x2a0c94 >>> 0x1 * 0xcac + -0x1bbf * -0x1 + -0x142d * 0x2) + _0x39eb64 << -0x11b4 + 0x10b1 * 0x1 + -0x25 * -0x7) | ~_0x227f23)) + _0x128d32[0x1 * -0x10d + 0x5f4 + -0x19 * 0x32] - (0x2181582 + -0x55ca10e + 0x6b0eb53)) << -0xd3d * 0x1 + -0x1dd7 + -0x1 * -0x2b29 | _0x3952af >>> 0x676 + 0xa84 * 0x1 + -0x10ef) + _0x2a0c94 << -0x2 * 0xc83 + 0x15 * -0x10c + -0x1781 * -0x2,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[0x2 * -0x527 + 0x246c + -0x8e * 0x2f] + (0x62359ef1 + 0xc3bd213a + -0xc0976668)) << -0x22fa * 0x1 + 0x2af + 0x2051 | _0x227f23 >>> -0x92b + -0x4b4 * 0x1 + 0xdf9) + _0x3952af << 0x494 + -0x1902 + -0x1 * -0x146e) | ~_0x2a0c94)) + _0x128d32[0x1d8 * 0x1 + 0x1 * -0x5ce + 0x3f9] - (-0x324 * -0x49722 + 0xde * 0x31ad3b + -0x1bba29be * -0x2)) << 0x941 + -0x1651 + -0x4e * -0x2b | _0x39eb64 >>> 0x2 * -0xc2 + -0x112a + 0x12c4) + _0x227f23 << 0x1369 + -0x1261 + -0x3 * 0x58) ^ ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[0x10c5 + 0x78f + 0x1 * -0x184a] - (-0x3b62a * 0x6 + 0x15245b + 0x89612 * 0x2)) << 0x252f + -0x5 * -0x661 + -0x4505 | _0x2a0c94 >>> 0x251e + 0x6 * 0x2b7 + -0x3557 * 0x1) + _0x39eb64 << -0x1 * -0xa79 + -0x8d * -0x33 + -0x2690) | ~_0x227f23)) + _0x128d32[0x395 * 0x8 + -0x24a9 + -0x52 * -0x19] - (-0xc3191853 + -0x57fdcd8 * 0x29 + -0x141d00ee * -0x1b)) << 0x132b * -0x1 + -0x13 * -0x15 + 0x11b1 | _0x3952af >>> -0x175f + 0x16 * 0xc2 + -0x2 * -0x35f) + _0x2a0c94 << -0xc * -0x2de + -0x1 * -0x261a + 0x1 * -0x4882,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[0x4 * -0x527 + -0xb71 + 0x2015 * 0x1] + (0x2 * -0x2405587c + 0x963dc885 * 0x1 + 0x217566c2)) << 0x14cb + -0x647 * -0x1 + -0x1b0c | _0x227f23 >>> -0xbd * 0x30 + -0x13 * 0x14f + 0x7 * 0x8a1) + _0x3952af << -0xd * 0x215 + 0xcc + 0x1a45) | ~_0x2a0c94)) + _0x128d32[-0x638 * 0x6 + -0x25fa + 0x4b59] - (0xab1cd2 + -0x184b1f6 + 0x2acae44)) << -0x177b + -0x500 + 0x1c85 | _0x39eb64 >>> -0x1e73 + -0x3 * 0x1f1 + -0x2 * -0x122e) + _0x227f23 << 0xb5 * -0x3 + 0x158f + -0x4 * 0x4dc) ^ ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[-0xe39 + 0x452 + 0x9ed] - (0x5a22d2a4 + 0x3a146128 + 0x154a34 * -0x298)) << 0x1 * -0x1fd0 + 0x1837 * 0x1 + 0x7a8 | _0x2a0c94 >>> 0x1212 + 0x2 * -0xc47 + 0x68d) + _0x39eb64 << -0x20ba + 0xbb2 + -0x8 * -0x2a1) | ~_0x227f23)) + _0x128d32[0x283 * 0x8 + -0x5f * 0x37 + 0x5e] + (-0x15db9faa + 0x3841d * -0x1db3 + 0xcc505a92)) << -0x172f + -0x5f * -0x1 + 0x16e5 | _0x3952af >>> 0x6c + 0x2 * 0x530 + 0xac1 * -0x1) + _0x2a0c94 << 0x3 * 0x312 + 0x19 * -0x107 + 0x1079,\n                            _0x3952af = ((_0x3952af += ((_0x39eb64 = ((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[-0x5bc + -0x1 * -0x887 + -0x1 * 0x2c7] - (0xd0d1959 + 0x9a4d1b1 + -0xe05698c)) << 0x3 * 0x6a7 + 0x252e + -0x391d | _0x227f23 >>> -0x2292 + -0x1385 + 0x1 * 0x3631) + _0x3952af << -0x2483 * -0x1 + 0x93e + 0xd * -0x385) | ~_0x2a0c94)) + _0x128d32[-0x1fd2 + 0x1bb0 + -0x1 * -0x42d] - (-0x9b7 * 0xd9fae + -0x9fdcf8b * -0x7 + 0xb3bb54 * 0xb8)) << 0x1f * 0xec + -0x260 + -0x18a * 0x11 | _0x39eb64 >>> 0x140 * -0x6 + 0x2231 * -0x1 + 0x29c7) + _0x227f23 << 0x26ef * -0x1 + -0x112b + 0x2b * 0x14e) ^ ((_0x2a0c94 = ((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[-0x1 * -0x100d + 0xdc0 + -0x1d * 0x107] + (0x43dc7475 + 0x524cbd91 + -0x82661 * 0xd2b)) << -0x1f * -0xf + -0x1d3a + -0x1 * -0x1b78 | _0x2a0c94 >>> 0x235b + 0x162b + -0x3975) + _0x39eb64 << -0xf * -0x27b + -0xc58 + -0x18dd) | ~_0x227f23)) + _0x128d32[-0x72 * -0x1f + 0xac4 + -0x1889] - (0xa * -0x3c812a2 + -0x2c * 0x1bc4a2 + -0x3 * -0x15053b89)) << 0x4 * 0x9c2 + -0xd46 * 0x2 + -0xc67 | _0x3952af >>> -0x8b9 + -0x1ed3 * 0x1 + -0x1 * -0x2797) + _0x2a0c94 << -0x1 * -0xede + 0x15d3 + -0x1f * 0x12f,\n                            this['first'] ? (this['h0'] = _0x227f23 + (-0x295123b + 0xc62a6020 * 0x1 + -0x22 * 0x2b71052) << -0x2 * -0x602 + -0x1 * 0x12c2 + 0x6be,\n                                this['h1'] = _0x3952af - (0x3a5b52c + 0x1d978e61 + 0x7 * -0x26f46ba) << 0x5ea * 0x4 + 0xe5 + -0x4e9 * 0x5,\n                                this['h2'] = _0x2a0c94 - (0xa6be44c7 + 0xc54d85a4 + -0x104c6a769) << 0x6d * 0x53 + 0x1809 + -0x3b60,\n                                this['h3'] = _0x39eb64 + (-0x1fdbc0b + 0x1 * 0x1a1047ff + 0x85f6 * -0xf0d) << 0x26e8 + -0x5d * 0x1f + 0x151 * -0x15,\n                                this[_0x2f0149(0x19f)] = !(0x25a2 + -0x5 * 0x1d5 + -0x38f * 0x8)) : (this['h0'] = this['h0'] + _0x227f23 << 0x923 + 0xb1c + -0x143f,\n                                this['h1'] = this['h1'] + _0x3952af << -0x23 * 0xc0 + 0x1aef + -0xaf,\n                                this['h2'] = this['h2'] + _0x2a0c94 << -0x1b53 + -0x1acc + -0xa3 * -0x55,\n                                this['h3'] = this['h3'] + _0x39eb64 << -0xba0 * 0x1 + 0x146 + 0xa * 0x109);\n                    }\n                    ,\n                    _0x22f902[_0x2db296(0x344)]['hex'] = function () {\n                        this['finalize']();\n                        var _0x58d18c = this['h0']\n                            , _0x4e2807 = this['h1']\n                            , _0x41534b = this['h2']\n                            , _0x136921 = this['h3'];\n                        return _0x142491[_0x58d18c >> 0x3cb * -0x4 + -0x6e * -0x3 + 0xde6 & 0x3b * 0x47 + 0x1567 + -0x25b5] + _0x142491[-0x1731 + -0x16e + 0x9 * 0x2be & _0x58d18c] + _0x142491[_0x58d18c >> -0xa78 + 0x18d4 + 0xe5 * -0x10 & 0x81e + -0x6 * 0x529 + 0x16e7] + _0x142491[_0x58d18c >> 0x1894 + -0x3c + -0x1850 & -0x2228 * -0x1 + 0x3 * 0x4ff + -0x3116] + _0x142491[_0x58d18c >> -0x67 * -0x1 + -0x1842 + 0x17ef & 0x580 * -0x6 + 0x1b * 0x171 + -0x5dc] + _0x142491[_0x58d18c >> -0x1 * -0x709 + 0x1594 + -0x1 * 0x1c8d & 0x1633 + -0x70d + -0xf17] + _0x142491[_0x58d18c >> -0xaf6 + 0x1ddb * 0x1 + -0x12c9 & -0x4b * 0x7b + 0x5 * 0x41b + 0xf91] + _0x142491[_0x58d18c >> -0x1 * 0x1543 + -0x1795 * -0x1 + -0x23a & -0x1e70 + 0xcc5 + -0x11ba * -0x1] + _0x142491[_0x4e2807 >> 0x651 + -0x10f7 * -0x2 + -0x283b & 0x1199 + -0x47 * -0x59 + -0x2a39] + _0x142491[0xe3 * -0x22 + 0x2479 + 0x644 * -0x1 & _0x4e2807] + _0x142491[_0x4e2807 >> 0x121a + 0x1a84 + -0x2c92 & -0x65 * -0x4a + -0x5db + -0x1748] + _0x142491[_0x4e2807 >> 0x14a3 + -0x11 * 0x55 + -0x5 * 0x2fe & -0x24e3 * -0x1 + 0xf64 + -0x3438] + _0x142491[_0x4e2807 >> 0x1cf + -0x1c89 + -0x2 * -0xd67 & -0xd47 * -0x2 + -0x1 * 0x221b + 0x1e7 * 0x4] + _0x142491[_0x4e2807 >> 0x673 + 0x1d12 + -0x1 * 0x2375 & 0x12ce + -0x8 * -0xb5 + -0x1867] + _0x142491[_0x4e2807 >> 0x1 * 0x1499 + 0x1a6b * 0x1 + -0x98 * 0x4f & 0x1516 + -0x147 * -0x2 + -0x1795 * 0x1] + _0x142491[_0x4e2807 >> 0x4 * 0x570 + -0x2 * 0x622 + -0x2 * 0x4b2 & -0x6 * -0x15d + -0x7eb + -0x34] + _0x142491[_0x41534b >> 0x1738 + -0x6 * 0x23b + -0x3 * 0x346 & -0x97 * -0x3a + 0x3a6 + -0x25cd] + _0x142491[-0x48 * -0x11 + 0x1 * -0x2502 + 0x13 * 0x1b3 & _0x41534b] + _0x142491[_0x41534b >> -0x1 * -0x1556 + 0x3 * 0x623 + -0x27b3 * 0x1 & -0x6b * 0x1f + 0x1 * -0x49 + -0x3 * -0x46f] + _0x142491[_0x41534b >> -0x794 + -0x1 * 0x2443 + 0x2bdf & 0x26ca + -0xb02 + 0x2f * -0x97] + _0x142491[_0x41534b >> 0x177f + -0x57b + -0x11f * 0x10 & 0x1eed + 0xbb2 + -0x2a90] + _0x142491[_0x41534b >> 0xab7 * -0x2 + 0x3ba + 0x11c4 & -0x1621 + 0xa3f * 0x2 + -0xd9 * -0x2] + _0x142491[_0x41534b >> 0x607 + -0x2065 + 0x1a7a & 0x2 * -0xb0f + 0x629 * -0x5 + 0x1a7d * 0x2] + _0x142491[_0x41534b >> -0x2205 + 0x20ac + 0x171 & -0x1 * -0x1337 + 0x6e * -0x1 + -0x22 * 0x8d] + _0x142491[_0x136921 >> -0x845 + -0x1 * 0x267b + 0x1762 * 0x2 & 0x340 + -0x21 * 0xcb + 0x16fa] + _0x142491[0x4 * -0x8e2 + -0xdea + 0x3181 & _0x136921] + _0x142491[_0x136921 >> 0x1784 + 0xa * 0x31b + -0x1 * 0x3686 & -0x26 * 0x4f + -0x1 * -0xca8 + 0xdf * -0x1] + _0x142491[_0x136921 >> 0x1823 * -0x1 + 0xe5c * -0x2 + 0x1 * 0x34e3 & 0x34e * 0x6 + 0x47f + -0x1844 * 0x1] + _0x142491[_0x136921 >> 0x1 * -0x10af + 0x39a + 0xd29 & -0xea2 + 0x2 * -0xad2 + 0x2455] + _0x142491[_0x136921 >> 0xadf + 0x2db * -0x7 + 0x92e & -0x493 * 0x3 + 0x15e1 + -0x819] + _0x142491[_0x136921 >> -0x22d6 + 0x20 * -0x17 + 0x25d2 & -0x17 * 0x83 + 0x1214 + -0x640] + _0x142491[_0x136921 >> -0x96e + -0x1e99 + 0x281f & -0x18c8 + 0x33 * 0x89 + -0x274];\n                    }\n                    ,\n                    _0x22f902['prototype'][_0x2db296(0x3ae)] = _0x22f902[_0x2db296(0x344)]['hex'],\n                    _0x22f902[_0x2db296(0x344)]['digest'] = function () {\n                        var _0x5a0a9e = _0x2db296;\n                        this[_0x5a0a9e(0x1d9)]();\n                        var _0x2a8796 = this['h0']\n                            , _0x2d7c31 = this['h1']\n                            , _0x1378d3 = this['h2']\n                            , _0x2e667f = this['h3'];\n                        return [0x1 * 0x4bd + 0x1f15 + 0x5 * -0x6f7 & _0x2a8796, _0x2a8796 >> 0xbcd + -0x25f7 + 0x1a32 & 0x1507 + -0x177d + 0x1 * 0x375, _0x2a8796 >> -0x141c + 0x1ae2 + -0x6b6 & 0x132a + -0x3 * 0x423 + 0xb * -0x86, _0x2a8796 >> -0x1 * -0x261f + 0x115 * -0xc + -0x190b & 0x1233 * -0x1 + 0xacf * -0x3 + 0x339f, -0x16a0 + 0x1002 + 0x79d * 0x1 & _0x2d7c31, _0x2d7c31 >> -0x2 * 0xff4 + -0x541 * 0x2 + -0xe26 * -0x3 & 0x54e + -0x1c * -0x148 + -0x282f * 0x1, _0x2d7c31 >> -0x4 * -0x83f + 0x20ab * -0x1 + -0x41 & 0x427 * 0x5 + 0xdd1 + -0x2195 * 0x1, _0x2d7c31 >> 0xf * -0x201 + 0x1c26 + -0x9 * -0x39 & 0x7 * -0x235 + 0x1be + 0xeb4 * 0x1, 0x34 * 0x9b + 0xa36 + -0x28b3 & _0x1378d3, _0x1378d3 >> 0x463 * 0x1 + -0x1f0d + 0x1ab2 & 0x13 * -0x17f + -0x536 + 0x22a2, _0x1378d3 >> 0x4a7 + -0x1a4 + -0x2f3 & 0x1066 + 0xb3d + -0x1aa4, _0x1378d3 >> -0xc00 + -0x2 * 0xfcb + 0x2bae & 0x11a7 * -0x1 + 0x3a1 * -0x1 + 0x1647, -0xa38 + -0x1304 + 0x1e3b & _0x2e667f, _0x2e667f >> 0x1102 + 0x1896 + -0x2f8 * 0xe & -0x15b2 * -0x1 + -0xa6 * 0x31 + -0xf * -0xbd, _0x2e667f >> 0x25a2 + -0x4 * 0x103 + -0x2186 & -0xa83 * -0x3 + -0x15f1 + -0x899, _0x2e667f >> 0xb95 * 0x3 + -0x1a34 + -0x873 & 0xfb6 * -0x2 + 0x3b * 0x3a + 0x130d];\n                    }\n                    ,\n                    _0x22f902[_0x2db296(0x344)][_0x2db296(0x238)] = _0x22f902['prototype'][_0x2db296(0x19b)],\n                    _0x22f902['prototype'][_0x2db296(0x249)] = function () {\n                        var _0x45ab2e = _0x2db296;\n                        this[_0x45ab2e(0x1d9)]();\n                        var _0x31d586 = new ArrayBuffer(0x13 * -0x20e + -0x4 * -0x62f + 0xe5e)\n                            , _0x2d9fbd = new Uint32Array(_0x31d586);\n                        return _0x2d9fbd[-0xbcc + -0xf5 * -0x3 + -0x5 * -0x1c9] = this['h0'],\n                            _0x2d9fbd[0x5 * 0x103 + 0x26ee + -0x2bfc] = this['h1'],\n                            _0x2d9fbd[0x7d + -0x1b05 * -0x1 + -0x1b80] = this['h2'],\n                            _0x2d9fbd[0x1 * 0x1c1c + 0x1 * 0x4eb + -0x2104] = this['h3'],\n                            _0x31d586;\n                    }\n                    ,\n                    _0x22f902['prototype']['buffer'] = _0x22f902[_0x2db296(0x344)][_0x2db296(0x249)],\n                    _0x22f902[_0x2db296(0x344)][_0x2db296(0x25f)] = function () {\n                        var _0x16e12f = _0x2db296;\n                        for (var _0x1dad5c, _0x24f20d, _0x70d99b, _0xb48dfc = '', _0x13e0cb = this[_0x16e12f(0x238)](), _0x12e65e = -0x719 * -0x5 + -0x747 * -0x5 + 0x170 * -0x32; _0x12e65e < -0x8c + 0x164f + -0x15b4;)\n                            _0x1dad5c = _0x13e0cb[_0x12e65e++],\n                                _0x24f20d = _0x13e0cb[_0x12e65e++],\n                                _0x70d99b = _0x13e0cb[_0x12e65e++],\n                                _0xb48dfc += _0xcb4d61[_0x1dad5c >>> 0x13b + 0x209 * -0xb + 0x152a] + _0xcb4d61[0x13d3 + 0x4c7 + -0x185b & (_0x1dad5c << 0x1334 + 0x1dd7 + 0x7 * -0x701 | _0x24f20d >>> -0x3b3 * 0xa + -0x17b * -0x13 + -0x1 * -0x8e1)] + _0xcb4d61[-0x25dd + 0x14bd + 0x115f & (_0x24f20d << -0x787 + 0x888 + -0xff | _0x70d99b >>> 0xe74 + -0x104f + 0xd * 0x25)] + _0xcb4d61[0x68e + -0x1082 + -0x175 * -0x7 & _0x70d99b];\n                        return _0x1dad5c = _0x13e0cb[_0x12e65e],\n                            _0xb48dfc += _0xcb4d61[_0x1dad5c >>> 0x2b * -0x77 + 0x29e * 0x2 + 0xec3] + _0xcb4d61[_0x1dad5c << -0x14c0 + -0x2 * -0x11a4 + 0x2 * -0x742 & 0xe5f + -0x1dab + 0xf8b * 0x1] + '==';\n                    }\n                ;\n                var _0x336469 = _0x1edabb();\n                _0x299a21 ? _0xb9c7d1[_0x2db296(0x1b8)] = _0x336469 : (_0x11d177[_0x2db296(0x35c)] = _0x336469,\n                _0x5efc8f && (void (0x1118 + -0x25 * 0x98 + 0x1a0 * 0x3))(function () {\n                    return _0x336469;\n                }));\n            }());\n        });\n\n        function _0x5dd467(_0x2e8eb5) {\n            var _0x344c50 = _0x5612de;\n            return w_0x5c3140(_0x344c50(0x333), {\n                get 0x0() {\n                    return _0x90795;\n                },\n                0x1: arguments,\n                0x2: _0x2e8eb5\n            }, this);\n        }\n\n        function _0x176a57() {\n            var _0x33742c = _0x5612de;\n            return !!document[_0x33742c(0x373)];\n        }\n\n        function _0x1230e7() {\n            return 'undefined' != typeof InstallTrigger;\n        }\n\n        function _0xf8ccf1() {\n            var _0x25d57d = _0x5612de;\n            return /constructor/i[_0x25d57d(0x22b)](window['HTMLElement']) || _0x25d57d(0x226) === (!window['safari'] || _0x25d57d(0x384) != typeof safari && safari['pushNotification'])[_0x25d57d(0x3ae)]();\n        }\n\n        function _0x30c916() {\n            var _0x56f7c2 = _0x5612de;\n            return new Date()[_0x56f7c2(0x16d)]();\n        }\n\n        function _0x5af46a(_0xeaff35) {\n            return null == _0xeaff35 ? '' : 'boolean' == typeof _0xeaff35 ? _0xeaff35 ? '1' : '0' : _0xeaff35;\n        }\n\n        function _0x325f58(_0x3fdcb7, _0x2838bc) {\n            var _0x17d12c = _0x5612de;\n            _0x2838bc || (_0x2838bc = _0x17d12c(0x24c));\n            for (var _0x3b8f2c = '', _0x98f0de = _0x3fdcb7; _0x98f0de > -0x2 * -0x90e + 0x4 * -0x3ae + -0x364; --_0x98f0de)\n                _0x3b8f2c += _0x2838bc[Math[_0x17d12c(0x1cf)](Math['random']() * _0x2838bc[_0x17d12c(0x259)])];\n            return _0x3b8f2c;\n        }\n\n        var _0x39693d = {\n            'sec': 0x9,\n            'asgw': 0x5,\n            'init': 0x0\n        }\n            , _0x6caf = {\n            'bogusIndex': 0x0,\n            'msNewTokenList': [],\n            'moveList': [],\n            'clickList': [],\n            'keyboardList': [],\n            'activeState': [],\n            'aidList': []\n        };\n\n        function _0x53b77d(_0x357347) {\n            return w_0x5c3140('484e4f4a403f5243001714366d6da13c00000025f8c25369000000ee00110307070002161103021200031103070700021303062b2f11030207000335490700044211010044001400011101014a1200001100010700010d05000000003c000e00054303491101034a12000607000711000143024911010433000611010412000833000911010412000812000947002100110107070002161101021200031101070700021303062b2f110102070003354902110105430047004f11010433002511010412000a11010412000b190400962934001111010412000c11010412000d190400962947002100110107070002161101021200031101070700021303062b2f11010207000335490842000e0e7170737c7b7045677a657067616c027c7108717077607272706707707b63767a71700003727061047c7b737a02307607767a7b667a797007737c67707760720a7a60617067427c71617d0a7c7b7b7067427c71617d0b7a606170675d707c727d610b7c7b7b70675d707c727d61', {\n                get 0x0() {\n                    return Image;\n                },\n                0x1: Object,\n                get 0x2() {\n                    return _0x6caf;\n                },\n                get 0x3() {\n                    return console;\n                },\n                get 0x4() {\n                    return window;\n                },\n                get 0x5() {\n                    return _0x1230e7;\n                },\n                0x6: arguments,\n                0x7: _0x357347\n            }, this);\n        }\n\n        function _0x3ed707() {\n            var _0x2077c7 = _0x5612de;\n            return w_0x5c3140(_0x2077c7(0x31d), {\n                get 0x0() {\n                    return navigator;\n                },\n                get 0x1() {\n                    var _0x573a52 = _0x2077c7;\n                    return _0x573a52(0x384) != typeof global ? global : void (-0x11 * -0x1cf + 0x95 * 0x16 + -0x1 * 0x2b8d);\n                },\n                0x2: Object,\n                get 0x3() {\n                    var _0x4b9092 = _0x2077c7;\n                    return _0x4b9092(0x384) != typeof process ? process : void (-0x65 * 0x2 + 0x2579 * 0x1 + -0x1 * 0x24af);\n                },\n                get 0x4() {\n                    return _0x1db123;\n                },\n                0x5: arguments\n            }, this);\n        }\n\n        function _0x328bde(_0xacb410, _0x4ed7bd, _0x49d137) {\n            var _0x197e65 = _0x5612de\n                , _0x2d8b28 = _0x197e65(0x2ce)\n                , _0x4dd4b8 = '=';\n            _0x49d137 && (_0x4dd4b8 = ''),\n            _0x4ed7bd && (_0x2d8b28 = _0x4ed7bd);\n            for (var _0x1aa067, _0x3b8c55 = '', _0x2d1a36 = 0xe0f * 0x2 + -0x35b * -0x8 + 0x29e * -0x15; _0xacb410[_0x197e65(0x259)] >= _0x2d1a36 + (0x73 * -0x26 + -0xb4e + 0x1c63);)\n                _0x1aa067 = (-0x1cb9 + 0x2c6 + -0x1 * -0x1af2 & _0xacb410[_0x197e65(0x195)](_0x2d1a36++)) << 0x1de9 + 0x1c + -0x1 * 0x1df5 | (-0x1 * 0xd91 + -0x23a + 0x10ca & _0xacb410[_0x197e65(0x195)](_0x2d1a36++)) << -0x16 * 0x135 + 0x9e2 * 0x3 + -0x188 * 0x2 | -0x752 + -0x2 * 0xaf3 + 0x1e37 & _0xacb410[_0x197e65(0x195)](_0x2d1a36++),\n                    _0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)]((0x1c78125 + -0x1df1122 + -0xb * -0x190d17 & _0x1aa067) >> 0x59 * 0x4f + -0x1176 + -0x1 * 0x9ef),\n                    _0x3b8c55 += _0x2d8b28['charAt']((-0x1 * 0x13b6b + -0x13 * -0x65aa + -0x26033 & _0x1aa067) >> 0x17ea * -0x1 + 0xef7 + 0x8ff),\n                    _0x3b8c55 += _0x2d8b28['charAt']((-0x1 * 0x16bd + 0x115 + 0x10a * 0x24 & _0x1aa067) >> 0x29c * -0x1 + -0x1 * 0x1475 + 0x1717),\n                    _0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)](-0xc * 0x196 + 0x1fae + -0xc67 & _0x1aa067);\n            return _0xacb410[_0x197e65(0x259)] - _0x2d1a36 > -0x69f + -0x1 * 0xe5c + 0x14fb && (_0x1aa067 = (0x740 + -0x1ed1 + 0x1890 & _0xacb410['charCodeAt'](_0x2d1a36++)) << -0x7 * 0xec + 0x2167 * 0x1 + -0x1ae3 | (_0xacb410['length'] > _0x2d1a36 ? (0x16aa + -0x762 * 0x1 + -0xe49 & _0xacb410[_0x197e65(0x195)](_0x2d1a36)) << 0x1af7 + -0x26be + 0xbcf : 0x1 * -0x649 + -0x1 * 0xe16 + 0x2e9 * 0x7),\n                _0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)]((-0x1 * 0x484e9 + -0x13c88 * -0x4a + -0x28bd * -0x40d & _0x1aa067) >> 0x6c * -0x4a + -0x81c * -0x2 + 0xf12),\n                _0x3b8c55 += _0x2d8b28['charAt']((-0x1ad98 + 0x1a5c8 + 0x3f7d0 & _0x1aa067) >> 0x1f95 + -0x1c06 + -0x383),\n                _0x3b8c55 += _0xacb410['length'] > _0x2d1a36 ? _0x2d8b28[_0x197e65(0x25c)]((-0x2447 + -0x1 * -0x1efe + 0x1509 & _0x1aa067) >> 0x1d66 + 0x2 * 0x202 + -0x2164) : _0x4dd4b8,\n                _0x3b8c55 += _0x4dd4b8),\n                _0x3b8c55;\n        }\n\n        function _0x389396(_0x49fdfd, _0x32eedf) {\n            var _0x36dcb8 = _0x5612de;\n            return w_0x5c3140(_0x36dcb8(0x3ad), {\n                0x0: arguments,\n                0x1: _0x49fdfd,\n                0x2: _0x32eedf\n            }, this);\n        }\n\n        function _0x3262d3(_0xb01975) {\n            var _0x55341a = _0x5612de;\n            return _0x55341a(0x315)[_0x55341a(0x2c5)](_0xb01975);\n        }\n\n        function _0xb5350b(_0x1289f5) {\n            var _0x341e09 = _0x5612de, _0x5b1849, _0x40ad1e, _0x341488, _0x5980c5, _0x31f759, _0x5bebd7 = '';\n            for (_0x5b1849 = 0x13d5 + -0xc4f * 0x1 + -0x786; _0x5b1849 < _0x1289f5[_0x341e09(0x259)] - (0xe50 * 0x1 + 0x17f3 + -0x2640); _0x5b1849 += -0xeed + 0x1 * 0x10c0 + -0x1cf * 0x1)\n                _0x40ad1e = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849)),\n                    _0x341488 = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x1103 + 0xa86 + 0x1 * -0x1b88))),\n                    _0x5980c5 = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (-0x1c54 + -0xf15 + 0x2b6b))),\n                    _0x31f759 = _0x3262d3(_0x1289f5['charAt'](_0x5b1849 + (0xd1a + 0x1 * -0x175d + -0x5 * -0x20e))),\n                    _0x5bebd7 += String[_0x341e09(0x1e2)](_0x40ad1e << 0x33 * -0x3f + 0xe73 * -0x2 + 0x2975 | _0x341488 >>> 0x12d2 + 0x851 + -0x1b1f),\n                '=' !== _0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x51 * -0x25 + -0x21d * 0x12 + 0x31c1 * 0x1)) && (_0x5bebd7 += String['fromCharCode'](_0x341488 << -0xa0c + 0xee3 + -0x4d3 & 0x1 * 0x397 + -0x113f + 0xe98 | _0x5980c5 >>> 0x2161 + 0x1b7 * -0x5 + 0xc66 * -0x2 & 0x22bb + -0xf08 + 0x6 * -0x346)),\n                '=' !== _0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x125d * 0x2 + -0x3d * -0x31 + 0x146 * -0x26)) && (_0x5bebd7 += String[_0x341e09(0x1e2)](_0x5980c5 << -0x2650 + 0x17 * 0xe9 + -0x3 * -0x5cd & 0x754 + -0x5df + -0xb5 | _0x31f759));\n            return _0x5bebd7;\n        }\n\n        _0x6caf[_0x5612de(0x380)] = -0x14e * -0x2 + 0x2519 + -0x217 * 0x13,\n            _0x6caf['msToken'] = '',\n            _0x6caf[_0x5612de(0x263)] = _0x39693d[_0x5612de(0x3b9)],\n            _0x6caf[_0x5612de(0x3b5)] = '',\n            _0x6caf['ttwid'] = '',\n            _0x6caf[_0x5612de(0x316)] = '',\n            _0x6caf[_0x5612de(0x339)] = '';\n        var _0x28d239 = 0x778 + 0xa41 + 0x1 * -0x11b9, _0x2d6b72, _0x1e9bba, _0xdc7355, _0xf08186;\n\n        function _0x33f406(_0x4b5fb5) {\n            var _0x1d1da4 = _0x5612de;\n            return _0x4b5fb5 &= -0x2632 + 0x3 * -0x591 + 0x3724,\n                String[_0x1d1da4(0x1e2)](_0x4b5fb5 + (_0x4b5fb5 < 0x22f * 0x1 + -0x1cac + 0x3 * 0x8dd ? -0xd * 0x123 + 0x19ac + -0x552 * 0x2 : _0x4b5fb5 < -0x1 * -0x1646 + 0x1 * -0x1f21 + -0x305 * -0x3 ? -0x2b4 * 0x1 + -0x45 * 0xb + -0x2 * -0x2f9 : _0x4b5fb5 < 0x1 * 0x70c + 0x123f + -0x190d * 0x1 ? -(0x1f73 + -0x1 * -0x3d7 + -0x46 * 0x81) : -(-0x248f + 0x20d3 + 0x3cd)));\n        }\n\n        function _0x4da136(_0x620f42) {\n            var _0xca40fa = _0x33f406;\n            return _0xca40fa(_0x620f42 >> 0x420 * -0x4 + -0x53f * -0x4 + -0x464) + _0xca40fa(_0x620f42 >> -0x1492 + -0x11c3 + -0x3 * -0xccd) + _0xca40fa(_0x620f42 >> 0x1479 + 0x571 * 0x6 + -0x795 * 0x7) + _0xca40fa(_0x620f42 >> -0x1d * 0x4f + 0x313 * -0xb + 0x2aca) + _0xca40fa(_0x620f42);\n        }\n\n        _0x2d6b72 = _0x1e9bba = function (_0x5d2d39) {\n            return _0x2d6b72 = _0xdc7355,\n                _0x28d239 = _0x5d2d39,\n                _0x4da136(_0x5d2d39 >> -0x418 * 0x8 + 0x9fe + 0x7c * 0x2f);\n        }\n            ,\n            _0xdc7355 = function (_0x135d9a) {\n                _0x2d6b72 = _0xf08186;\n                var _0x9cdabb = _0x28d239 << -0xa41 + -0x164f + 0x2b9 * 0xc | _0x135d9a >>> 0xee4 + 0x1 * -0x143 + 0xcd * -0x11;\n                return _0x28d239 = _0x135d9a,\n                    _0x4da136(_0x9cdabb);\n            }\n            ,\n            _0xf08186 = function (_0x36c054) {\n                return _0x2d6b72 = _0x1e9bba,\n                _0x4da136(_0x28d239 << -0x302 + 0x1 * 0x2447 + -0x7 * 0x4bd | _0x36c054 >>> -0x1f5e + 0x1aa0 + 0x3d * 0x14) + _0x33f406(_0x36c054);\n            }\n        ;\n        var _0x539097 = -0x2 * -0x621a4af5 + 0xc681287f + -0xec7e44b0, _0x12ada0;\n\n        function _0x75d5b3(_0x5a0afa, _0x1ccbbd) {\n            var _0x13780b = _0x5612de\n                , _0xc312d4 = _0x5a0afa['length']\n                , _0x102845 = _0xc312d4 << -0x3 * -0x711 + 0x9a9 * 0x2 + -0x2883;\n            if (_0x1ccbbd) {\n                var _0x25438e = _0x5a0afa[_0xc312d4 - (0x1b18 + 0x1 * 0xfb6 + -0x1 * 0x2acd)];\n                if (_0x25438e < (_0x102845 -= 0x1f * 0x62 + -0xac0 + -0x8d * 0x2) - (-0xfed + -0x8a * 0x23 + 0x22ce) || _0x25438e > _0x102845)\n                    return null;\n                _0x102845 = _0x25438e;\n            }\n            for (var _0x41e0a1 = -0x13b + -0x1963 + -0xd4f * -0x2; _0x41e0a1 < _0xc312d4; _0x41e0a1++)\n                _0x5a0afa[_0x41e0a1] = String['fromCharCode'](-0x30 * -0x12 + -0x235b + -0x15 * -0x192 & _0x5a0afa[_0x41e0a1], _0x5a0afa[_0x41e0a1] >>> -0x1839 * -0x1 + -0x5 * -0x196 + 0x1 * -0x201f & -0x2 * 0x2b3 + 0x1 * 0x19c9 + -0x1364, _0x5a0afa[_0x41e0a1] >>> -0x12b * 0x1 + 0xa54 * 0x1 + -0x11 * 0x89 & 0xc36 * 0x2 + 0x2 * 0x1259 + 0x1 * -0x3c1f, _0x5a0afa[_0x41e0a1] >>> 0x564 + 0x2325 + -0x15 * 0x1ed & 0x2673 + -0x1411 + -0x1163);\n            var _0x5ef85e = _0x5a0afa[_0x13780b(0x24f)]('');\n            return _0x1ccbbd ? _0x5ef85e['substring'](0x3 * -0x388 + -0xe41 + 0x18d9, _0x102845) : _0x5ef85e;\n        }\n\n        function _0x183951(_0x15f4d9, _0x59200b) {\n            var _0x4f373f = _0x5612de, _0x40761a, _0x6155ee = _0x15f4d9[_0x4f373f(0x259)],\n                _0x21fe82 = _0x6155ee >> 0xb8d * -0x1 + -0x1 * 0x5fe + -0x1 * -0x118d;\n            0x4 * -0xbc + 0x12f0 + -0x1000 != (-0x79 * 0x2 + -0xb1 * 0x16 + 0x102b & _0x6155ee) && ++_0x21fe82,\n                _0x59200b ? (_0x40761a = new Array(_0x21fe82 + (0x13 * -0x65 + -0x14ef + 0xfb * 0x1d)))[_0x21fe82] = _0x6155ee : _0x40761a = new Array(_0x21fe82);\n            for (var _0x56bca4 = -0x9e0 + 0x51 * 0x1a + 0x1a6; _0x56bca4 < _0x6155ee; ++_0x56bca4)\n                _0x40761a[_0x56bca4 >> -0xc1b * -0x2 + -0xc2 * -0x21 + 0x1 * -0x3136] |= _0x15f4d9['charCodeAt'](_0x56bca4) << ((0x3 * -0x4cd + -0xdfc + 0x1c66 & _0x56bca4) << 0x1 * -0x133b + 0x21a5 + 0xe67 * -0x1);\n            return _0x40761a;\n        }\n\n        function _0x25c901(_0x431b9d) {\n            return 0x1a1299587 + 0x91539 * -0x1c1b + -0x202b07 * -0x2ed & _0x431b9d;\n        }\n\n        function _0x38d33e(_0x1aed31, _0x212e8a, _0x427b15, _0x8fcd39, _0x4eaad6, _0x532b8e) {\n            return (_0x427b15 >>> -0x1 * -0x1ddb + -0x20f7 + -0x3 * -0x10b ^ _0x212e8a << -0x1 * -0x407 + -0x132e + -0xf29 * -0x1) + (_0x212e8a >>> -0x828 + -0xf23 + -0x9d * -0x26 ^ _0x427b15 << -0xd51 + 0xc9f + 0xb6) ^ (_0x1aed31 ^ _0x212e8a) + (_0x532b8e[0x9ad + -0x763 + -0xb * 0x35 & _0x8fcd39 ^ _0x4eaad6] ^ _0x427b15);\n        }\n\n        function _0x231484(_0xefe811) {\n            var _0x13eaf5 = _0x5612de;\n            return _0xefe811[_0x13eaf5(0x259)] < -0xa13 + 0x1086 + -0x66f && (_0xefe811[_0x13eaf5(0x259)] = -0x1371 + -0x1ec1 * -0x1 + 0x5a6 * -0x2),\n                _0xefe811;\n        }\n\n        function _0x3d58e7(_0x5e28f2, _0x468b52) {\n            var _0x50c100 = _0x5612de, _0x7c35df, _0x4c97b3, _0x5e0270, _0x3034db, _0x56f817, _0x3084b8,\n                _0x66df40 = _0x5e28f2[_0x50c100(0x259)], _0x5506f5 = _0x66df40 - (-0x1c76 + 0x2246 + -0x5cf);\n            for (_0x4c97b3 = _0x5e28f2[_0x5506f5],\n                     _0x5e0270 = 0x22ee + 0xa15 * -0x1 + -0x18d9 * 0x1,\n                     _0x3084b8 = 0x1 * 0x36f + -0x2707 + 0x2398 | Math[_0x50c100(0x1cf)](0xc72 * 0x2 + -0xe3 * 0x2b + 0xd43 + (0x1a + 0x1c2a + -0x1c10) / _0x66df40); _0x3084b8 > 0x1 * -0x1cd + -0x2476 + 0x2643; --_0x3084b8) {\n                for (_0x3034db = (_0x5e0270 = _0x25c901(_0x5e0270 + _0x539097)) >>> 0x3b * -0x2f + 0x1290 + 0x3 * -0x293 & 0x1533 + -0x116d + -0x3c3,\n                         _0x56f817 = 0x8 * 0x23b + -0xb89 + 0x64f * -0x1; _0x56f817 < _0x5506f5; ++_0x56f817)\n                    _0x7c35df = _0x5e28f2[_0x56f817 + (0x3b * 0x5f + -0x1e1 * 0x1 + -0x1403)],\n                        _0x4c97b3 = _0x5e28f2[_0x56f817] = _0x25c901(_0x5e28f2[_0x56f817] + _0x38d33e(_0x5e0270, _0x7c35df, _0x4c97b3, _0x56f817, _0x3034db, _0x468b52));\n                _0x7c35df = _0x5e28f2[-0x1570 + -0x1 * -0x385 + -0x8b * -0x21],\n                    _0x4c97b3 = _0x5e28f2[_0x5506f5] = _0x25c901(_0x5e28f2[_0x5506f5] + _0x38d33e(_0x5e0270, _0x7c35df, _0x4c97b3, _0x5506f5, _0x3034db, _0x468b52));\n            }\n            return _0x5e28f2;\n        }\n\n        function _0x4aaf04(_0x33a7ba, _0x386196) {\n            var _0x257c0b = _0x5612de, _0x379288, _0x247a8b, _0x334bb9, _0x2fa83f, _0x417a88,\n                _0x2a3ae5 = _0x33a7ba[_0x257c0b(0x259)], _0x429a0d = _0x2a3ae5 - (0xc1 * -0x11 + 0x1f99 + -0xb * 0x1b5);\n            for (_0x379288 = _0x33a7ba[-0x1 * -0x1397 + -0x13 * -0x187 + -0x309c],\n                     _0x334bb9 = _0x25c901(Math[_0x257c0b(0x1cf)](0xe52 * -0x1 + -0x10 * 0xb + -0x34 * -0x4a + (-0x3 * -0xd9 + 0x9f * 0x2f + 0xfc4 * -0x2) / _0x2a3ae5) * _0x539097); -0x2e * 0x1f + 0x2223 + -0x47 * 0x67 !== _0x334bb9; _0x334bb9 = _0x25c901(_0x334bb9 - _0x539097)) {\n                for (_0x2fa83f = _0x334bb9 >>> 0x437 * 0x5 + -0xfd * 0x22 + -0xc89 * -0x1 & 0x1 * 0x863 + 0x2267 * 0x1 + -0x2f * 0xe9,\n                         _0x417a88 = _0x429a0d; _0x417a88 > 0xfc7 + -0x788 * -0x1 + -0x15f * 0x11; --_0x417a88)\n                    _0x247a8b = _0x33a7ba[_0x417a88 - (0x3b * -0x4f + 0x6d * -0xa + 0xb3c * 0x2)],\n                        _0x379288 = _0x33a7ba[_0x417a88] = _0x25c901(_0x33a7ba[_0x417a88] - _0x38d33e(_0x334bb9, _0x379288, _0x247a8b, _0x417a88, _0x2fa83f, _0x386196));\n                _0x247a8b = _0x33a7ba[_0x429a0d],\n                    _0x379288 = _0x33a7ba[-0x1fb + 0x1952 * -0x1 + -0x1d * -0xf1] = _0x25c901(_0x33a7ba[0x7 * 0x59 + 0x5 * -0x2d2 + 0xbab] - _0x38d33e(_0x334bb9, _0x379288, _0x247a8b, -0xbac + -0x7 * 0xea + -0x606 * -0x3, _0x2fa83f, _0x386196));\n            }\n            return _0x33a7ba;\n        }\n\n        function _0x532596(_0x2394ed) {\n            var _0x22f5e8 = _0x5612de;\n            if (/^[\\x00-\\x7f]*$/[_0x22f5e8(0x22b)](_0x2394ed))\n                return _0x2394ed;\n            for (var _0x47e840 = [], _0x5f04b8 = _0x2394ed[_0x22f5e8(0x259)], _0x150666 = -0xe97 + 0xd02 + 0x195, _0x19b157 = 0xf1c + -0x1f5 * 0x8 + 0x8c; _0x150666 < _0x5f04b8; ++_0x150666,\n                ++_0x19b157) {\n                var _0x44de53 = _0x2394ed[_0x22f5e8(0x195)](_0x150666);\n                if (_0x44de53 < -0x1 * -0xb7b + 0x1566 + -0x2061)\n                    _0x47e840[_0x19b157] = _0x2394ed[_0x22f5e8(0x25c)](_0x150666);\n                else {\n                    if (_0x44de53 < -0x3 * 0xcd2 + 0x1168 + 0x1 * 0x1d0e)\n                        _0x47e840[_0x19b157] = String['fromCharCode'](0x2 * 0x579 + 0x263c * 0x1 + 0x306e * -0x1 | _0x44de53 >> 0xca4 * -0x1 + 0x6f * 0x13 + -0x46d * -0x1, 0x7 * -0x5 + 0x35 * 0x73 + -0x172c | 0xf88 * -0x1 + -0x108f * -0x1 + -0xc8 & _0x44de53);\n                    else {\n                        if (!(_0x44de53 < -0xaebb * 0x1 + -0x3 * -0x3a46 + 0x6f7 * 0x1f || _0x44de53 > 0x1679b * 0x1 + -0x121 * -0x15 + -0x9f51)) {\n                            if (_0x150666 + (0x15a6 + 0x1ec1 + -0x26 * 0x161) < _0x5f04b8) {\n                                var _0x254ff6 = _0x2394ed[_0x22f5e8(0x195)](_0x150666 + (-0x42 * -0x7a + 0x4 * 0x91d + -0x43e7));\n                                if (_0x44de53 < -0x181e4 + 0xbcbb + 0x1a129 && -0x17db * -0xf + 0xac6d * -0x1 + -0x3d8 * -0x9 <= _0x254ff6 && _0x254ff6 <= 0x159a + 0x17967 + 0x9b9 * -0x12) {\n                                    var _0x304310 = -0x1862f + 0x1121d + 0x2 * 0xba09 + ((0x1 * -0x140f + -0x18dd + 0x30eb & _0x44de53) << -0xb0 * -0x8 + 0x875 + -0x7 * 0x1fd | 0x2301 + 0x171f + 0x3621 * -0x1 & _0x254ff6);\n                                    _0x47e840[_0x19b157] = String[_0x22f5e8(0x1e2)](0x1afc * -0x1 + 0x26f4 + -0xb08 | _0x304310 >> 0xb * 0x14e + -0x119 * -0x1d + -0x2e1d & 0x1037 * 0x1 + -0x1090 + -0x2 * -0x4c, 0x1922 + 0x4 * 0x351 + -0x25e6 | _0x304310 >> 0x1e93 + -0x517 + -0x1970 & 0x2481 + 0x1591 + -0x39d3, -0xace * -0x1 + 0x1ef3 + -0x2941 | _0x304310 >> -0xb7f * -0x3 + -0x1 * 0xe7d + -0x13fa & -0x10d * -0x6 + 0x252a * 0x1 + -0x2b39, -0x1c61 * 0x1 + 0x1 * -0x5e7 + -0x13e * -0x1c | 0x13 * -0x1f9 + 0x16 * -0x164 + -0x37 * -0x13e & _0x304310),\n                                        ++_0x150666;\n                                    continue;\n                                }\n                            }\n                            throw new Error(_0x22f5e8(0x297));\n                        }\n                        _0x47e840[_0x19b157] = String[_0x22f5e8(0x1e2)](-0x170b + 0x109b + 0x750 | _0x44de53 >> -0xbf0 * -0x2 + 0x25bc + -0x3d90, 0x4ec + 0x1f0c + -0x8de * 0x4 | _0x44de53 >> 0x2 * 0x829 + -0x1b * -0x10c + -0x2c90 & -0x2322 + 0x19d5 + 0x34 * 0x2f, 0x2a1 + 0x1 * 0x1ac0 + 0x1 * -0x1ce1 | -0xe95 + 0x1cf * 0x11 + 0x1 * -0xfeb & _0x44de53);\n                    }\n                }\n            }\n            return _0x47e840[_0x22f5e8(0x24f)]('');\n        }\n\n        function _0x45fbef(_0x316827, _0x2a039f) {\n            var _0x1c80ac = _0x5612de;\n            for (var _0x4921e2 = new Array(_0x2a039f), _0x79a402 = 0x20bd + -0x10b1 + -0x1 * 0x100c, _0x28b895 = -0xd2c + -0x1730 + 0x1 * 0x245c, _0x2bc88b = _0x316827[_0x1c80ac(0x259)]; _0x79a402 < _0x2a039f && _0x28b895 < _0x2bc88b; _0x79a402++) {\n                var _0x43b518 = _0x316827[_0x1c80ac(0x195)](_0x28b895++);\n                switch (_0x43b518 >> -0x1342 + 0x67 * -0x53 + 0x34ab) {\n                    case -0x410 * -0x3 + -0xd9 + -0xb57:\n                    case -0x17cb + 0x2362 + -0xb96 * 0x1:\n                    case -0x24 * 0x7f + -0x1 * -0xcfc + 0x19 * 0x32:\n                    case 0x2025 + 0x1102 + -0x3124:\n                    case 0x1b0d + 0xcb4 + 0xd3f * -0x3:\n                    case -0x11d9 + 0x9 * 0x16d + -0x1 * -0x509:\n                    case 0x79 * 0x49 + 0x1 * 0x1b8e + -0x3e09 * 0x1:\n                    case 0x26c1 + -0x2137 * 0x1 + -0x583:\n                        _0x4921e2[_0x79a402] = _0x43b518;\n                        break;\n                    case 0x10f * -0x13 + 0x426 + 0x1003:\n                    case 0x164d * 0x1 + 0xb5a * 0x3 + 0x1c27 * -0x2:\n                        if (!(_0x28b895 < _0x2bc88b))\n                            throw new Error('Unfinished\\x20UTF-8\\x20octet\\x20sequence');\n                        _0x4921e2[_0x79a402] = (-0x1f7 * 0xb + -0x1fa0 + 0x2ab * 0x14 & _0x43b518) << -0x233b + 0x160e + 0xd33 | -0x1e40 + 0x22b9 + -0x2 * 0x21d & _0x316827[_0x1c80ac(0x195)](_0x28b895++);\n                        break;\n                    case -0x2512 + -0x1595 + 0x3ab5:\n                        if (!(_0x28b895 + (0xba3 * -0x1 + -0x17dd * 0x1 + 0x1 * 0x2381) < _0x2bc88b))\n                            throw new Error(_0x1c80ac(0x394));\n                        _0x4921e2[_0x79a402] = (0x247f * -0x1 + 0xec2 * 0x1 + -0x136 * -0x12 & _0x43b518) << 0x1 * 0x1bcd + -0x3dd + -0x17e4 | (0x1631 + -0x1058 + 0x2 * -0x2cd & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << 0x889 * 0x4 + 0x11c8 * 0x2 + -0x45ae | -0x698 * -0x4 + -0x2f * -0x4f + -0x28a2 & _0x316827[_0x1c80ac(0x195)](_0x28b895++);\n                        break;\n                    case -0x85 * -0x8 + 0x1148 + -0x1561:\n                        if (!(_0x28b895 + (0x1 * -0x8f1 + -0x67 * 0x3e + 0x21e5) < _0x2bc88b))\n                            throw new Error(_0x1c80ac(0x394));\n                        var _0x1740ac = ((0x1 * -0x1d4f + 0x1 * 0x24bf + -0x769 & _0x43b518) << 0xb19 + 0x4a * -0x48 + -0x3 * -0x343 | (-0x1ab4 + -0x205 * -0x8 + -0x3 * -0x399 & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << 0x1e52 + -0x144b + -0x5 * 0x1ff | (0x4c5 * -0x3 + 0x1 * -0x70b + 0x1599 & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << -0xf6e + -0x37 * -0x86 + 0x239 * -0x6 | 0x2 * -0xc31 + 0x26b5 + -0xe14 & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) - (0x1 * -0x6b6b + -0x14502 + -0x1 * -0x2b06d);\n                        if (!(0x86 * 0xd + -0x2210 + 0x1b42 <= _0x1740ac && _0x1740ac <= 0x141d1 * 0x1 + -0x3044 * -0x8b + 0x1 * -0xb76be))\n                            throw new Error(_0x1c80ac(0x24e) + _0x1740ac['toString'](-0x959 * 0x3 + -0x50e * -0x5 + -0x1 * -0x2d5));\n                        _0x4921e2[_0x79a402++] = _0x1740ac >> -0x1a89 * 0x1 + 0x125 * -0x1 + 0x1bb8 & -0x2 * 0x12e4 + 0xc1e + 0x1da9 | -0x4e * -0x332 + -0x6764 * -0x2 + -0xf004 * 0x1,\n                            _0x4921e2[_0x79a402] = 0x23f0 + 0x2b * 0x11 + -0x4 * 0x8b3 & _0x1740ac | 0xb45d + -0xd352 + 0x3 * 0x53a7;\n                        break;\n                    default:\n                        throw new Error(_0x1c80ac(0x330) + _0x43b518[_0x1c80ac(0x3ae)](-0x1f71 + 0xdc3 * -0x1 + 0x2d44));\n                }\n            }\n            return _0x79a402 < _0x2a039f && (_0x4921e2[_0x1c80ac(0x259)] = _0x79a402),\n                String[_0x1c80ac(0x1e2)]['apply'](String, _0x4921e2);\n        }\n\n        function _0x25bfe1(_0x5ad020, _0x1001f1) {\n            var _0xa8facb = _0x5612de;\n            for (var _0xdb2671 = [], _0x67f891 = new Array(-0x29 * 0x169 + 0x1d * -0x3c7 + -0x6 * -0x313a), _0x3fce02 = -0x47c * -0x1 + -0xc83 + 0x2ad * 0x3, _0x47254b = 0x1010 + -0xb * 0x29 + -0xe4d, _0x4445a9 = _0x5ad020[_0xa8facb(0x259)]; _0x3fce02 < _0x1001f1 && _0x47254b < _0x4445a9; _0x3fce02++) {\n                var _0x488af6 = _0x5ad020['charCodeAt'](_0x47254b++);\n                switch (_0x488af6 >> -0x1148 + 0xbd2 + 0x57a) {\n                    case -0x1 * -0xb6b + 0x16f6 + -0x2261:\n                    case -0x1678 + -0x1c12 + 0x3 * 0x10d9:\n                    case 0xd01 * -0x2 + 0x2c2 + -0x1a * -0xe5:\n                    case 0x1985 + 0x49 * -0x6d + 0x593:\n                    case 0xbac + 0xd1a * 0x1 + -0x18c2:\n                    case -0x11 * -0x1 + 0x1 * -0x18bd + 0x18b1:\n                    case 0x1e6 + -0x129a * -0x1 + 0x1 * -0x147a:\n                    case -0x1 * 0xf49 + 0xed + 0xe63:\n                        _0x67f891[_0x3fce02] = _0x488af6;\n                        break;\n                    case 0x30e * 0xb + 0x255b + -0x1 * 0x46e9:\n                    case 0x71 * -0xf + -0x1371 + 0x1a1d:\n                        if (!(_0x47254b < _0x4445a9))\n                            throw new Error(_0xa8facb(0x394));\n                        _0x67f891[_0x3fce02] = (-0x407 * -0x5 + -0xcb5 + 0x74f * -0x1 & _0x488af6) << -0x585 + -0xbf8 + 0x1183 | -0x1 * 0x1e25 + 0x6d * -0x3b + 0x1281 * 0x3 & _0x5ad020['charCodeAt'](_0x47254b++);\n                        break;\n                    case -0x676 * -0x4 + -0x351 + -0x1679:\n                        if (!(_0x47254b + (0x1b63 + -0x5 * 0x463 + -0x573) < _0x4445a9))\n                            throw new Error(_0xa8facb(0x394));\n                        _0x67f891[_0x3fce02] = (0x2dd * 0x7 + -0x15dd + 0x1e1 & _0x488af6) << 0x141c + 0x18e3 + -0x2cf3 | (-0x1 * -0x619 + 0x1 * 0x18bf + -0xa33 * 0x3 & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << 0x1343 * -0x1 + -0x9 * 0x198 + 0x21a1 | 0x455 + -0x1ef3 + 0x1add & _0x5ad020['charCodeAt'](_0x47254b++);\n                        break;\n                    case -0x21f + -0x13f9 * 0x1 + -0x6b * -0x35:\n                        if (!(_0x47254b + (-0xde * -0xb + 0x20cf + -0x2a57) < _0x4445a9))\n                            throw new Error(_0xa8facb(0x394));\n                        var _0x59357e = ((0x1081 + -0x1b6f + 0xaf5 & _0x488af6) << -0x1 * -0x511 + -0x45 * 0x55 + 0x11ea | (0x125a * 0x2 + 0x4bd * -0x2 + -0x1afb & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << 0xbf4 * -0x2 + -0x1512 + 0x2d06 | (0x1aae + 0xd81 + -0x27f0 & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << 0x1759 + -0x9a1 * -0x1 + 0x4c * -0x6f | 0x352 * -0xb + -0xde7 + 0x32ac & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) - (-0x57e9 + 0x19207 + -0x3a1e);\n                        if (!(0x41b * -0x7 + 0x1658 + 0x1 * 0x665 <= _0x59357e && _0x59357e <= -0xf6 * -0x7ed + -0x1bcf3b + -0x4 * -0x90c5f))\n                            throw new Error('Character\\x20outside\\x20valid\\x20Unicode\\x20range:\\x200x' + _0x59357e['toString'](-0x40f + -0x5 * -0x61f + 0x1c4 * -0xf));\n                        _0x67f891[_0x3fce02++] = _0x59357e >> -0x15e2 + 0x1 * -0xb51 + -0x43 * -0x7f & -0x11a2 + 0xb * -0x29 + 0x7cc * 0x3 | 0x1 * -0x3d14 + 0x159a9 + -0x1 * 0x4495,\n                            _0x67f891[_0x3fce02] = 0x1 * 0x101 + -0x499 + 0x797 & _0x59357e | 0x1dec + 0x87f7 + 0x361d;\n                        break;\n                    default:\n                        throw new Error('Bad\\x20UTF-8\\x20encoding\\x200x' + _0x488af6[_0xa8facb(0x3ae)](-0x11 * 0x1dc + 0x1a53 + 0x559));\n                }\n                if (_0x3fce02 >= -0xb3 * -0x16e + 0x1616 + 0x1a6 * -0x5b) {\n                    var _0x2ceb4e = _0x3fce02 + (0x4 * -0x8fe + 0x665 * 0x3 + 0x10ca);\n                    _0x67f891[_0xa8facb(0x259)] = _0x2ceb4e,\n                        _0xdb2671[_0xdb2671[_0xa8facb(0x259)]] = String[_0xa8facb(0x1e2)][_0xa8facb(0x207)](String, _0x67f891),\n                        _0x1001f1 -= _0x2ceb4e,\n                        _0x3fce02 = -(-0x18 * -0x111 + 0x2 * 0x9e3 + -0x2d5d);\n                }\n            }\n            return _0x3fce02 > 0x1 * 0xb5d + -0x20a3 + 0x1546 && (_0x67f891['length'] = _0x3fce02,\n                _0xdb2671[_0xdb2671[_0xa8facb(0x259)]] = String['fromCharCode'][_0xa8facb(0x207)](String, _0x67f891)),\n                _0xdb2671['join']('');\n        }\n\n        function _0x31dfb5(_0x360a73, _0xe765ba) {\n            var _0x293f34 = _0x5612de;\n            return (null == _0xe765ba || _0xe765ba < -0x1605 + 0xf7 * 0xe + 0x883) && (_0xe765ba = _0x360a73[_0x293f34(0x259)]),\n                -0x6 * 0x30b + -0x1608 + 0x284a === _0xe765ba ? '' : /^[\\x00-\\x7f]*$/[_0x293f34(0x22b)](_0x360a73) || !/^[\\x00-\\xff]*$/[_0x293f34(0x22b)](_0x360a73) ? _0xe765ba === _0x360a73[_0x293f34(0x259)] ? _0x360a73 : _0x360a73[_0x293f34(0x3a7)](0x169 + 0x887 + 0x6a * -0x18, _0xe765ba) : _0xe765ba < 0x1d0d6 + 0x73e5 + -0x4 * 0x512f ? _0x45fbef(_0x360a73, _0xe765ba) : _0x25bfe1(_0x360a73, _0xe765ba);\n        }\n\n        function _0xdda738(_0x21d8ce, _0x4bf3f9) {\n            var _0x46d91f = _0x5612de;\n            return null == _0x21d8ce || 0x1 * -0xab1 + -0x2567 * -0x1 + -0x1ab6 === _0x21d8ce[_0x46d91f(0x259)] ? _0x21d8ce : (_0x21d8ce = _0x532596(_0x21d8ce),\n                _0x4bf3f9 = _0x532596(_0x4bf3f9),\n                _0x75d5b3(_0x3d58e7(_0x183951(_0x21d8ce, !(0xad5 + 0xaa1 + -0x2 * 0xabb)), _0x231484(_0x183951(_0x4bf3f9, !(-0x106c + -0x1173 * -0x2 + -0x1279)))), !(-0x1 * 0x2c8 + -0xc8 + 0x391)));\n        }\n\n        function _0x4bb829(_0x1f763e, _0x47e9cd) {\n            var _0x18b798 = _0x5612de;\n            return null == _0x1f763e || -0x12 * 0xe1 + 0x3cb * -0x5 + 0x22c9 === _0x1f763e[_0x18b798(0x259)] ? _0x1f763e : (_0x47e9cd = _0x532596(_0x47e9cd),\n                _0x31dfb5(_0x75d5b3(_0x4aaf04(_0x183951(_0x1f763e, !(-0x40 * -0x16 + -0x133 * -0x1d + -0x2846)), _0x231484(_0x183951(_0x47e9cd, !(0x1e64 + 0xcee + -0x2b51)))), !(-0x1daa + -0xbb1 + 0x295b))));\n        }\n\n        function _0x39dfe4() {\n            var _0x2fd4da = _0x5612de\n                , _0x21e994 = '';\n            try {\n                window[_0x2fd4da(0x3be)] && (_0x21e994 = window[_0x2fd4da(0x3be)]['getItem']('_byted_param_sw')),\n                _0x21e994 && !window[_0x2fd4da(0x1dc)] || (_0x21e994 = window['localStorage'][_0x2fd4da(0x2d8)]('_byted_param_sw'));\n            } catch (_0x3b8cd9) {\n            }\n            if (_0x21e994)\n                try {\n                    var _0x25acb5 = _0x4bb829(_0xb5350b(_0x21e994[_0x2fd4da(0x2a5)](0x19 * 0xc9 + -0x1bc8 + -0x82f * -0x1)), _0x21e994[_0x2fd4da(0x2a5)](0x2 * 0xa88 + -0x25 * -0x94 + -0x2a74, 0x2c6 * 0x5 + -0x14c6 + 0x1bc * 0x4));\n                    if ('on' === _0x25acb5)\n                        return !(0x527 * -0x7 + 0x7b7 + 0x1c5a);\n                    if (_0x2fd4da(0x304) === _0x25acb5)\n                        return !(0x1b29 * -0x1 + -0xd8d + 0x1 * 0x28b7);\n                } catch (_0x1da1e4) {\n                }\n            return !(-0x158c + 0x10 * -0x13d + 0x1 * 0x295d);\n        }\n\n        function _0x1b4bf1() {\n            var _0x4eb990 = _0x5612de;\n            return w_0x5c3140(_0x4eb990(0x211), {\n                get 0x0() {\n                    var _0x448d97 = _0x4eb990;\n                    return _0x448d97(0x384) != typeof navigator ? navigator : void (-0xd95 * -0x2 + -0x1 * 0x16ed + 0x5 * -0xd9);\n                },\n                get 0x1() {\n                    var _0x389269 = _0x4eb990;\n                    return _0x389269(0x384) != typeof window ? window : void (0x63e + 0xb * -0x32b + -0x1c9b * -0x1);\n                },\n                get 0x2() {\n                    return _0x1db123;\n                },\n                0x3: Object,\n                get 0x4() {\n                    return 'undefined' != typeof document ? document : void (0xe3a + 0x2499 + -0x32d3);\n                },\n                get 0x5() {\n                    var _0x813809 = _0x4eb990;\n                    return _0x813809(0x384) != typeof location ? location : void (-0x1 * -0x2145 + 0x54e * -0x7 + -0x1 * -0x3dd);\n                },\n                get 0x6() {\n                    return _0x176a57;\n                },\n                get 0x7() {\n                    return 'undefined' != typeof history ? history : void (-0x17d + -0x1ef4 + 0x2071);\n                },\n                0x8: arguments\n            }, this);\n        }\n\n        function _0x532cd9() {\n            var _0x3b3ba1 = _0x5612de;\n            return w_0x5c3140(_0x3b3ba1(0x190), {\n                get 0x0() {\n                    return _0x176a57;\n                },\n                get 0x1() {\n                    return navigator;\n                },\n                get 0x2() {\n                    return PluginArray;\n                },\n                get 0x3() {\n                    return window;\n                },\n                0x4: arguments\n            }, this);\n        }\n\n        function _0x3391fc() {\n            var _0x2aea9b = _0x5612de;\n            return w_0x5c3140(_0x2aea9b(0x266), {\n                get 0x0() {\n                    return _0x12ada0;\n                },\n                get 0x1() {\n                    return navigator;\n                },\n                0x2: Object,\n                get 0x3() {\n                    return window;\n                },\n                0x4: arguments,\n                0x5: RegExp\n            }, this);\n        }\n\n        function _0x21fa28() {\n            var _0x1106df = _0x5612de;\n            return w_0x5c3140(_0x1106df(0x17b), {\n                set 0x0(_0x2b3a0b) {\n                    _0x12ada0 = _0x2b3a0b;\n                },\n                0x1: Object,\n                get 0x2() {\n                    return window;\n                },\n                0x3: arguments\n            }, this);\n        }\n\n        function _0x49b1d7(_0x4f4807) {\n            var _0x4f1753 = _0x5612de;\n            return w_0x5c3140(_0x4f1753(0x171), {\n                get 0x0() {\n                    return _0x1230e7;\n                },\n                get 0x1() {\n                    return indexedDB;\n                },\n                get 0x2() {\n                    return _0xf8ccf1;\n                },\n                get 0x3() {\n                    return window;\n                },\n                get 0x4() {\n                    return DOMException;\n                },\n                get 0x5() {\n                    return _0x176a57;\n                },\n                get 0x6() {\n                    return _0x6caf;\n                },\n                0x7: arguments,\n                0x8: _0x4f4807\n            }, this);\n        }\n\n        function _0x462256() {\n            var _0x1ed1aa = _0x5612de;\n            return w_0x5c3140(_0x1ed1aa(0x163), {\n                get 0x0() {\n                    return _0x176a57;\n                },\n                get 0x1() {\n                    return document;\n                },\n                get 0x2() {\n                    return navigator;\n                },\n                0x3: arguments,\n                0x4: RegExp\n            }, this);\n        }\n\n        function _0x3cee0e() {\n            var _0x5f1e22 = _0x5612de;\n            return w_0x5c3140(_0x5f1e22(0x2dd), {\n                get 0x0() {\n                    return navigator;\n                },\n                get 0x1() {\n                    return window;\n                },\n                0x2: arguments,\n                0x3: RegExp\n            }, this);\n        }\n\n        function _0x1f9824() {\n            var _0x1d4f72 = _0x5612de\n                , _0x5821af = '';\n            if (_0x6caf['PLUGIN'])\n                _0x5821af = _0x6caf[_0x1d4f72(0x354)];\n            else {\n                for (var _0x580f96 = [], _0x3ca683 = navigator[_0x1d4f72(0x1ba)] || [], _0x15f771 = 0x389 * 0x5 + -0x2a * -0xe2 + -0x36c1; _0x15f771 < -0xe3b * 0x1 + 0x1a76 + -0x6 * 0x209; _0x15f771++)\n                    try {\n                        for (var _0x5a4f6c = _0x3ca683[_0x15f771], _0x3a1f6 = [], _0x1a6da9 = -0x869 + -0x111 * 0x14 + -0x1dbd * -0x1; _0x1a6da9 < _0x5a4f6c[_0x1d4f72(0x259)]; _0x1a6da9++)\n                            _0x5a4f6c[_0x1d4f72(0x37c)](_0x1a6da9) && _0x3a1f6[_0x1d4f72(0x36e)](_0x5a4f6c['item'](_0x1a6da9)[_0x1d4f72(0x1ab)]);\n                        var _0x1ae7c8 = _0x5a4f6c[_0x1d4f72(0x341)] + '';\n                        _0x5a4f6c['version'] && (_0x1ae7c8 += _0x5a4f6c[_0x1d4f72(0x2c1)] + ''),\n                            _0x1ae7c8 += _0x5a4f6c['filename'] + '',\n                            _0x1ae7c8 += _0x3a1f6[_0x1d4f72(0x24f)](''),\n                            _0x580f96['push'](_0x1ae7c8);\n                    } catch (_0x4e31c6) {\n                    }\n                _0x5821af = _0x580f96[_0x1d4f72(0x24f)]('##'),\n                    _0x6caf[_0x1d4f72(0x354)] = _0x5821af;\n            }\n            return _0x5821af[_0x1d4f72(0x2a5)](-0x1 * 0x26c + -0x1e2f + 0x209b, -0x26ff + 0x1b6e * 0x1 + 0xf91);\n        }\n\n        function _0x30412e() {\n            var _0x5a747f = _0x5612de\n                , _0x5640f8 = [];\n            try {\n                var _0x3405cb = navigator[_0x5a747f(0x1ba)];\n                if (_0x3405cb) {\n                    for (var _0x53b06e = -0x8aa + 0x341 + 0x115 * 0x5; _0x53b06e < _0x3405cb[_0x5a747f(0x259)]; _0x53b06e++)\n                        for (var _0xa74ec6 = -0x1829 + 0x1f9c + -0x773; _0xa74ec6 < _0x3405cb[_0x53b06e][_0x5a747f(0x259)]; _0xa74ec6++) {\n                            var _0x2bcc6c = [_0x3405cb[_0x53b06e][_0x5a747f(0x19e)], _0x3405cb[_0x53b06e][_0xa74ec6][_0x5a747f(0x1ab)], _0x3405cb[_0x53b06e][_0xa74ec6][_0x5a747f(0x169)]][_0x5a747f(0x24f)]('|');\n                            _0x5640f8['push'](_0x2bcc6c);\n                        }\n                }\n            } catch (_0x11c0f4) {\n            }\n            return _0x5640f8;\n        }\n\n        function _0x28e2ec() {\n            var _0x3301ae = _0x5612de;\n            return w_0x5c3140(_0x3301ae(0x1a6), {\n                get 0x0() {\n                    return navigator;\n                },\n                get 0x1() {\n                    return _0x1f9824;\n                },\n                get 0x2() {\n                    return window;\n                },\n                0x3: arguments\n            }, this);\n        }\n\n        function _0x5863d1() {\n            var _0x247350 = _0x5612de;\n            return w_0x5c3140(_0x247350(0x21c), {\n                get 0x0() {\n                    return _0x462335;\n                },\n                get 0x1() {\n                    return _0x39dfe4;\n                },\n                get 0x2() {\n                    return _0x1b4bf1;\n                },\n                get 0x3() {\n                    return _0x53b77d;\n                },\n                get 0x4() {\n                    return _0x49b1d7;\n                },\n                get 0x5() {\n                    return _0x3ed707;\n                },\n                get 0x6() {\n                    return _0x532cd9;\n                },\n                get 0x7() {\n                    return _0x3391fc;\n                },\n                get 0x8() {\n                    return _0x462256;\n                },\n                get 0x9() {\n                    return _0x3cee0e;\n                },\n                get 0xa() {\n                    return _0x28e2ec;\n                },\n                get 0xb() {\n                    return _0x6caf;\n                },\n                0xc: arguments\n            }, this);\n        }\n\n        function _0x2a900b(_0x29489b) {\n            var _0x3163ac = _0x5612de;\n            for (var _0x2edc36 = Object[_0x3163ac(0x17f)](_0x29489b), _0x4da10f = -0x26c9 + -0x11f1 * -0x1 + 0x14d8, _0x26fc90 = _0x2edc36[_0x3163ac(0x259)] - (0x1cea + -0x5 * 0x2f5 + 0x8 * -0x1c4); _0x26fc90 >= -0x2 * -0x397 + 0x17ce + -0x1efc; _0x26fc90--) {\n                _0x4da10f = (_0x29489b[_0x2edc36[_0x26fc90]] ? 0x455 * 0x9 + 0x1715 + -0x3e11 : -0x1 * -0x22f7 + 0x1f6c * 0x1 + -0x203 * 0x21) << _0x2edc36[_0x3163ac(0x259)] - _0x26fc90 - (-0x64c * -0x6 + -0x163 + -0x224 * 0x11) | _0x4da10f;\n            }\n            return _0x4da10f;\n        }\n\n        function _0x246aeb(_0x1b02ae, _0x32abc9) {\n            var _0x172517 = _0x5612de;\n            for (var _0x4d2e6c = 0x1e44 + 0x2 * 0x443 + 0x2 * -0x1365; _0x4d2e6c < _0x32abc9[_0x172517(0x259)]; _0x4d2e6c++)\n                _0x1b02ae = (-0xa15f + -0x1a803 + 0x349a1) * _0x1b02ae + _0x32abc9[_0x172517(0x195)](_0x4d2e6c) >>> -0x2c6 + 0x2 * -0x126c + 0x279e;\n            return _0x1b02ae;\n        }\n\n        function _0x184783(_0x9867bc, _0x21d0e6) {\n            var _0x25b989 = _0x5612de;\n            for (var _0x21703e = -0xa6 * -0x1 + 0xbf * -0x5 + -0x315 * -0x1; _0x21703e < _0x21d0e6[_0x25b989(0x259)]; _0x21703e++)\n                _0x9867bc = (-0x6275 + 0xd966 + -0x5f * -0x172) * (_0x9867bc ^ _0x21d0e6['charCodeAt'](_0x21703e)) >>> -0xf * 0x1a + 0x7 * -0x543 + 0x443 * 0x9;\n            return _0x9867bc;\n        }\n\n        function _0xf119da(_0x57529f, _0x19340f) {\n            var _0x1de06d = _0x5612de;\n            for (var _0x3e7b02 = 0x45a * 0x1 + -0xe5d * 0x2 + 0x1860; _0x3e7b02 < _0x19340f[_0x1de06d(0x259)]; _0x3e7b02++) {\n                var _0x25af5d = _0x19340f[_0x1de06d(0x195)](_0x3e7b02);\n                if (_0x25af5d >= -0x12321 + 0x417 * -0xa + 0x22407 && _0x25af5d <= 0x92d4 + 0xb6fd + -0x6dd2 && _0x3e7b02 < _0x19340f[_0x1de06d(0x259)]) {\n                    var _0xfb40a0 = _0x19340f['charCodeAt'](_0x3e7b02 + (0x688 * 0x4 + 0x145 * 0x17 + -0x3752));\n                    -0xa62a + -0x10ba7 + -0x5d67 * -0x7 == (0xfbaf + 0x1ce63 + -0x1ce12 & _0xfb40a0) && (_0x25af5d = ((-0x9fe * 0x1 + 0x2 * -0xf33 + 0x2c63 & _0x25af5d) << -0x86d * 0x4 + -0x211 * 0x9 + -0x1 * -0x3457) + (-0x1b17 + 0xb6c + 0x13aa & _0xfb40a0) + (0x2 * 0xab9c + -0x18f24 + -0x4 * -0x4dfb),\n                        _0x3e7b02 += -0x1e31 + -0xa * 0x38b + -0x150 * -0x32);\n                }\n                _0x57529f = (-0x3a * 0x7e4 + -0x3827 * -0x2 + 0x151 * 0x1c9) * _0x57529f + _0x25af5d >>> 0x3e7 + -0x1 * -0x5e7 + -0x9ce;\n            }\n            return _0x57529f;\n        }\n\n        function _0x53f850(_0x450920) {\n            var _0x30ac3f = _0x5612de\n                , _0x4eeea4 = _0x450920 || '';\n            return _0x4eeea4 = (_0x4eeea4 = -(-0x13 * -0x5a + 0xb2f + -0x11dc) !== (_0x4eeea4 = _0x4eeea4[_0x30ac3f(0x377)](/(http:\\/\\/|https:\\/\\/|\\/\\/)?[^\\/]*/, ''))['indexOf']('?') ? _0x4eeea4[_0x30ac3f(0x3a7)](-0x819 * 0x3 + 0x1d1c + -0x9 * 0x89, _0x4eeea4[_0x30ac3f(0x2c5)]('?')) : _0x4eeea4) || '/';\n        }\n\n        function _0x446110(_0xc80785) {\n            var _0x5bf664 = _0x5612de\n                , _0x471548 = _0xc80785 || ''\n                , _0x2cf363 = _0x471548[_0x5bf664(0x1c2)](/[?](\\w+=.*&?)*/)\n                ,\n                _0x137237 = (_0x471548 = _0x2cf363 ? _0x2cf363[-0x2292 + -0x4 * 0x520 + 0x173 * 0x26][_0x5bf664(0x3a7)](0x112 * 0x11 + 0x61 + -0x2 * 0x949) : '') ? _0x471548[_0x5bf664(0x342)]('&') : null\n                , _0x290269 = {};\n            if (_0x137237) {\n                for (var _0x15cd4c = 0xd54 + -0x49f + 0x2e7 * -0x3; _0x15cd4c < _0x137237[_0x5bf664(0x259)]; _0x15cd4c++)\n                    _0x290269[_0x137237[_0x15cd4c]['split']('=')[0x65c + 0x3f8 * -0x2 + 0x194]] = _0x137237[_0x15cd4c][_0x5bf664(0x342)]('=')[0x15bb * -0x1 + -0x50b * 0x4 + 0x29e8];\n            }\n            return _0x290269;\n        }\n\n        function _0x3a1cf3(_0x8af04, _0xe4b509) {\n            var _0x28f81c = _0x5612de;\n            if (!_0x8af04 || '{}' === JSON[_0x28f81c(0x1e6)](_0x8af04))\n                return {};\n            for (var _0x257ee8 = Object[_0x28f81c(0x17f)](_0x8af04)['sort'](), _0x24c84a = {}, _0x4bfbcd = -0x1 * 0x21fb + -0x25 * -0x16 + 0x1ecd; _0x4bfbcd < _0x257ee8[_0x28f81c(0x259)]; _0x4bfbcd++)\n                _0x24c84a[_0x257ee8[_0x4bfbcd]] = _0xe4b509 ? _0x8af04[_0x257ee8[_0x4bfbcd]] + '' : _0x8af04[_0x257ee8[_0x4bfbcd]];\n            return _0x24c84a;\n        }\n\n        function _0x20b77a(_0x3745f1) {\n            var _0x211da5 = _0x5612de;\n            return Array[_0x211da5(0x2af)](_0x3745f1) ? _0x3745f1['map'](_0x20b77a) : _0x3745f1 instanceof Object ? Object[_0x211da5(0x17f)](_0x3745f1)[_0x211da5(0x38e)]()[_0x211da5(0x376)](function (_0x4b45b3, _0x5188a8) {\n                return _0x4b45b3[_0x5188a8] = _0x20b77a(_0x3745f1[_0x5188a8]),\n                    _0x4b45b3;\n            }, {}) : _0x3745f1;\n        }\n\n        function _0x483e03(_0x44c650) {\n            var _0x498394 = _0x5612de;\n            if (!_0x44c650 || '{}' === JSON[_0x498394(0x1e6)](_0x44c650))\n                return '';\n            for (var _0x52341a = Object['keys'](_0x44c650)['sort'](), _0x3c151a = '', _0x4f5c3f = -0xefc + 0x25ba + 0x29 * -0x8e; _0x4f5c3f < _0x52341a[_0x498394(0x259)]; _0x4f5c3f++)\n                _0x3c151a += [_0x52341a[_0x4f5c3f]] + '=' + _0x44c650[_0x52341a[_0x4f5c3f]] + '&';\n            return _0x3c151a;\n        }\n\n        function _0x4bae98() {\n            var _0x33d77a = _0x5612de;\n            try {\n                return !!window[_0x33d77a(0x3be)];\n            } catch (_0x2002b2) {\n                return !(0xcab + -0xcff + 0x2 * 0x2a);\n            }\n        }\n\n        function _0x275e5a() {\n            try {\n                return !!window['localStorage'];\n            } catch (_0x2df8fe) {\n                return !(-0x1ff * -0xd + 0x1cf1 * -0x1 + -0x17f * -0x2);\n            }\n        }\n\n        function _0x4fdb47() {\n            var _0x34b6b1 = _0x5612de;\n            try {\n                return !!window[_0x34b6b1(0x218)];\n            } catch (_0x3b6071) {\n                return !(0xedb * -0x1 + 0x41b * -0x5 + -0x2 * -0x11b1);\n            }\n        }\n\n        function _0x1afbc2() {\n            return _0x5af46a(_0x4fdb47()) + _0x5af46a(_0x275e5a()) + _0x5af46a(_0x4bae98());\n        }\n\n        function _0xc6f828(_0x23a724) {\n            var _0x198ea0 = _0x5612de, _0x112670, _0x256bde = document[_0x198ea0(0x260)](_0x198ea0(0x24d));\n            _0x256bde[_0x198ea0(0x302)] = 0x1813 * -0x1 + 0x1f94 + 0x751 * -0x1,\n                _0x256bde[_0x198ea0(0x245)] = -0x205f + 0x4f6 + -0x1b79 * -0x1;\n            var _0xa760ad = _0x256bde['getContext']('2d');\n            _0xa760ad[_0x198ea0(0x18f)] = '14px\\x20serif',\n                _0xa760ad[_0x198ea0(0x196)]('龘ฑภ경', 0x2162 * 0x1 + 0xbbb + -0x2d1b, -0x1 * -0x138a + -0x164e + 0x90 * 0x5),\n                _0xa760ad[_0x198ea0(0x3a0)] = -0xa67 + 0x7c * 0x39 + 0x103 * -0x11,\n                _0xa760ad[_0x198ea0(0x268)] = 0x22cf * 0x1 + -0x4d3 + 0x5 * -0x5ff,\n                _0xa760ad[_0x198ea0(0x340)] = _0x198ea0(0x21b),\n                _0xa760ad['arc'](-0x1 * -0x5dd + -0x6de + 0x109, -0x336 * 0x4 + -0x167a + 0x712 * 0x5, -0x7c8 + 0xb80 + -0x3b * 0x10, 0x411 + 0x38 * -0xaa + 0x3d * 0x8b, 0x7f * -0x20 + 0x11bb + -0x1d9),\n                _0xa760ad['stroke'](),\n                _0x112670 = _0x256bde[_0x198ea0(0x239)]();\n            for (var _0x367ff8 = 0xfa7 * -0x1 + -0x53 * 0x6d + 0x32fe; _0x367ff8 < 0x17b + -0x1b0e * 0x1 + 0x2b * 0x99; _0x367ff8++)\n                _0x23a724 = (0x1675 * -0xc + -0xe91a + 0x2f6d5) * _0x23a724 + _0x112670['charCodeAt'](_0x23a724 % _0x112670[_0x198ea0(0x259)]) >>> -0x44 + 0xfa0 * -0x2 + -0x1f84 * -0x1;\n            return _0x23a724;\n        }\n\n        var _0x37a93a = -0x1b3b + 0x2136 + -0x1 * 0x5fb;\n\n        function _0x18b4be() {\n            var _0x4d1378 = _0x5612de;\n            try {\n                return _0x37a93a || (_0x462335[_0x4d1378(0x219)] ? -(-0x1 * 0x19d5 + -0x1e5d + 0x3833) : _0x37a93a = _0xc6f828(0x15 * 0x144d79ba + 0x8831fd63 + -0x153df3ab6));\n            } catch (_0x3c9d0d) {\n                return -(0x1e58 + -0x26 * -0xcb + 0x3c79 * -0x1);\n            }\n        }\n\n        function _0x1a39c4() {\n            if (_0x37a93a)\n                return _0x37a93a;\n            _0x37a93a = _0xc6f828(-0x361cdc2a * -0x5 + 0x17c5 * 0xb369b + -0x2f7 * 0x6a0ca6);\n        }\n\n        var _0x45ece5 = {\n            'fpProfileUrl': _0x5612de(0x172)\n        };\n\n        function _0x130155() {\n            var _0x5e9262 = _0x5612de\n                , _0x380346 = window[_0x5e9262(0x328)];\n            return _0x380346[_0x5e9262(0x302)] + '_' + _0x380346[_0x5e9262(0x245)] + '_' + _0x380346[_0x5e9262(0x17e)];\n        }\n\n        function _0x2a76f8() {\n            var _0x1d2b79 = _0x5612de\n                , _0xa8cb6a = window['screen'];\n            return _0xa8cb6a[_0x1d2b79(0x38a)] + '_' + _0xa8cb6a[_0x1d2b79(0x276)];\n        }\n\n        function _0x3da279() {\n            return new Promise(function (_0x2a10ed) {\n                    var _0x7d3f27 = w_0x25f3;\n                    if (_0x7d3f27(0x1b2) in navigator)\n                        try {\n                            navigator['getBattery']()[_0x7d3f27(0x1ed)](function (_0x13ff1d) {\n                                var _0x479b99 = _0x7d3f27;\n                                _0x2a10ed(_0x13ff1d[_0x479b99(0x3ac)] + '_' + _0x13ff1d[_0x479b99(0x2b0)] + '_' + _0x13ff1d[_0x479b99(0x353)] + '_' + _0x13ff1d[_0x479b99(0x213)]);\n                            });\n                        } catch (_0x2c28b8) {\n                            _0x2a10ed('');\n                        }\n                    else\n                        _0x2a10ed('');\n                }\n            );\n        }\n\n        var _0x47ec2a = {};\n\n        function _0x299f3a() {\n            var _0x2531b6 = _0x5612de, _0x1a8a34, _0x2e0843 = _0x2531b6(0x33b), _0x29ea20 = -0x12a4 + 0x30b + 0xf99;\n            void (-0x2b * 0xa + -0x1d8d + 0x1f3b) !== navigator[_0x2e0843] && (_0x29ea20 = navigator[_0x2e0843]);\n            try {\n                document[_0x2531b6(0x188)](_0x2531b6(0x240)),\n                    _0x1a8a34 = !(-0x1f61 + 0x19 * 0x22 + 0x1c0f);\n            } catch (_0x3992e0) {\n                _0x1a8a34 = !(0x17 * -0x5d + -0x1 * 0x209 + 0x377 * 0x3);\n            }\n            var _0x11190a = _0x2531b6(0x1ea) in window;\n            return Object[_0x2531b6(0x2a0)](_0x47ec2a, {\n                'maxTouchPoints': _0x29ea20,\n                'touchEvent': _0x1a8a34,\n                'touchStart': _0x11190a\n            }),\n            _0x29ea20 + '_' + _0x1a8a34 + '_' + _0x11190a;\n        }\n\n        function _0xbe842b() {\n            return _0x47ec2a;\n        }\n\n        function _0x4649a1() {\n            var _0x3b6f20 = _0x5612de\n                , _0x4256a7 = new Date();\n            _0x4256a7[_0x3b6f20(0x22d)](-0x1477 + 0xde4 * -0x1 + 0xb74 * 0x3),\n                _0x4256a7[_0x3b6f20(0x294)](-0x360 + -0x263d + 0x29a2);\n            var _0x213a03 = -_0x4256a7[_0x3b6f20(0x237)]();\n            _0x4256a7[_0x3b6f20(0x294)](-0x9b5 + 0x5 * 0x77e + -0x2 * 0xddb);\n            var _0x5a2621 = -_0x4256a7[_0x3b6f20(0x237)]();\n            return Math['min'](_0x213a03, _0x5a2621);\n        }\n\n        function _0x487576() {\n            var _0x5557a1 = _0x5612de;\n            if (_0x6caf[_0x5557a1(0x2db)])\n                return _0x6caf[_0x5557a1(0x2db)];\n            try {\n                var _0x4f28ec = document[_0x5557a1(0x260)](_0x5557a1(0x24d))[_0x5557a1(0x2f9)]('webgl')\n                    , _0x36473d = _0x4f28ec['getExtension'](_0x5557a1(0x375))\n                    ,\n                    _0x3ebb8d = _0x4f28ec[_0x5557a1(0x383)](_0x36473d['UNMASKED_VENDOR_WEBGL']) + '/' + _0x4f28ec['getParameter'](_0x36473d[_0x5557a1(0x39e)]);\n                return _0x6caf[_0x5557a1(0x2db)] = _0x3ebb8d,\n                    _0x3ebb8d;\n            } catch (_0x2b9fa5) {\n                return '';\n            }\n        }\n\n        function _0x4f323e() {\n            var _0x2968a5 = _0x5612de\n                , _0xf55c22 = [_0x2968a5(0x27b), 'sans-serif', _0x2968a5(0x1fb)]\n                , _0x3ed5f8 = {}\n                , _0x2fef11 = {};\n            if (!document[_0x2968a5(0x189)])\n                return '0';\n            for (var _0x6f70bc = -0x2271 + 0x2f * 0x72 + 0xd83, _0x3e66d7 = _0xf55c22; _0x6f70bc < _0x3e66d7['length']; _0x6f70bc++) {\n                var _0x189f91 = _0x3e66d7[_0x6f70bc]\n                    , _0x2bf145 = document[_0x2968a5(0x260)](_0x2968a5(0x1f7));\n                _0x2bf145['innerHTML'] = _0x2968a5(0x2a3),\n                    _0x2bf145['style'][_0x2968a5(0x362)] = '72px',\n                    _0x2bf145['style']['fontFamily'] = _0x189f91,\n                    document[_0x2968a5(0x189)][_0x2968a5(0x26c)](_0x2bf145),\n                    _0x3ed5f8[_0x189f91] = _0x2bf145[_0x2968a5(0x2ee)],\n                    _0x2fef11[_0x189f91] = _0x2bf145['offsetHeight'],\n                    document[_0x2968a5(0x189)][_0x2968a5(0x30d)](_0x2bf145);\n            }\n            var _0x4f59cf,\n                _0x4abd0f = ['Trebuchet\\x20MS', _0x2968a5(0x177), _0x2968a5(0x25d), 'Segoe\\x20UI', _0x2968a5(0x321), _0x2968a5(0x192), 'MT\\x20Extra', _0x2968a5(0x3a9), _0x2968a5(0x28e), _0x2968a5(0x346), 'Meiryo', _0x2968a5(0x247), _0x2968a5(0x1ef), _0x2968a5(0x1d8), 'IrisUPC', 'Palatino', 'Colonna\\x20MT', 'Playbill', _0x2968a5(0x1f4), _0x2968a5(0x288), _0x2968a5(0x1f2), _0x2968a5(0x38d), 'OPTIMA', _0x2968a5(0x2d9), _0x2968a5(0x348), _0x2968a5(0x2b3), 'Savoye\\x20LET', _0x2968a5(0x3c5), _0x2968a5(0x21e)];\n            _0x4f59cf = -0x255b * -0x1 + -0x1 * -0x139d + -0x38f8;\n            for (var _0x16c300 = -0x1 * 0xc3e + -0x20ff + 0x2d3d; _0x16c300 < _0x4abd0f[_0x2968a5(0x259)]; _0x16c300++) {\n                var _0x2c3be4, _0x37b937 = _0x350075(_0xf55c22);\n                try {\n                    for (_0x37b937['s'](); !(_0x2c3be4 = _0x37b937['n']())[_0x2968a5(0x1e3)];) {\n                        var _0x400340 = _0x2c3be4['value']\n                            , _0x200821 = document[_0x2968a5(0x260)]('span');\n                        _0x200821[_0x2968a5(0x36a)] = _0x2968a5(0x2a3),\n                            _0x200821['style'][_0x2968a5(0x362)] = _0x2968a5(0x283),\n                            _0x200821[_0x2968a5(0x280)]['fontFamily'] = _0x4abd0f[_0x16c300] + ',' + _0x400340,\n                            document['body'][_0x2968a5(0x26c)](_0x200821);\n                        var _0x533f71 = _0x200821[_0x2968a5(0x2ee)] !== _0x3ed5f8[_0x400340] || _0x200821[_0x2968a5(0x2a4)] !== _0x2fef11[_0x400340];\n                        if (document[_0x2968a5(0x189)][_0x2968a5(0x30d)](_0x200821),\n                            _0x533f71) {\n                            _0x16c300 < -0x45 * -0x8a + -0x7a9 + -0x1d6b && (_0x4f59cf |= -0x239 + 0x3 * -0x458 + 0xf42 << _0x16c300);\n                            break;\n                        }\n                    }\n                } catch (_0x5c1c6e) {\n                    _0x37b937['e'](_0x5c1c6e);\n                } finally {\n                    _0x37b937['f']();\n                }\n            }\n            return _0x4f59cf[_0x2968a5(0x3ae)](-0xe97 + -0x183c + -0x1 * -0x26e3);\n        }\n\n        function _0x5090f5() {\n            var _0x458c87 = _0x5612de;\n            try {\n                new WebSocket(_0x458c87(0x199));\n            } catch (_0x34e866) {\n                return _0x34e866[_0x458c87(0x312)];\n            }\n        }\n\n        function _0x468d57() {\n            var _0x2ef0c5 = _0x5612de;\n            return eval[_0x2ef0c5(0x3ae)]()[_0x2ef0c5(0x259)];\n        }\n\n        function _0x5bbaf0() {\n            var _0x5ec561 = _0x5612de\n                , _0x5971d6 = window['RTCPeerConnection'] || window[_0x5ec561(0x2e0)] || window[_0x5ec561(0x19a)]\n                , _0x5aac87 = [];\n            return new Promise(function (_0x4e6ec1) {\n                    var _0x5af634 = _0x5ec561;\n                    (_0x176a57() || navigator[_0x5af634(0x229)][_0x5af634(0x202)]()[_0x5af634(0x2c5)](_0x5af634(0x20e)) > -0x707 + -0x106 * 0x10 + -0x1 * -0x1767) && _0x4e6ec1('');\n                    try {\n                        if (_0x5971d6 && 'function' == typeof _0x5971d6) {\n                            var _0xadabb6 = new _0x5971d6({\n                                'iceServers': [{\n                                    'urls': _0x5af634(0x27c)\n                                }]\n                            })\n                                , _0x4405e6 = function () {\n                            }\n                                , _0x4de1d1 = /([0-9]{1,3}(\\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/;\n                            _0xadabb6[_0x5af634(0x1eb)] = function () {\n                                var _0x374eb0 = _0x5af634;\n                                _0x374eb0(0x162) === _0xadabb6['iceGatheringState'] && (_0xadabb6[_0x374eb0(0x27a)](),\n                                    _0xadabb6 = null);\n                            }\n                                ,\n                                _0xadabb6['onicecandidate'] = function (_0x4e2717) {\n                                    var _0x18e62e = _0x5af634;\n                                    if (_0x4e2717 && _0x4e2717[_0x18e62e(0x227)] && _0x4e2717[_0x18e62e(0x227)][_0x18e62e(0x227)]) {\n                                        if ('' === _0x4e2717['candidate'][_0x18e62e(0x227)])\n                                            return;\n                                        var _0x1d1cd1 = _0x4de1d1['exec'](_0x4e2717[_0x18e62e(0x227)][_0x18e62e(0x227)]);\n                                        if (null !== _0x1d1cd1 && _0x1d1cd1[_0x18e62e(0x259)] > -0x1675 * 0x1 + -0x19 * 0xdd + 0x19 * 0x1c3) {\n                                            var _0xbaa956 = _0x1d1cd1[-0x1bdd * 0x1 + 0x13 * -0x1df + -0x11 * -0x3bb];\n                                            -(0x1 * -0x12c1 + -0xa * 0x38c + -0x4ee * -0xb) === _0x5aac87[_0x18e62e(0x2c5)](_0xbaa956) && _0x5aac87[_0x18e62e(0x36e)](_0xbaa956);\n                                        }\n                                    } else\n                                        _0x4e6ec1(_0x5aac87[_0x18e62e(0x24f)]());\n                                }\n                                ,\n                                _0xadabb6[_0x5af634(0x1e5)]('')\n                            // setTimeout(function () {\n                            //     var _0x36b72e = _0x5af634;\n                            //     _0x4e6ec1(_0x5aac87[_0x36b72e(0x24f)]());\n                            // }, 0x2205 * 0x1 + 0x1d4 * -0x10 + -0x67 * 0x7);\n                            var _0x38a358 = _0xadabb6[_0x5af634(0x2f5)]();\n                            _0x38a358 instanceof Promise ? _0x38a358[_0x5af634(0x1ed)](function (_0x33e26c) {\n                                return _0xadabb6['setLocalDescription'](_0x33e26c);\n                            })[_0x5af634(0x1ed)](_0x4405e6) : _0xadabb6['createOffer'](function (_0x1c6e51) {\n                                _0xadabb6['setLocalDescription'](_0x1c6e51, _0x4405e6, _0x4405e6);\n                            }, _0x4405e6);\n                        } else\n                            _0x4e6ec1('');\n                    } catch (_0x31debb) {\n                        _0x4e6ec1('');\n                    }\n                }\n            );\n        }\n\n        function _0x2e02ca() {\n            var _0x74cdcb = _0x5612de;\n            return _0x74cdcb(0x3af)[_0x74cdcb(0x377)](/[xy]/g, function (_0x5790dd) {\n                var _0x52f0b5 = _0x74cdcb\n                    ,\n                    _0x2eeaf3 = (0x506 + -0x85c + -0x2 * -0x1b3) * Math[_0x52f0b5(0x18e)]() | 0xbb9 * -0x1 + 0x1 * 0x9dd + 0x1dc;\n                return ('x' == _0x5790dd ? _0x2eeaf3 : -0xd1f * 0x1 + 0x1df6 + -0x1 * 0x10d4 & _0x2eeaf3 | 0x182d + -0x10 * 0x262 + -0xdfb * -0x1)[_0x52f0b5(0x3ae)](0x1a65 + 0x3 * 0x17a + 0x13b * -0x19);\n            });\n        }\n\n        function _0x2e2fa0(_0x1a6938) {\n            var _0x5aaa98 = _0x5612de;\n            return -0x14 * 0x1df + 0x649 + 0x1f45 === _0x1a6938[_0x5aaa98(0x259)] && _0x246aeb(-0x21ad + 0x819 * -0x1 + 0x29c6, _0x1a6938[_0x5aaa98(0x1b0)](-0x1a55 * 0x1 + 0x1279 + 0x7dc, 0x31b + -0xcb4 * -0x1 + -0xfaf))[_0x5aaa98(0x3ae)]()['substring'](0x17cc + 0x1 * -0xd19 + -0x3 * 0x391, -0x1ff * 0x1 + 0x2579 + -0x1c6 * 0x14) === _0x1a6938[_0x5aaa98(0x1b0)](0x1746 + 0x7b8 + -0x1ede, -0x369 * -0x2 + -0x5e5 * 0x4 + 0xbc * 0x17);\n        }\n\n        function _0x178d7c() {\n            var _0x4d5814 = _0x5612de\n                , _0x2d4341 = _0x24dc34(_0x4d5814(0x262));\n            return _0x2d4341 && _0x2e2fa0(_0x2d4341) || _0x1f42cb(_0x4d5814(0x262), _0x2d4341 = ((_0x2d4341 = _0x2e02ca()) + _0x246aeb(0x17 * 0x12d + -0x6 * 0x3f7 + -0x341, _0x2d4341))[_0x4d5814(0x1b0)](0x2d1 * -0xd + 0x3a * -0x7c + 0x40b5, 0x188e + 0x13 * -0x127 + -0x287)),\n                _0x2d4341;\n        }\n\n        function _0x3c0a68(_0x449fe8, _0x5ede0c) {\n            var _0x40bd5b = _0x5612de\n                , _0x401085 = null;\n            try {\n                _0x401085 = document['getElementsByTagName'](_0x40bd5b(0x221))[-0x2581 + 0x844 + -0x1d3d * -0x1];\n            } catch (_0x599ca4) {\n                _0x401085 = document['body'];\n            }\n            if (null !== _0x401085) {\n                var _0x3a3665 = document[_0x40bd5b(0x260)](_0x40bd5b(0x361))\n                    ,\n                    _0x215422 = '_' + parseInt((0x3df0 + 0x13d + -0x181d) * Math['random'](), 0x1 * -0x2141 + -0x1 * -0xf82 + 0x11c9) + '_' + new Date()[_0x40bd5b(0x16d)]();\n                _0x449fe8 += _0x40bd5b(0x1be) + _0x215422,\n                    _0x3a3665[_0x40bd5b(0x16b)] = _0x449fe8,\n                    window[_0x215422] = function (_0x1efd79) {\n                        var _0x4afb72 = _0x40bd5b;\n                        try {\n                            _0x5ede0c(_0x1efd79),\n                                _0x401085[_0x4afb72(0x30d)](_0x3a3665),\n                                delete window[_0x215422];\n                        } catch (_0xf98f95) {\n                        }\n                    }\n                    ,\n                    _0x401085[_0x40bd5b(0x26c)](_0x3a3665);\n            }\n        }\n\n        function _0x4072ad(_0x18cd85) {\n            return w_0x5c3140('484e4f4a403f524300022c395eafc0a4000000004a04440d00000030110104324700040700004202110100030443011400011100010211010102110102110104110001430207000143021842000200404f4c4d4a4b484946474445424340415e5f5c5d5a5b58595657546f6c6d6a6b686966676465626360617e7f7c7d7a7b78797677743e3f3c3d3a3b383936372320', {\n                get 0x0() {\n                    return _0x325f58;\n                },\n                get 0x1() {\n                    return _0x328bde;\n                },\n                get 0x2() {\n                    return _0xdda738;\n                },\n                0x3: arguments,\n                0x4: _0x18cd85\n            }, this);\n        }\n\n        function _0x5c0cdd(_0x380d2b, _0x1c644a) {\n            var _0x349270 = _0x5612de;\n            if (_0x1c644a) {\n                for (var _0x25fd23 = -0xbdc + -0xd78 * -0x2 + -0xf14, _0x2c655d = -0x1 * -0xbdb + 0xc2 + -0xc9d; _0x2c655d < _0x380d2b[_0x349270(0x259)]; _0x2c655d++)\n                    _0x380d2b[_0x2c655d]['p'] && (_0x380d2b[_0x2c655d]['r'] = _0x1c644a[_0x25fd23++]);\n            }\n            var _0x20da32 = '';\n            _0x380d2b[_0x349270(0x254)](function (_0x564ece) {\n                _0x20da32 += _0x5af46a(_0x564ece['r']) + '^^';\n            }),\n                _0x20da32 += _0x30c916();\n            var _0x2803a3 = _0x2e02ca()\n                ,\n                _0x273650 = Math[_0x349270(0x1cf)](_0x2803a3[_0x349270(0x195)](0x127a + 0x22e0 + -0x3557 * 0x1) / (0x1 * 0x199f + -0xab4 + -0x1 * 0xee3)) + _0x2803a3[_0x349270(0x195)](-0x15 * 0xca + -0x1ff6 * -0x1 + 0x1 * -0xf61) % (-0x1085 + -0x553 + 0x15e0)\n                ,\n                _0x102025 = _0x2803a3['substring'](0x1 * -0x1ebf + 0x13a1 + 0x1e * 0x5f, 0x5c7 + -0x5a5 + -0x5 * 0x6 + _0x273650);\n            _0x20da32 = _0x328bde(_0xdda738(_0x20da32, _0x102025) + _0x2803a3);\n            var _0x197e34 = _0x45ece5['fpProfileUrl'];\n            _0x3c0a68(_0x197e34 += _0x349270(0x173) + encodeURIComponent(_0x20da32) + '&', function (_0x5b4c95) {\n                var _0x3c0c48 = _0x349270;\n                0x1db6 + -0x21d * 0x1 + -0x1b99 == _0x5b4c95[_0x3c0c48(0x356)] && _0x5b4c95['fp'] && (_0x462335[_0x3c0c48(0x35f)] = _0x5b4c95['fp'],\n                    _0x462335[_0x3c0c48(0x363)] = _0x4072ad(_0x5b4c95['fp']),\n                    _0x1f42cb('tt_scid', _0x5b4c95['fp']));\n            });\n        }\n\n        function _0x1c3b6d(_0x20f8c9) {\n            var _0x596053 = _0x5612de;\n            return w_0x5c3140(_0x596053(0x242), {\n                get 0x0() {\n                    return navigator;\n                },\n                get 0x1() {\n                    return window;\n                },\n                get 0x2() {\n                    return document;\n                },\n                get 0x3() {\n                    return _0x30c916;\n                },\n                get 0x4() {\n                    return _0x1afbc2;\n                },\n                get 0x5() {\n                    return _0x18b4be;\n                },\n                get 0x6() {\n                    return _0x130155;\n                },\n                get 0x7() {\n                    return _0x2a76f8;\n                },\n                get 0x8() {\n                    return _0x3da279;\n                },\n                get 0x9() {\n                    return _0x299f3a;\n                },\n                get 0xa() {\n                    return _0x4649a1;\n                },\n                get 0xb() {\n                    return _0x487576;\n                },\n                get 0xc() {\n                    return _0x4f323e;\n                },\n                get 0xd() {\n                    return _0x1f9824;\n                },\n                get 0xe() {\n                    return _0x24dc34;\n                },\n                get 0xf() {\n                    return _0x5090f5;\n                },\n                get 0x10() {\n                    return _0x468d57;\n                },\n                get 0x11() {\n                    return _0x5bbaf0;\n                },\n                get 0x12() {\n                    return _0x45b94b;\n                },\n                get 0x13() {\n                    return _0x178d7c;\n                },\n                get 0x14() {\n                    return _0x5af46a;\n                },\n                0x15: Promise,\n                get 0x16() {\n                    return _0x5c0cdd;\n                },\n                0x17: arguments,\n                0x18: _0x20f8c9\n            }, this);\n        }\n\n        function _0x20cbf3(_0x38a8fe, _0x406d4b, _0x2e7a9b) {\n            var _0x1b116c = _0x5612de;\n            return w_0x5c3140(_0x1b116c(0x233), {\n                0x0: String,\n                0x1: Date,\n                get 0x2() {\n                    return _0x45b94b;\n                },\n                get 0x3() {\n                    return _0x184783;\n                },\n                get 0x4() {\n                    return location;\n                },\n                0x5: parseInt,\n                get 0x6() {\n                    return _0x5863d1;\n                },\n                0x7: JSON,\n                get 0x8() {\n                    return _0xf119da;\n                },\n                get 0x9() {\n                    return _0x3a1cf3;\n                },\n                get 0xa() {\n                    return _0x20b77a;\n                },\n                get 0xb() {\n                    return _0x446110;\n                },\n                0xc: Object,\n                get 0xd() {\n                    return _0x483e03;\n                },\n                get 0xe() {\n                    return _0x53f850;\n                },\n                get 0xf() {\n                    return _0x2a900b;\n                },\n                get 0x10() {\n                    return _0x18b4be;\n                },\n                get 0x11() {\n                    return _0x462335;\n                },\n                get 0x12() {\n                    return _0x4072ad;\n                },\n                get 0x13() {\n                    return _0x24dc34;\n                },\n                get 0x14() {\n                    return navigator;\n                },\n                0x15: arguments,\n                0x16: _0x38a8fe,\n                0x17: _0x406d4b,\n                0x18: _0x2e7a9b\n            }, this);\n        }\n\n        function _0x5e5a64(_0x27ec41, _0x4e1246) {\n            var _0x15a192 = _0x5612de;\n            for (var _0x3f84da = {}, _0x389521 = -0x4bd * -0x1 + -0x28a + -0x233; _0x389521 < _0x4e1246['length']; _0x389521++) {\n                var _0x58af98 = _0x4e1246[_0x389521]\n                    , _0x1b7f4e = _0x27ec41[_0x58af98];\n                null == _0x1b7f4e && (_0x1b7f4e = !(-0x1f76 + -0x1c06 + 0x3b7d * 0x1)),\n                null === _0x1b7f4e || 'function' != typeof _0x1b7f4e && _0x15a192(0x17d) !== _0x1db123(_0x1b7f4e) || (_0x1b7f4e = !(-0x2 * -0xef9 + -0xa1 * 0x3 + -0xb * 0x28d)),\n                    _0x3f84da[_0x58af98] = _0x1b7f4e;\n            }\n            return _0x3f84da;\n        }\n\n        function _0x2a6ac2() {\n            var _0x42b9bc = _0x5612de;\n            return _0x5e5a64(navigator, [_0x42b9bc(0x36b), 'appName', _0x42b9bc(0x17a), _0x42b9bc(0x246), _0x42b9bc(0x3a4), _0x42b9bc(0x360), _0x42b9bc(0x1fa), _0x42b9bc(0x33b), _0x42b9bc(0x38c), _0x42b9bc(0x212), 'vendorSub', 'doNotTrack', _0x42b9bc(0x24a), _0x42b9bc(0x2e2), _0x42b9bc(0x292), _0x42b9bc(0x390), _0x42b9bc(0x38f)]);\n        }\n\n        function _0x226933() {\n            var _0xe67fb0 = _0x5612de;\n            return _0x5e5a64(window, [_0xe67fb0(0x29d), _0xe67fb0(0x222), _0xe67fb0(0x306), _0xe67fb0(0x26e), _0xe67fb0(0x366), 'isSecureContext', _0xe67fb0(0x3c0), _0xe67fb0(0x399), 'locationbar', _0xe67fb0(0x29f), _0xe67fb0(0x39f), _0xe67fb0(0x2e0), 'postMessage', 'webkitRequestAnimationFrame', _0xe67fb0(0x2de), 'netscape']);\n        }\n\n        function _0x1e5a7f() {\n            var _0x577bf2 = _0x5612de;\n            return _0x5e5a64(document, [_0x577bf2(0x335), _0x577bf2(0x253), _0x577bf2(0x373), 'layers', _0x577bf2(0x2c0)]);\n        }\n\n        function _0x11a1d6() {\n            var _0x3927af = _0x5612de\n                , _0x306255 = document[_0x3927af(0x260)](_0x3927af(0x24d))\n                , _0x3b8708 = null;\n            try {\n                _0x3b8708 = _0x306255[_0x3927af(0x2f9)](_0x3927af(0x26b)) || _0x306255['getContext'](_0x3927af(0x3aa));\n            } catch (_0x30a5e5) {\n            }\n            return _0x3b8708 || (_0x3b8708 = null),\n                _0x3b8708;\n        }\n\n        function _0x39c3d8(_0xc6dcf6) {\n            var _0x59367a = _0x5612de\n                ,\n                _0x5a3a25 = _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x1f1)) || _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x2e5)) || _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x31a));\n            if (_0x5a3a25) {\n                var _0x5cca98 = _0xc6dcf6[_0x59367a(0x383)](_0x5a3a25[_0x59367a(0x1bf)]);\n                return 0xb * -0x2b8 + 0xa * 0xe + 0x1d5c === _0x5cca98 && (_0x5cca98 = -0xe6 + -0x1909 + -0xe5 * -0x1d),\n                    _0x5cca98;\n            }\n            return null;\n        }\n\n        function _0x425568() {\n            var _0x556a1e = _0x5612de;\n            if (_0x6caf[_0x556a1e(0x23d)])\n                return _0x6caf[_0x556a1e(0x23d)];\n            var _0x4f4b6e = _0x11a1d6();\n            if (!_0x4f4b6e)\n                return {};\n            var _0x58c017 = {\n                'supportedExtensions': _0x4f4b6e[_0x556a1e(0x30f)]() || [],\n                'antialias': _0x4f4b6e[_0x556a1e(0x1c5)]()[_0x556a1e(0x1a5)],\n                'blueBits': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x27e)]),\n                'depthBits': _0x4f4b6e['getParameter'](_0x4f4b6e[_0x556a1e(0x252)]),\n                'greenBits': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x3c3)]),\n                'maxAnisotropy': _0x39c3d8(_0x4f4b6e),\n                'maxCombinedTextureImageUnits': _0x4f4b6e['getParameter'](_0x4f4b6e[_0x556a1e(0x1d2)]),\n                'maxCubeMapTextureSize': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x300)]),\n                'maxFragmentUniformVectors': _0x4f4b6e['getParameter'](_0x4f4b6e['MAX_FRAGMENT_UNIFORM_VECTORS']),\n                'maxRenderbufferSize': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x2da)]),\n                'maxTextureImageUnits': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x269)]),\n                'maxTextureSize': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x203)]),\n                'maxVaryingVectors': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x264)]),\n                'maxVertexAttribs': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e['MAX_VERTEX_ATTRIBS']),\n                'maxVertexTextureImageUnits': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x205)]),\n                'maxVertexUniformVectors': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x19d)]),\n                'shadingLanguageVersion': _0x4f4b6e['getParameter'](_0x4f4b6e['SHADING_LANGUAGE_VERSION']),\n                'stencilBits': _0x4f4b6e['getParameter'](_0x4f4b6e['STENCIL_BITS']),\n                'version': _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e['VERSION'])\n            };\n            return _0x6caf[_0x556a1e(0x23d)] = _0x58c017,\n                _0x58c017;\n        }\n\n        function _0x18707d() {\n            var _0x52b59d = _0x5612de\n                , _0x56cb86 = {};\n            return _0x56cb86[_0x52b59d(0x270)] = _0x2a6ac2(),\n                _0x56cb86[_0x52b59d(0x393)] = _0x226933(),\n                _0x56cb86[_0x52b59d(0x208)] = _0x1e5a7f(),\n                _0x56cb86[_0x52b59d(0x26b)] = _0x425568(),\n                _0x56cb86[_0x52b59d(0x381)] = _0x487576(),\n                _0x56cb86['plugins'] = _0x1f9824(),\n                _0x6caf['SECINFO'] = _0x56cb86,\n                _0x56cb86;\n        }\n\n        function _0x572e48() {\n            var _0x151b17 = _0x5612de;\n            return w_0x5c3140(_0x151b17(0x1d1), {\n                get 0x0() {\n                    return _0x6caf;\n                },\n                get 0x1() {\n                    return _0x18707d;\n                },\n                0x2: Date,\n                get 0x3() {\n                    return _0x325f58;\n                },\n                get 0x4() {\n                    return _0x328bde;\n                },\n                get 0x5() {\n                    return _0xdda738;\n                },\n                0x6: JSON,\n                0x7: arguments\n            }, this);\n        }\n\n        var _0x522d20 = {\n            'kCallTypeDirect': 0x0,\n            'kCallTypeInterceptor': 0x1\n        }\n            , _0x2e10da = {\n            'kHttp': 0x0,\n            'kWebsocket': 0x1\n        }\n            , _0x3f742e = _0x45b94b;\n\n        function _0x5646fa(_0x29e841) {\n            var _0x2ecc2b = _0x5612de;\n            for (var _0x5d379d, _0x5e2317, _0x34abf7 = [], _0x448a08 = -0x25ac + 0x1 * -0x1a4 + -0x128 * -0x22; _0x448a08 < _0x29e841[_0x2ecc2b(0x259)]; _0x448a08++) {\n                _0x5d379d = _0x29e841[_0x2ecc2b(0x195)](_0x448a08),\n                    _0x5e2317 = [];\n                do {\n                    _0x5e2317[_0x2ecc2b(0x36e)](-0x8d * -0x3e + 0x24d * -0x1 + -0x1eda & _0x5d379d),\n                        _0x5d379d >>= -0x6d * 0x11 + 0x75 * 0x11 + 0x10 * -0x8;\n                } while (_0x5d379d);\n                _0x34abf7 = _0x34abf7[_0x2ecc2b(0x2b8)](_0x5e2317['reverse']());\n            }\n            return _0x34abf7;\n        }\n\n        function _0x6bc4ae(_0x4e8b7c) {\n        }\n\n        function _0x5b890d(_0x592717) {\n        }\n\n        function _0x16f345(_0x1a40af) {\n        }\n\n        function _0x361214(_0x426175) {\n        }\n\n        function _0xc35122(_0xe69c60, _0x3e14a1, _0x2d525a) {\n        }\n\n        var _0x5dde58 = {\n            'WEB_DEVICE_INFO': 0x8\n        };\n\n        function _0x4df596(_0x14c951, _0x4c06b0) {\n            var _0x3cd5a5 = _0x5612de;\n            return JSON[_0x3cd5a5(0x1e6)]({\n                'magic': 0x20200422,\n                'version': 0x1,\n                'dataType': _0x14c951,\n                'strData': _0x4c06b0,\n                'tspFromClient': new Date()[_0x3cd5a5(0x16d)]()\n            });\n        }\n\n        function _0x29a5ac(_0x1a16de, _0x1af868, _0x2e45c3, _0x2a9bcc) {\n            var _0x233cbb = _0x5612de;\n            return _0x32af0e(_0x233cbb(0x3a1), _0x1a16de, _0x1af868, _0x2e45c3, _0x2a9bcc);\n        }\n\n        function _0x32af0e(_0x58e2fa, _0x35c6ef, _0x5ce009, _0xba3041, _0x20e80f) {\n            var _0x393ad1 = _0x5612de\n                , _0x4841fc = new XMLHttpRequest();\n            if (_0x4841fc[_0x393ad1(0x18b)](_0x58e2fa, _0x35c6ef, !(-0xb * 0x8b + -0x233 + 0x82c)),\n            _0x20e80f && (_0x4841fc[_0x393ad1(0x1c6)] = !(0x1 * -0x260f + -0x2 * 0xcdf + 0x3fcd)),\n                _0xba3041)\n                for (var _0x3f91e1 = -0x2ce + -0x1 * 0xe0f + 0x10dd, _0x2f8bec = Object['keys'](_0xba3041); _0x3f91e1 < _0x2f8bec[_0x393ad1(0x259)]; _0x3f91e1++) {\n                    var _0x475f86 = _0x2f8bec[_0x3f91e1]\n                        , _0x42c2b4 = _0xba3041[_0x475f86];\n                    _0x4841fc[_0x393ad1(0x3ab)](_0x475f86, _0x42c2b4);\n                }\n            _0x4841fc[_0x393ad1(0x20a)](_0x5ce009);\n        }\n\n        function _0x2cd488(_0x751be6, _0x4c12d4) {\n            var _0x253a32 = _0x5612de;\n            return _0x4c12d4 || (_0x4c12d4 = null),\n            !!navigator['sendBeacon'] && (navigator[_0x253a32(0x24b)](_0x751be6, _0x4c12d4),\n                !(-0x1da1 + 0x1e93 + -0xf2));\n        }\n\n        function _0x4a2daf(_0x1ea426, _0x5a460b) {\n            var _0x22c57e = _0x5612de;\n            try {\n                window[_0x22c57e(0x1dc)] && window[_0x22c57e(0x1dc)][_0x22c57e(0x1c4)](_0x1ea426, _0x5a460b);\n            } catch (_0xe6e06d) {\n            }\n        }\n\n        function _0x34f60a(_0x1e7505) {\n            var _0x389acb = _0x5612de;\n            try {\n                window[_0x389acb(0x1dc)] && window[_0x389acb(0x1dc)][_0x389acb(0x2c3)](_0x1e7505);\n            } catch (_0x5daf1b) {\n            }\n        }\n\n        function _0x3d13cf(_0x3480fd) {\n            var _0x1ccc66 = _0x5612de;\n            try {\n                return window[_0x1ccc66(0x1dc)] ? window['localStorage']['getItem'](_0x3480fd) : null;\n            } catch (_0x3bb8f0) {\n                return null;\n            }\n        }\n\n        function _0x21db29(_0x584f42, _0xde0f43) {\n            var _0x4464a1 = _0x5612de;\n            for (var _0x2b8d40, _0x22bd9c = [], _0x13f024 = 0x1856 * 0x1 + -0x6a * 0x20 + -0x16 * 0x81, _0x5648fb = '', _0x4c41a3 = -0x2 * -0xc67 + -0xf91 + -0x5 * 0x1d9; _0x4c41a3 < -0x1 * -0x322 + -0x25ce + 0x23ac; _0x4c41a3++)\n                _0x22bd9c[_0x4c41a3] = _0x4c41a3;\n            for (var _0x4d4c13 = -0x18e4 + -0x3 * -0x10f + 0x15b7; _0x4d4c13 < -0x36a * -0x8 + 0x1cf7 + 0x126d * -0x3; _0x4d4c13++)\n                _0x13f024 = (_0x13f024 + _0x22bd9c[_0x4d4c13] + _0x584f42[_0x4464a1(0x195)](_0x4d4c13 % _0x584f42[_0x4464a1(0x259)])) % (-0x577 * 0x3 + 0x4eb + 0xc7a),\n                    _0x2b8d40 = _0x22bd9c[_0x4d4c13],\n                    _0x22bd9c[_0x4d4c13] = _0x22bd9c[_0x13f024],\n                    _0x22bd9c[_0x13f024] = _0x2b8d40;\n            var _0x11b95d = -0x7d8 + -0x256 + -0x517 * -0x2;\n            _0x13f024 = -0x1bef + -0xbc5 * -0x3 + -0x760 * 0x1;\n            for (var _0x15a79f = 0xd * 0x12e + 0x80 * -0x3d + 0xf2a; _0x15a79f < _0xde0f43[_0x4464a1(0x259)]; _0x15a79f++)\n                _0x13f024 = (_0x13f024 + _0x22bd9c[_0x11b95d = (_0x11b95d + (0x8ed + -0x1 * -0x836 + -0x22 * 0x81)) % (0x32b * 0x7 + 0x2311 + -0x2 * 0x1c1f)]) % (-0x1 * -0x106d + 0x35e * 0x5 + -0x2043),\n                    _0x2b8d40 = _0x22bd9c[_0x11b95d],\n                    _0x22bd9c[_0x11b95d] = _0x22bd9c[_0x13f024],\n                    _0x22bd9c[_0x13f024] = _0x2b8d40,\n                    _0x5648fb += String[_0x4464a1(0x1e2)](_0xde0f43[_0x4464a1(0x195)](_0x15a79f) ^ _0x22bd9c[(_0x22bd9c[_0x11b95d] + _0x22bd9c[_0x13f024]) % (0x179 * -0x7 + 0x2385 + -0x2 * 0xc1b)]);\n            return _0x5648fb;\n        }\n\n        var _0x45bf15 = _0x21db29\n            , _0x48a082 = {};\n\n        function _0x641e3d(_0x21dbac, _0x4a67ec) {\n            var _0x51016d = _0x5612de;\n            return w_0x5c3140(_0x51016d(0x3c4), {\n                0x0: String,\n                0x1: Math,\n                get 0x2() {\n                    return _0x45bf15;\n                },\n                get 0x3() {\n                    return _0x389396;\n                },\n                0x4: arguments,\n                0x5: _0x21dbac,\n                0x6: _0x4a67ec\n            }, this);\n        }\n\n        _0x48a082['pb'] = -0xd0f * -0x1 + 0xade * 0x2 + -0x22c9,\n            _0x48a082['json'] = 0x405 + -0x1 * -0xe59 + -0x125d;\n        var _0x216650 = {\n            'kNoMove': 0x2,\n            'kNoClickTouch': 0x4,\n            'kNoKeyboardEvent': 0x8,\n            'kMoveFast': 0x10,\n            'kKeyboardFast': 0x20,\n            'kFakeOperations': 0x40\n        }\n            , _0x5dc9cc = {\n            'sTm': 0x0,\n            'acc': 0x0\n        };\n\n        function _0x18a9f7() {\n            var _0x4e02b7 = _0x5612de;\n            try {\n                var _0x41737c = _0x3d13cf(_0x4e02b7(0x343));\n                _0x41737c ? Object[_0x4e02b7(0x2a0)](_0x5dc9cc, JSON[_0x4e02b7(0x3b1)](_0x41737c)) : (_0x5dc9cc[_0x4e02b7(0x293)] = new Date()[_0x4e02b7(0x16d)](),\n                    _0x5dc9cc[_0x4e02b7(0x27d)] = -0x175c + -0x1066 + 0x27c2);\n            } catch (_0x3da833) {\n                _0x5dc9cc[_0x4e02b7(0x293)] = new Date()[_0x4e02b7(0x16d)](),\n                    _0x5dc9cc[_0x4e02b7(0x27d)] = -0x1 * -0x1129 + -0x1f1f + -0x1 * -0xdf6,\n                    _0x26e186();\n            }\n        }\n\n        function _0x26e186() {\n            var _0x48e1a8 = _0x5612de;\n            _0x4a2daf(_0x48e1a8(0x343), JSON['stringify'](_0x5dc9cc));\n        }\n\n        var _0xf63a81 = {\n            'T_MOVE': 0x1,\n            'T_CLICK': 0x2,\n            'T_KEYBOARD': 0x3\n        }\n            , _0x2786f5 = !(0x1f31 * -0x1 + 0x1 * 0x22c7 + 0x83 * -0x7)\n            , _0x9fb121 = []\n            , _0x207cc5 = []\n            , _0x191fa5 = []\n            , _0xe06992 = {\n            'ubcode': 0x0\n        }\n            , _0x388856 = function (_0x4e0342, _0x5ca571) {\n            return _0x4e0342 + _0x5ca571;\n        }\n            , _0x20a3d9 = function (_0x2309ca) {\n            return _0x2309ca * _0x2309ca;\n        };\n\n        function _0x9c0be2(_0x232ed8, _0x432cf8) {\n            var _0x59688f = _0x5612de;\n            if (_0x232ed8[_0x59688f(0x259)] > 0x1 * 0xa93 + 0x1d7a + -0xd17 * 0x3 && _0x232ed8['splice'](0x1ab7 + 0x1 * -0x2147 + -0x1a4 * -0x4, 0x617 + 0x280 + 0x1 * -0x833),\n            _0x232ed8[_0x59688f(0x259)] > -0x1c57 + 0x1059 + 0xbfe) {\n                var _0x97b7e7 = _0x232ed8[_0x232ed8['length'] - (-0xc0e + 0xb26 * 0x2 + 0xa3d * -0x1)];\n                if (_0x432cf8['d'] - _0x97b7e7['d'] <= 0x5 * -0x1a3 + -0x91 * -0x32 + 0x5 * -0x407 || 'y' in _0x432cf8 && _0x432cf8['x'] === _0x97b7e7['x'] && _0x432cf8['y'] === _0x97b7e7['y'])\n                    return;\n            }\n            _0x232ed8[_0x59688f(0x36e)](_0x432cf8);\n        }\n\n        function _0x1d26db(_0x261f4b, _0x3c3c83, _0x131716) {\n            var _0x10f2ca = _0x5612de;\n            if (_0x462335['enableTrack']) {\n                if (_0x131716 !== _0xf63a81['T_MOVE'])\n                    return _0x131716 === _0xf63a81[_0x10f2ca(0x1f0)] ? (_0x261f4b[_0x10f2ca(0x259)] >= 0x1167 + -0x856 * -0x4 + 0x1 * -0x30cb && _0x450b73(),\n                        void _0x261f4b[_0x10f2ca(0x36e)](_0x3c3c83)) : _0x131716 === _0xf63a81[_0x10f2ca(0x355)] ? (_0x261f4b[_0x10f2ca(0x259)] > -0x1b6 * 0x16 + -0x115 * 0x17 + 0x11 * 0x3cb && _0x450b73(),\n                        void _0x261f4b['push'](_0x3c3c83)) : void (-0x15a4 + -0xc9f + 0x2243);\n                if (_0x261f4b['length'] >= -0x5b9 + -0x1b5 + -0x2 * -0x4b1 && _0x450b73(),\n                _0x261f4b[_0x10f2ca(0x259)] > 0x13e * 0x6 + 0x4a5 * -0x2 + 0x1d6) {\n                    var _0x40dc65 = _0x261f4b[_0x261f4b[_0x10f2ca(0x259)] - (-0x233e + 0x6bf + 0x1c80)]\n                        , _0x243563 = _0x40dc65['x']\n                        , _0x7ef629 = _0x40dc65['y']\n                        , _0x293666 = _0x40dc65['ts'];\n                    if (_0x243563 === _0x3c3c83['x'] && _0x7ef629 === _0x3c3c83['y'])\n                        return;\n                    if (_0x3c3c83['ts'] - _0x293666 < -0x1 * -0x9dc + -0x7 * -0x32d + -0x1e23)\n                        return;\n                }\n                _0x261f4b['push'](_0x3c3c83);\n            }\n        }\n\n        var _0x19ffaf = {\n            'init': 0x0,\n            'running': 0x1,\n            'exit': 0x2,\n            'flush': 0x3\n        };\n\n        function _0x450b73(_0xd6648d) {\n            var _0x5b1d4d = _0x5612de;\n            return w_0x5c3140(_0x5b1d4d(0x3a2), {\n                get 0x0() {\n                    return _0x6caf;\n                },\n                get 0x1() {\n                    return _0x19ffaf;\n                },\n                0x2: Date,\n                get 0x3() {\n                    return _0x5dc9cc;\n                },\n                get 0x4() {\n                    return _0x462335;\n                },\n                get 0x5() {\n                    return _0x26e186;\n                },\n                0x6: Object,\n                get 0x7() {\n                    return _0x4df596;\n                },\n                get 0x8() {\n                    return _0x5dde58;\n                },\n                get 0x9() {\n                    return _0x641e3d;\n                },\n                0xa: JSON,\n                get 0xb() {\n                    return _0x48a082;\n                },\n                get 0xc() {\n                    return _0x2cd488;\n                },\n                get 0xd() {\n                    return _0x29a5ac;\n                },\n                0xe: arguments,\n                0xf: _0xd6648d\n            }, this);\n        }\n\n        function _0x58c311() {\n            var _0x30dab3 = _0x5612de;\n            _0x462335[_0x30dab3(0x37f)] && _0x450b73(_0x19ffaf['exit']);\n        }\n\n        var _0x1a755e = {};\n        _0x1a755e[_0x5612de(0x2d4)] = _0x3dcfd5,\n            _0x1a755e['touchmove'] = _0x3dcfd5,\n            _0x1a755e[_0x5612de(0x364)] = _0x56114b,\n            _0x1a755e[_0x5612de(0x1d6)] = _0x19d89b,\n            _0x1a755e[_0x5612de(0x2d3)] = _0x19d89b;\n        var _0x18582a = !(0x1796 + -0xf7d + -0x818);\n\n        function _0x1dbe74() {\n            var _0x101f5b = _0x5612de;\n            if (document && document[_0x101f5b(0x2f6)] && !_0x18582a) {\n                for (var _0x1dfebe = 0x1 * -0xe36 + 0x6e8 + -0xa * -0xbb, _0x5af0b0 = Object[_0x101f5b(0x17f)](_0x1a755e); _0x1dfebe < _0x5af0b0[_0x101f5b(0x259)]; _0x1dfebe++) {\n                    var _0x2ecc3c = _0x5af0b0[_0x1dfebe];\n                    document[_0x101f5b(0x2f6)](_0x2ecc3c, _0x1a755e[_0x2ecc3c]);\n                }\n                _0x18582a = !(-0x1 * -0xfcb + 0x21 * 0x65 + -0x1cd0);\n            }\n        }\n\n        function _0x3dcfd5(_0x1f9f7e) {\n            var _0x4f99fd = _0x5612de\n                , _0x395631 = _0x1f9f7e\n                , _0x1f0c31 = _0x1f9f7e['type'];\n            _0x1f9f7e[_0x4f99fd(0x379)] && _0x4f99fd(0x299) === _0x1f0c31 && (_0x395631 = _0x1f9f7e['touches'][-0x9 * -0x3f4 + 0x1 * 0xc73 + -0x3007],\n                _0x2786f5 = !(-0x129a + 0x1bca + -0x930));\n            var _0x5d0e65 = {\n                'x': Math[_0x4f99fd(0x1cf)](_0x395631['clientX']),\n                'y': Math[_0x4f99fd(0x1cf)](_0x395631['clientY']),\n                'd': Date[_0x4f99fd(0x34d)]()\n            };\n            _0x9c0be2(_0x9fb121, _0x5d0e65),\n                _0x1d26db(_0x6caf[_0x4f99fd(0x21d)], {\n                    'ts': _0x5d0e65['d'],\n                    'x': _0x5d0e65['x'],\n                    'y': _0x5d0e65['y']\n                }, _0xf63a81[_0x4f99fd(0x2be)]);\n        }\n\n        function _0x56114b(_0x35e1c1) {\n            var _0x3de3de = _0x5612de\n                , _0x411a0a = 0x22e7 + -0x5 * -0x133 + -0x28e6;\n            (_0x35e1c1[_0x3de3de(0x28c)] || _0x35e1c1['ctrlKey'] || _0x35e1c1['metaKey'] || _0x35e1c1[_0x3de3de(0x22e)]) && (_0x411a0a = 0xe7c + -0x3 * 0x143 + -0xab2);\n            var _0x5239f5 = {\n                'x': _0x411a0a,\n                'd': Date['now']()\n            };\n            _0x9c0be2(_0x191fa5, _0x5239f5),\n                _0x1d26db(_0x6caf[_0x3de3de(0x391)], {\n                    'ts': _0x5239f5['d']\n                }, _0xf63a81[_0x3de3de(0x355)]);\n        }\n\n        function _0x19d89b(_0x39a86c) {\n            var _0x3bb659 = _0x5612de\n                , _0x4a9de2 = _0x39a86c\n                , _0x33eb04 = _0x39a86c['type'];\n            _0x39a86c[_0x3bb659(0x379)] && 'touchstart' === _0x33eb04 && (_0x4a9de2 = _0x39a86c['touches'][0x1491 + 0x1 * -0x1216 + -0x1 * 0x27b],\n                _0x2786f5 = !(-0x1 * -0x853 + 0x12df * 0x2 + -0x2e11));\n            var _0xf57aea = {\n                'x': Math['floor'](_0x4a9de2[_0x3bb659(0x2bf)]),\n                'y': Math[_0x3bb659(0x1cf)](_0x4a9de2['clientY']),\n                'd': Date['now']()\n            };\n            _0x9c0be2(_0x207cc5, _0xf57aea),\n                _0x1d26db(_0x6caf[_0x3bb659(0x3b6)], {\n                    'ts': _0xf57aea['d'],\n                    'x': _0xf57aea['x'],\n                    'y': _0xf57aea['y']\n                }, _0xf63a81[_0x3bb659(0x1f0)]);\n        }\n\n        function _0x42fe9b(_0x320405) {\n            var _0x2bf333 = _0x5612de;\n            return _0x320405['reduce'](_0x388856) / _0x320405[_0x2bf333(0x259)];\n        }\n\n        function _0x3ea7d6(_0xbdd4a6) {\n            var _0x1e5c1e = _0x5612de;\n            if (_0xbdd4a6[_0x1e5c1e(0x259)] <= -0x1 * -0x2420 + 0xc87 * -0x1 + 0x5e6 * -0x4)\n                return -0x1 * -0x309 + 0x15 * 0x9d + -0xfea * 0x1;\n            var _0x3deca4 = _0x42fe9b(_0xbdd4a6)\n                , _0x58472b = _0xbdd4a6['map'](function (_0x508d28) {\n                return _0x508d28 - _0x3deca4;\n            });\n            return Math[_0x1e5c1e(0x317)](_0x58472b['map'](_0x20a3d9)[_0x1e5c1e(0x376)](_0x388856) / (_0xbdd4a6[_0x1e5c1e(0x259)] - (0xa * 0x127 + -0x2103 + -0xe * -0x189)));\n        }\n\n        function _0x52f064(_0x2031c9, _0x5a5379, _0xb6ab78) {\n            var _0x1d0db5 = _0x5612de\n                , _0xcfe257 = 0xae8 + -0xb * -0x6f + -0xfad\n                , _0x4f9c60 = -0x894 + -0x12a7 + 0x1 * 0x1b3b;\n            if (_0x2031c9[_0x1d0db5(0x259)] > _0x5a5379) {\n                for (var _0x147b41 = [], _0x5ca0e0 = -0x10a8 + -0x212f + 0x3 * 0x109d; _0x5ca0e0 < _0x2031c9[_0x1d0db5(0x259)] - (0x557 * -0x7 + -0x5 * -0xc6 + 0x14a * 0x1a); _0x5ca0e0++) {\n                    var _0x2a170e = _0x2031c9[_0x5ca0e0 + (-0x20c6 * -0x1 + 0x1f31 + -0x3ff6)]\n                        , _0x1f8ecf = _0x2031c9[_0x5ca0e0]\n                        , _0x1b82ec = _0x2a170e['d'] - _0x1f8ecf['d'];\n                    _0x1b82ec && (_0xb6ab78 ? _0x147b41[_0x1d0db5(0x36e)]((0xf98 + 0x90f + 0x2 * -0xc53) / _0x1b82ec) : _0x147b41[_0x1d0db5(0x36e)](Math[_0x1d0db5(0x317)](_0x20a3d9(_0x2a170e['x'] - _0x1f8ecf['x']) + _0x20a3d9(_0x2a170e['y'] - _0x1f8ecf['y'])) / _0x1b82ec));\n                }\n                _0xcfe257 = _0x42fe9b(_0x147b41),\n                0x5 * -0x79d + 0xf2d * -0x1 + -0xeb * -0x3a === (_0x4f9c60 = _0x3ea7d6(_0x147b41)) && (_0x4f9c60 = 0xcc5 + -0x1 * -0x9e1 + -0x16a6 + 0.01);\n            }\n            return [_0xcfe257, _0x4f9c60];\n        }\n\n        function _0x26d461() {\n            var _0x3f77b6 = _0x5612de\n                , _0x5e9ee6 = !(0x9d * -0x6 + 0x16b0 + -0x1301)\n                , _0x499168 = -0x21e + -0x1b6a + 0x28 * 0xbd;\n            try {\n                document && document['createEvent'] && (document[_0x3f77b6(0x188)](_0x3f77b6(0x240)),\n                    _0x5e9ee6 = !(0x195e + -0x5 * -0x371 + -0x3f * 0xad));\n            } catch (_0x4b2baa) {\n            }\n            var _0x462d0a = _0x52f064(_0x9fb121, 0x6a * 0x2 + -0x1b * 0x16b + 0x2576)\n                , _0x136148 = _0x52f064(_0x191fa5, -0x94c + -0xd * 0x51 + 0xd6e, !(0x1 * 0x7ed + -0xab4 + 0x2c7))\n                , _0x17d8e6 = -0x2 * 0xb95 + -0xda0 + 0x24cb;\n            !_0x5e9ee6 && _0x2786f5 && (_0x17d8e6 |= 0x2468 + -0x1 * 0x2c2 + -0x2166,\n                _0x499168 |= _0x216650[_0x3f77b6(0x2f2)]),\n                -0x293 * -0x3 + 0x1 * 0xdad + -0x1566 === _0x9fb121['length'] ? (_0x17d8e6 |= -0x1cf3 * 0x1 + 0x12e1 + 0xa14,\n                    _0x499168 |= _0x216650[_0x3f77b6(0x2fe)]) : _0x462d0a[-0x17f8 + -0x1eae + 0x36a6] > 0xbab + -0x1fb9 + 0x3 * 0x6c0 && (_0x17d8e6 |= 0x20 * -0x5c + 0xb22 + 0x6e,\n                    _0x499168 |= _0x216650['kMoveFast']),\n            0x2297 * -0x1 + 0x57b * 0x3 + 0x65 * 0x2e === _0x207cc5['length'] && (_0x17d8e6 |= 0x15a5 + 0x557 + -0x1af8,\n                _0x499168 |= _0x216650['kNoClickTouch']),\n                0x20bb + 0x1e5f + 0x1f8d * -0x2 === _0x191fa5[_0x3f77b6(0x259)] ? (_0x17d8e6 |= -0x1 * 0x1b73 + -0x43e + 0x1fb9,\n                    _0x499168 |= _0x216650['kNoKeyboardEvent']) : _0x136148[0x16ee + -0x1 * 0x1e99 + 0x7ab] > 0x1 * 0xb77 + -0x82 + -0xaf5 + 0.5 && (_0x17d8e6 |= 0x176a + 0x183 + 0x7 * -0x38b,\n                    _0x499168 |= _0x216650[_0x3f77b6(0x3bf)]),\n                _0xe06992['ubcode'] = _0x499168;\n            var _0x9340b9 = _0x17d8e6[_0x3f77b6(0x3ae)](-0x2018 + -0x543 * 0x7 + 0x450d);\n            return 0xc8e * 0x1 + -0x3 * 0x3ca + -0x12f === _0x9340b9['length'] ? _0x9340b9 = '00' + _0x9340b9 : -0x117a + 0x19 * -0x57 + 0x8a9 * 0x3 === _0x9340b9[_0x3f77b6(0x259)] && (_0x9340b9 = '0' + _0x9340b9),\n                _0x9340b9;\n        }\n\n        function _0x5047d8() {\n            _0x450b73(-0x1b05 + 0x103 * 0x1c + -0x4 * 0x53);\n        }\n\n        function _0x4145f8(_0x30c511, _0x35c283) {\n            var _0x46d631 = _0x5612de;\n            for (var _0x3d95be = _0x35c283[_0x46d631(0x259)], _0x3c9714 = new ArrayBuffer(_0x3d95be + (-0x2ef * -0x2 + 0x1bbd + 0x2e * -0xbb)), _0x1054b9 = new Uint8Array(_0x3c9714), _0x5633c2 = -0x114 + -0x2096 + 0x21aa, _0x28d040 = 0x10a * -0x1a + 0x5 * 0x5cf + -0x207 * 0x1; _0x28d040 < _0x3d95be; _0x28d040++)\n                _0x1054b9[_0x28d040] = _0x35c283[_0x28d040],\n                    _0x5633c2 ^= _0x35c283[_0x28d040];\n            _0x1054b9[_0x3d95be] = _0x5633c2;\n            var _0x280d0b = -0xe * -0x98 + 0x1f * 0x9e + 0x6f * -0x3d & Math[_0x46d631(0x1cf)]((-0x1 * 0x13ed + -0x2 * 0x581 + 0x1fee) * Math[_0x46d631(0x18e)]())\n                , _0x418204 = String[_0x46d631(0x1e2)][_0x46d631(0x207)](null, _0x1054b9)\n                , _0x250194 = _0x21db29(String[_0x46d631(0x1e2)](_0x280d0b), _0x418204)\n                , _0x37237c = '';\n            return _0x37237c += String[_0x46d631(0x1e2)](_0x30c511),\n                _0x37237c += String[_0x46d631(0x1e2)](_0x280d0b),\n                _0x389396(_0x37237c += _0x250194, 's1');\n        }\n\n        function _0x1633f2(_0x48f290, _0x504655, _0x4fa808, _0x1a5c57, _0x3a4737) {\n            var _0x5a9e67 = _0x5612de;\n            _0x5863d1(),\n                _0x26d461(),\n            void (0x247a + -0x3f2 + -0x2088) !== _0x1a5c57 && '' !== _0x1a5c57 && (_0x1a5c57 = '');\n            var _0x21ca02 = _0x5dd467(_0x1a5c57);\n            _0x3a4737 || (_0x3a4737 = '00000000000000000000000000000000');\n            var _0x1fb174 = new ArrayBuffer(0x1cc4 + -0x1109 + -0x3e6 * 0x3)\n                , _0x1ffaa7 = new Uint8Array(_0x1fb174)\n                ,\n                _0xeefda2 = 0x22cb + 0x1 * -0x32c + 0x1f9f * -0x1 | _0x48f290 << -0x228e + 0x22f4 * 0x1 + -0x60 | _0x504655 << 0x1075 + -0x2c * -0x26 + -0x16f8 | (-0x261a + 0x1e95 + 0x786 & Math[_0x5a9e67(0x1cf)]((0x705 + 0x1069 + -0x3 * 0x7ae) * Math[_0x5a9e67(0x18e)]())) << 0x3f4 * 0x5 + 0x59a + -0x195a | -0x1 * -0x2033 + 0x284 * 0x5 + 0xeed * -0x3;\n            _0x6caf[_0x5a9e67(0x326)]++;\n            _0x6caf['envcode'] = 1\n            var _0x5eb39b = -0x55 + 0x8a3 + -0x80f & _0x6caf[_0x5a9e67(0x326)];\n            _0x1ffaa7[0x18e0 * 0x1 + 0xd8d + -0x266d] = _0x4fa808 << -0x1 * 0x1117 + -0x144f + 0x256c | _0x5eb39b,\n                _0x1ffaa7[-0x177d + 0x3 * 0xb39 + -0xa2d] = _0x6caf['envcode'] >> -0x163b + 0x2c3 + 0x1380 & 0x15b3 + -0x1efd + 0xa49 * 0x1,\n                _0x1ffaa7[-0x5e3 + -0x1 * 0x1535 + 0x1b1a * 0x1] = 0x64a + -0xc * 0xa3 + 0x259 & _0x6caf[_0x5a9e67(0x380)],\n                _0x1ffaa7[0x81 * 0x11 + 0xa49 * 0x1 + -0x12d7] = _0xe06992[_0x5a9e67(0x382)];\n            var _0x13f487 = _0x42e709[_0x5a9e67(0x2b7)](_0x5dd467(_0x42e709[_0x5a9e67(0x2b7)](_0x21ca02)));\n            _0x1ffaa7[-0xf6b * 0x2 + 0x1c4 + 0x1d16] = _0x13f487[-0x81a + -0x24ee + -0x18e * -0x1d],\n                _0x1ffaa7[0x73d * -0x3 + 0x2335 + -0x1 * 0xd79] = _0x13f487[-0x16 * -0x4 + -0xfdd + 0x3e5 * 0x4];\n            var _0x136ce1 = _0x42e709['decode'](_0x5dd467(_0x42e709['decode'](_0x3a4737)));\n            return _0x1ffaa7[0x17 * -0x35 + 0x220e + -0x1d45] = _0x136ce1[0xe7 * -0x11 + 0x1 * -0x17a1 + 0x2706],\n                _0x1ffaa7[0x1b8 + -0x2 * -0x665 + 0x151 * -0xb] = _0x136ce1[-0x276 * 0x9 + -0x1335 + -0x39 * -0xba],\n                _0x1ffaa7[0x1fa8 + 0x776 + 0x1 * -0x2716] = -0x23cd + -0x69d + 0x2b69 & Math[_0x5a9e67(0x1cf)]((0x9c + 0x77b * 0x4 + -0x1 * 0x1d89) * Math[_0x5a9e67(0x18e)]()),\n                _0x4145f8(_0xeefda2, _0x1ffaa7);\n        }\n\n        function _0x34c70a(_0xf6b3d0, _0x289075, _0x2c48ed) {\n            var _0x1fe583 = _0x5612de;\n            return {\n                'X-Bogus': _0x1633f2(_0x2e10da[_0x1fe583(0x289)], _0x462335['initialized'], _0xf6b3d0, null, _0x2c48ed)\n            };\n        }\n\n        function _0x11233a(_0x34d47b, _0x1b3ba5, _0x55dcd4) {\n            var _0x3e598d = _0x5612de;\n            return {\n                'X-Bogus': _0x1633f2(_0x2e10da[_0x3e598d(0x1df)], _0x462335[_0x3e598d(0x1fc)], _0x34d47b, _0x1b3ba5, _0x55dcd4)\n            };\n        }\n\n        function _0x5c2014(_0x1fa689) {\n            return w_0x5c3140('484e4f4a403f524300362d0a5f00233c0000000029b6a730000000630214000103001400020700001400030700011400041101031100031347000d11010311000313140001450023110103110004134700130211010011010311000413430114000145000607000214000102110101110002021100014303140005110005420003096b1e7e601e606766710c6b1e7e601e63726a7f7c7277200303030303030303030303030303030303030303030303030303030303030303', {\n                get 0x0() {\n                    return _0x5dd467;\n                },\n                get 0x1() {\n                    return _0x34c70a;\n                },\n                0x2: arguments,\n                0x3: _0x1fa689\n            }, this);\n        }\n\n        function _0x3c875d(_0x17e2b2, _0x1e7967) {\n            var _0x36f0c4 = _0x5612de\n                , _0x292251 = new Uint8Array(-0x1d76 + 0xa81 * -0x3 + 0x3cfc);\n            return _0x292251[0xff * 0x25 + 0x1ee0 * -0x1 + -0x5fb] = _0x17e2b2 / (0x1126 * -0x2 + -0x1 * 0x20f6 + -0x2 * -0x2221),\n                _0x292251[0x29 * -0xde + 0x25a6 + 0x6b * -0x5] = _0x17e2b2 % (-0x5 * 0x705 + 0x10bd + -0xb1 * -0x1c),\n                _0x292251[-0x1 * -0x1fb5 + -0x1921 + -0x692] = _0x1e7967 % (0x1615 + -0xda0 + 0x1 * -0x775),\n                String[_0x36f0c4(0x1e2)][_0x36f0c4(0x207)](null, _0x292251);\n        }\n\n        function _0x4b49f3(_0xe64465) {\n            var _0x2fa114 = _0x5612de;\n            return String[_0x2fa114(0x1e2)](_0xe64465);\n        }\n\n        function _0x26151b(_0x51896f, _0x3a647f, _0x2db6f6) {\n            return _0x4b49f3(_0x51896f) + _0x4b49f3(_0x3a647f) + _0x2db6f6;\n        }\n\n        function _0xc38697(_0x5bf566, _0x20667e) {\n            return _0x389396(_0x5bf566, _0x20667e);\n        }\n\n        function _0x538c80(_0x213380, _0x5bb06d, _0x2807a8, _0x2bbe8d, _0x43c759, _0x510d57, _0x5b433d, _0x30b81d, _0x392407, _0x124f15, _0x22fc4c, _0x56f654, _0x8ab411, _0x1c9de4, _0x24f978, _0x27f46c, _0x1bd4f9, _0x572854, _0x34f6a0) {\n            var _0x2e1799 = _0x5612de\n                , _0x432584 = new Uint8Array(0x22bb + 0xd * -0x2bd + 0x1 * 0xf1);\n            return _0x432584[-0xc70 + 0x5e9 + 0x22d * 0x3] = _0x213380,\n                _0x432584[-0x2 * -0x127c + -0x1 * 0x1f61 + -0x596] = _0x22fc4c,\n                _0x432584[-0x1af * 0xb + 0x97b + 0xc1 * 0xc] = _0x5bb06d,\n                _0x432584[-0xfc5 * -0x2 + -0x5e5 + -0x19a2] = _0x56f654,\n                _0x432584[-0x35 * 0xa3 + -0x10c9 * -0x2 + 0x1 * 0x31] = _0x2807a8,\n                _0x432584[0x1d1d + 0x124a + -0x1 * 0x2f62] = _0x8ab411,\n                _0x432584[-0x1 * -0xb49 + -0x5d1 + -0x572] = _0x2bbe8d,\n                _0x432584[-0x18e * -0xe + 0xff * 0x22 + -0x379b] = _0x1c9de4,\n                _0x432584[-0x697 * 0x2 + 0xcc8 + 0x5 * 0x16] = _0x43c759,\n                _0x432584[0x2 * 0x8bf + 0xcc4 + -0x1e39] = _0x24f978,\n                _0x432584[0x63 * -0x43 + -0x242 + 0x3 * 0x967] = _0x510d57,\n                _0x432584[0x1aa9 + 0xe38 + 0x1 * -0x28d6] = _0x27f46c,\n                _0x432584[-0xdee + -0x1 * 0x105b + 0x1e55 * 0x1] = _0x5b433d,\n                _0x432584[0x1 * -0x1543 + -0x1 * 0x1b5b + 0x1 * 0x30ab] = _0x1bd4f9,\n                _0x432584[0xc86 * -0x1 + 0x1c9 + 0xacb] = _0x30b81d,\n                _0x432584[0x1581 + -0x70c + -0xe66] = _0x572854,\n                _0x432584[0x1dc1 + 0xd * 0xb5 + -0x26e2] = _0x392407,\n                _0x432584[-0x36 * 0x4a + 0x268a + -0x16dd] = _0x34f6a0,\n                _0x432584[0xf * -0x1ca + -0x16c2 + 0x31aa] = _0x124f15,\n                String['fromCharCode'][_0x2e1799(0x207)](null, _0x432584);\n        }\n\n        var _0x3c4305 = !(-0xc6b + 0x270e * 0x1 + -0x1aa2);\n\n        function _0x8edc3d(_0x22218f, _0x1e70b9) {\n            var _0x364732 = _0x5612de;\n            return w_0x5c3140(_0x364732(0x2b2), {\n                get 0x0() {\n                    return _0x5dd467;\n                },\n                get 0x1() {\n                    return _0x3c4305;\n                },\n                set 0x1(_0x539e8c) {\n                    _0x3c4305 = _0x539e8c;\n                },\n                get 0x2() {\n                    return _0x462335;\n                },\n                get 0x3() {\n                    return _0x5863d1;\n                },\n                get 0x4() {\n                    return _0x26d461;\n                },\n                get 0x5() {\n                    return _0xe06992;\n                },\n                get 0x6() {\n                    return _0x6caf;\n                },\n                get 0x7() {\n                    return _0x42e709;\n                },\n                0x8: String,\n                get 0x9() {\n                    return navigator;\n                },\n                get 0xa() {\n                    return _0x3c875d;\n                },\n                get 0xb() {\n                    return _0x21db29;\n                },\n                get 0xc() {\n                    return _0xc38697;\n                },\n                0xd: Date,\n                get 0xe() {\n                    return _0x18b4be;\n                },\n                get 0xf() {\n                    return _0x538c80;\n                },\n                get 0x10() {\n                    return _0x4b49f3;\n                },\n                get 0x11() {\n                    return _0x26151b;\n                },\n                get 0x12() {\n                    return _0x389396;\n                },\n                0x13: arguments,\n                0x14: _0x22218f,\n                0x15: _0x1e70b9,\n                0x16: RegExp\n            }, this);\n        }\n\n        function _0x556182(_0x5e8c32) {\n            var _0x4a1328 = _0x5612de;\n            _0x4a2daf(_0x4a1328(0x28a), _0x5e8c32);\n        }\n\n        function _0x5141ac() {\n            var _0x2770a6 = _0x3d13cf('xmst');\n            return _0x2770a6 || '';\n        }\n\n        function _0x50686a(_0x193aca) {\n            var _0x460363 = _0x5612de;\n            return _0x460363(0x331) === Object[_0x460363(0x344)][_0x460363(0x3ae)][_0x460363(0x334)](_0x193aca);\n        }\n\n        function _0x2195cd(_0x383b5f, _0x4a7858) {\n            var _0x20b490 = _0x5612de;\n            if (_0x383b5f) {\n                var _0x11f5aa = _0x383b5f[_0x4a7858];\n                if (_0x11f5aa) {\n                    var _0x4fcde1 = _0x1db123(_0x11f5aa);\n                    return _0x20b490(0x17d) === _0x4fcde1 || _0x20b490(0x1ee) === _0x4fcde1 ? -0x1 * -0x4e8 + 0x18eb + -0x1dd2 : 'string' === _0x4fcde1 ? _0x4fcde1[_0x20b490(0x259)] > -0x124c + 0x20c3 + -0xe77 ? 0x35 * 0x34 + 0x1ec8 + -0x298b : -0x8a * 0x31 + -0x18c7 + -0x1111 * -0x3 : _0x50686a(_0x11f5aa) ? -0x1 * -0xc83 + -0x3 * 0x466 + 0x4 * 0x2c : 0x1018 + -0x371 * -0x9 + 0x1 * -0x2f0f;\n                }\n            }\n            return -0x155a + 0x4c * -0x6c + 0x4 * 0xd5b;\n        }\n\n        function _0xdc4d4c(_0x3c0aaa) {\n            var _0x11952c = _0x5612de;\n            try {\n                var _0x57243b = Object[_0x11952c(0x344)][_0x11952c(0x3ae)][_0x11952c(0x334)](_0x3c0aaa);\n                return _0x11952c(0x30e) === _0x57243b ? !(-0x1 * 0x7c5 + 0x1 * -0x853 + 0x338 * 0x5) === _0x3c0aaa ? -0xa1 * -0x23 + 0x2 * 0xaa9 + -0x2b54 : -0x1e71 * 0x1 + 0x1 * 0x1885 + 0x5ee : _0x11952c(0x1af) === _0x57243b ? -0xce * 0x25 + 0x1e1a + 0x3 * -0x1b : '[object\\x20Undefined]' === _0x57243b ? -0x1 * 0x159a + -0x684 + 0x1c22 : _0x11952c(0x1ce) === _0x57243b ? -0x3a * -0x70 + 0x4b1 + 0xa04 * -0x3 : '[object\\x20String]' === _0x57243b ? '' === _0x3c0aaa ? 0x12 * 0xad + 0x3b * 0x71 + -0x262e : 0x3 * 0xf8 + 0x22ec + -0x25cc : _0x11952c(0x331) === _0x57243b ? -0x1 * -0x874 + -0x1 * 0x2197 + 0x1923 === _0x3c0aaa['length'] ? -0xf6f + -0x1ee3 + 0x2e5b : -0x10c3 + -0x466 * -0x4 + 0x7 * -0x1d : _0x11952c(0x37b) === _0x57243b ? 0x1 * 0x22e6 + 0x1 * 0x2669 + 0x824 * -0x9 : _0x11952c(0x1fe) === _0x57243b ? 0x2392 + -0x15db + -0xdab : _0x11952c(0x17d) === _0x1db123(_0x3c0aaa) ? -0x3 * 0xd7 + -0x17b0 + 0x1a98 : -(-0x8e4 + 0x2 * 0xd1b + -0x1151);\n            } catch (_0x320465) {\n                return -(-0x62e * 0x1 + 0x3 * -0x3ec + 0x11f4);\n            }\n        }\n\n        var _0x2d8bb4 = {};\n\n        function _0x241339() {\n            var _0x5d55e6 = _0x5612de;\n            return document[_0x5d55e6(0x373)] ? 'IE' : -0xc04 + -0xbe8 + 0x17ec;\n        }\n\n        function _0x5011f8() {\n            var _0x52b3d6 = _0x5612de;\n            return eval['toString']()[_0x52b3d6(0x259)];\n        }\n\n        function _0x58210c(_0x4d43be, _0x3faa08, _0x3d51f5) {\n            var _0x16b761 = _0x5612de;\n            for (var _0x4738ee = {}, _0x793fa7 = 0x111 + -0x209 * 0x1 + 0x1f * 0x8; _0x793fa7 < _0x3faa08[_0x16b761(0x259)]; _0x793fa7++) {\n                var _0x15231e = void (-0xf02 * -0x1 + 0xe35 + -0x1d37)\n                    , _0x2d01fa = void (-0x782 + 0x5 * -0x143 + 0xdd1)\n                    , _0x17bcc5 = _0x3faa08[_0x793fa7];\n                try {\n                    _0x4d43be && (_0x15231e = _0x4d43be[_0x17bcc5]);\n                } catch (_0x1de94f) {\n                }\n                if ('string' === _0x3d51f5)\n                    _0x2d01fa = '' + _0x15231e;\n                else {\n                    if (_0x16b761(0x28b) === _0x3d51f5)\n                        _0x2d01fa = _0x15231e ? Math[_0x16b761(0x1cf)](_0x15231e) : -(-0x19f0 + 0x1ada + 0xe9 * -0x1);\n                    else {\n                        if (_0x16b761(0x1ab) !== _0x3d51f5)\n                            throw Error(_0x16b761(0x256));\n                        _0x2d01fa = _0xdc4d4c(_0x15231e);\n                    }\n                }\n                _0x4738ee[_0x17bcc5] = _0x2d01fa;\n            }\n            return _0x4738ee;\n        }\n\n        function _0x3a2b92() {\n            var _0x53dacb = _0x5612de, _0x1c216f;\n            Object[_0x53dacb(0x2a0)](_0x2d8bb4[_0x53dacb(0x270)], _0x58210c(navigator, [_0x53dacb(0x36b), _0x53dacb(0x350), _0x53dacb(0x184), 'appVersion', _0x53dacb(0x32d), 'doNotTrack', _0x53dacb(0x39a), _0x53dacb(0x38c), _0x53dacb(0x17a), _0x53dacb(0x246), 'productSub', 'cpuClass', _0x53dacb(0x212), _0x53dacb(0x1d5), _0x53dacb(0x1de), _0x53dacb(0x210), _0x53dacb(0x314), _0x53dacb(0x1c9), 'webdriver'], 'string')),\n                Object['assign'](_0x2d8bb4[_0x53dacb(0x270)], _0x58210c(navigator, [_0x53dacb(0x1e1), 'vibrate', _0x53dacb(0x2e2), _0x53dacb(0x292), _0x53dacb(0x390), _0x53dacb(0x38f)], _0x53dacb(0x1ab))),\n                Object[_0x53dacb(0x2a0)](_0x2d8bb4[_0x53dacb(0x270)], _0x58210c(navigator, [_0x53dacb(0x360), _0x53dacb(0x33b)], _0x53dacb(0x28b))),\n                _0x2d8bb4['navigator'][_0x53dacb(0x398)] = '' + navigator[_0x53dacb(0x398)];\n            try {\n                document[_0x53dacb(0x188)](_0x53dacb(0x240)),\n                    _0x1c216f = -0xa2 * -0x5 + 0x26 * -0xe8 + -0x11 * -0x1d7;\n            } catch (_0x264380) {\n                _0x1c216f = 0xbc0 + -0x26b + -0xd9 * 0xb;\n            }\n            _0x2d8bb4['navigator'][_0x53dacb(0x34b)] = _0x1c216f;\n            var _0x5ac61e = _0x53dacb(0x1ea) in window ? 0x2424 + 0x1 * 0xa5c + -0x2e7f : -0x86b * 0x1 + -0x195 + 0xa02;\n            _0x2d8bb4[_0x53dacb(0x270)][_0x53dacb(0x1d6)] = _0x5ac61e;\n        }\n\n        function _0x5abc93() {\n            var _0x279235 = _0x5612de;\n            Object['assign'](_0x2d8bb4['window'], _0x58210c(window, ['Image', _0x279235(0x309), _0x279235(0x29f), _0x279235(0x399), _0x279235(0x33a), 'external', 'mozRTCPeerConnection', 'postMessage', _0x279235(0x284), _0x279235(0x2de), _0x279235(0x2ff), _0x279235(0x1dc), _0x279235(0x3be), _0x279235(0x2e9)], _0x279235(0x1ab))),\n                Object[_0x279235(0x2a0)](_0x2d8bb4[_0x279235(0x393)], _0x58210c(window, [_0x279235(0x3c0)], _0x279235(0x28b))),\n                _0x2d8bb4[_0x279235(0x393)][_0x279235(0x3c2)] = window[_0x279235(0x3c2)][_0x279235(0x290)];\n        }\n\n        function _0x5d3845() {\n            var _0x4ceb6d = _0x5612de;\n            try {\n                var _0x55434c = document\n                    , _0x2f0012 = window[_0x4ceb6d(0x328)]\n                    , _0x5ac16c = window[_0x4ceb6d(0x306)] >>> 0x1d2c + -0x21 * 0xa7 + -0x1 * 0x7a5\n                    , _0x44cace = window[_0x4ceb6d(0x222)] >>> -0xcd0 + -0x1f70 + 0x162 * 0x20\n                    , _0x5953b9 = window[_0x4ceb6d(0x1aa)] >>> 0x5 * 0x2e3 + -0x1 * -0x1f7 + -0x1 * 0x1066\n                    , _0x1dfce9 = window[_0x4ceb6d(0x26d)] >>> 0x1545 + -0x8d7 + -0xc6e\n                    , _0x29911c = Math[_0x4ceb6d(0x1cf)](window['screenX'])\n                    , _0x340972 = Math['floor'](window[_0x4ceb6d(0x366)])\n                    , _0x4bc0b8 = window[_0x4ceb6d(0x258)] >>> -0x1 * -0x1548 + -0x21 * -0x7 + -0x162f\n                    , _0x39df7d = window[_0x4ceb6d(0x282)] >>> 0x1dc7 * 0x1 + -0x2113 + 0x34c\n                    , _0x13b30d = _0x2f0012['availWidth'] >>> 0xc84 + 0x1 * -0x644 + -0x640\n                    , _0x3f047e = _0x2f0012[_0x4ceb6d(0x276)] >>> -0x23c + 0xc * 0x1c4 + -0x12f4 * 0x1\n                    , _0x3e7595 = _0x2f0012['width'] >>> 0x61 * 0x4 + -0x2469 + 0x22e5 * 0x1\n                    , _0xa6e264 = _0x2f0012[_0x4ceb6d(0x245)] >>> 0x882 + 0x2646 + -0x5d9 * 0x8;\n                return {\n                    'innerWidth': void (-0xa40 + 0x192e + -0x31 * 0x4e) !== _0x5ac16c ? _0x5ac16c : -(0x135c + -0xd * -0x115 + -0x45 * 0x7c),\n                    'innerHeight': void (-0x2176 + -0x281 * -0xc + 0x17 * 0x26) !== _0x44cace ? _0x44cace : -(-0x17a1 + 0xe8 * 0x8 + 0x576 * 0x3),\n                    'outerWidth': void (-0x167c + -0x6f * 0x49 + 0x3623) !== _0x5953b9 ? _0x5953b9 : -(0x3 * -0x795 + 0x4 * -0x53b + 0x2bac),\n                    'outerHeight': void (-0x26 * -0x5f + -0xf71 + -0x1 * -0x157) !== _0x1dfce9 ? _0x1dfce9 : -(0xebd + -0x18cd + 0x3 * 0x35b),\n                    'screenX': void (-0xf9 * -0x22 + 0xd3 * -0x2c + 0x332) !== _0x29911c ? _0x29911c : -(-0x188 + -0x24e3 + 0x266c),\n                    'screenY': void (-0x5 * -0x105 + 0x2 * 0x11fe + -0x2915) !== _0x340972 ? _0x340972 : -(-0x3cc * -0x6 + 0x1561 * 0x1 + -0x2c28),\n                    'pageXOffset': void (0xb15 + -0x64d * 0x5 + -0x2 * -0xa36) !== _0x4bc0b8 ? _0x4bc0b8 : -(0x647 + -0x1 * -0x1ced + -0x2333),\n                    'pageYOffset': void (-0x1337 * 0x1 + -0x10c1 + -0x1 * -0x23f8) !== _0x39df7d ? _0x39df7d : -(0x3b * 0x5b + -0x7 * 0x3a6 + 0x492),\n                    'availWidth': void (-0xd * 0x267 + 0x1a67 + -0x2 * -0x26a) !== _0x13b30d ? _0x13b30d : -(0xe48 + -0x7d * -0x23 + -0x1f5e),\n                    'availHeight': void (-0x192a + 0x5 * -0x5b3 + 0xf1 * 0x39) !== _0x3f047e ? _0x3f047e : -(0x4 * 0x5b + -0x3 * -0x13 + -0x1a4),\n                    'sizeWidth': void (-0x1a38 * 0x1 + -0x20cb + 0x1 * 0x3b03) !== _0x3e7595 ? _0x3e7595 : -(-0x663 + -0x2659 + 0x2cbd * 0x1),\n                    'sizeHeight': void (0x857 * 0x3 + -0x65 * -0xa + -0x1cf7) !== _0xa6e264 ? _0xa6e264 : -(0xafa + 0x305 * 0x5 + -0x1a12),\n                    'clientWidth': _0x55434c['body'] ? _0x55434c[_0x4ceb6d(0x189)][_0x4ceb6d(0x1a2)] >>> -0xe38 + 0x1839 + -0xa01 : -(0x1338 + 0x21c1 + 0x69f * -0x8),\n                    'clientHeight': _0x55434c[_0x4ceb6d(0x189)] ? _0x55434c[_0x4ceb6d(0x189)][_0x4ceb6d(0x3bb)] >>> -0x1 * 0x156 + 0x31 * 0x43 + -0xb7d : -(0x1202 + -0x32b + -0xed6),\n                    'colorDepth': _0x2f0012[_0x4ceb6d(0x17e)] >>> -0x1d * -0xcb + 0x197 * 0x11 + 0x26 * -0x151,\n                    'pixelDepth': _0x2f0012[_0x4ceb6d(0x30a)] >>> -0x254c + 0x469 + 0x20e3 * 0x1\n                };\n            } catch (_0x35aa5a) {\n                return {};\n            }\n        }\n\n        function _0x573065() {\n            var _0x109cfa = _0x5612de;\n            Object[_0x109cfa(0x2a0)](_0x2d8bb4[_0x109cfa(0x208)], _0x58210c(document, [_0x109cfa(0x335), _0x109cfa(0x253), 'documentMode'], _0x109cfa(0x33c))),\n                Object['assign'](_0x2d8bb4[_0x109cfa(0x208)], _0x58210c(document, [_0x109cfa(0x325), _0x109cfa(0x183), 'images'], _0x109cfa(0x1ab)));\n        }\n\n        function _0x47f354() {\n            var _0xad51a5 = _0x5612de\n                , _0x5ad193 = {};\n            try {\n                var _0x344158 = document[_0xad51a5(0x260)](_0xad51a5(0x24d))[_0xad51a5(0x2f9)](_0xad51a5(0x26b))\n                    , _0x45ab53 = _0x344158[_0xad51a5(0x1d7)](_0xad51a5(0x375))\n                    , _0x3724de = _0x344158['getParameter'](_0x45ab53['UNMASKED_VENDOR_WEBGL'])\n                    , _0x41fa79 = _0x344158[_0xad51a5(0x383)](_0x45ab53[_0xad51a5(0x39e)]);\n                _0x5ad193['vendor'] = _0x3724de,\n                    _0x5ad193[_0xad51a5(0x2c2)] = _0x41fa79;\n            } catch (_0x22684e) {\n            }\n            return _0x5ad193;\n        }\n\n        function _0x58bcf8() {\n            var _0x3fa932 = _0x5612de\n                , _0xf9ae75 = _0x11a1d6();\n            if (_0xf9ae75) {\n                var _0x3c4406 = {\n                    'antialias': _0xf9ae75[_0x3fa932(0x1c5)]()[_0x3fa932(0x1a5)] ? -0x1d2e + -0x4b1 + 0x21e0 : -0x1 * -0x87c + 0x4b * 0x49 + -0x5 * 0x5f9,\n                    'blueBits': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x27e)]),\n                    'depthBits': _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x252)]),\n                    'greenBits': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['GREEN_BITS']),\n                    'maxAnisotropy': _0x39c3d8(_0xf9ae75),\n                    'maxCombinedTextureImageUnits': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_COMBINED_TEXTURE_IMAGE_UNITS']),\n                    'maxCubeMapTextureSize': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x300)]),\n                    'maxFragmentUniformVectors': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x286)]),\n                    'maxRenderbufferSize': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x2da)]),\n                    'maxTextureImageUnits': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_TEXTURE_IMAGE_UNITS']),\n                    'maxTextureSize': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x203)]),\n                    'maxVaryingVectors': _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x264)]),\n                    'maxVertexAttribs': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_VERTEX_ATTRIBS']),\n                    'maxVertexTextureImageUnits': _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x205)]),\n                    'maxVertexUniformVectors': _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x19d)]),\n                    'shadingLanguageVersion': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x179)]),\n                    'stencilBits': _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x2bb)]),\n                    'version': _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x201)])\n                };\n                Object['assign'](_0x2d8bb4['webgl'], _0x3c4406);\n            }\n            Object[_0x3fa932(0x2a0)](_0x2d8bb4[_0x3fa932(0x26b)], _0x47f354());\n        }\n\n        function _0x75957() {\n            var _0x122393 = _0x5612de;\n            if (window[_0x122393(0x29f)]) {\n                for (var _0x2963d5 = -0x81a + -0xad * -0x1 + 0x76f; _0x2963d5 < -0x1629 + 0x1 * 0x31c + 0x1317; _0x2963d5++)\n                    try {\n                        return !!new window[(_0x122393(0x29f))](_0x122393(0x3b4) + _0x2963d5) && _0x2963d5[_0x122393(0x3ae)]();\n                    } catch (_0x2c5722) {\n                    }\n                try {\n                    return !!new window[(_0x122393(0x29f))]('PDF.PdfCtrl.1') && '4';\n                } catch (_0x1be01e) {\n                }\n                try {\n                    return !!new window[(_0x122393(0x29f))](_0x122393(0x345)) && '7';\n                } catch (_0x19cffa) {\n                }\n            }\n            return '0';\n        }\n\n        function _0x1555d9() {\n            return {\n                'plugin': _0x30412e(),\n                'pv': _0x75957()\n            };\n        }\n\n        function _0x1f01ce(_0x371dd1) {\n            var _0x5c76bb = _0x5612de;\n            try {\n                var _0xf71d16 = window[_0x371dd1]\n                    , _0x28a4d1 = _0x5c76bb(0x1f9);\n                return _0xf71d16[_0x5c76bb(0x1c4)](_0x28a4d1, _0x28a4d1),\n                    _0xf71d16[_0x5c76bb(0x2c3)](_0x28a4d1),\n                    !(0x1e7a + -0x1824 + 0x2 * -0x32b);\n            } catch (_0x1dd803) {\n                return !(0x6e5 + 0x599 * -0x2 + -0x1 * -0x44e);\n            }\n        }\n\n        function _0x3ffe15() {\n            return w_0x5c3140('484e4f4a403f5243003c20117d3adeac000000004e770f390000003a030014000102110100070000430147000b11000103012f170001354902110100070001430147000e110001030103012b2f17000135491100014200020c45464a48457a5d465b484e4c0e5a4c5a5a4046477a5d465b484e4c', {\n                get 0x0() {\n                    return _0x1f01ce;\n                },\n                0x1: arguments\n            }, this);\n        }\n\n        function _0x252788(_0x468bb4, _0x392758, _0x269720) {\n            var _0x16947c = _0x5612de;\n            for (var _0x4dea11 = 0x1 * 0x1705 + 0x29 * -0xbf + 0x72 * 0x11, _0x1f88e5 = 0x65 * -0x7 + 0xb50 + -0x88d; _0x1f88e5 < _0x392758['length']; _0x1f88e5++) {\n                var _0x1dd5f9 = _0x2195cd(_0x468bb4, _0x392758[_0x1f88e5]);\n                if (_0x1dd5f9 && (_0x4dea11 |= _0x1dd5f9 << _0x269720 + _0x1f88e5,\n                _0x269720 + _0x1f88e5 >= 0xd5a + 0x7c + -0x1 * 0xdb6)) {\n                    console[_0x16947c(0x310)]('abort\\x2032');\n                    break;\n                }\n            }\n            return _0x4dea11;\n        }\n\n        function _0x484054() {\n            return w_0x5c3140('484e4f4a403f5243002c3b0a6f4f88290000000044c410000000011f1101001400010700000700010700020700030700040700050700060700070700080700090c000a14000207000a14000307000b14000407000a110101110004163e000414000a413d00d11100014a07000c1307000d43010300131400050c0000140006030014000711000711000207000e13274700691100014a07000f130700104301140008110002110007131400091100084a0700111307001207001311000918430249110004070014181100091807001518110008070016161100054a070017131100084301491100064a07001813110008430149170007214945ff891101011100041317000335490300170007354911000711000207000e132747001a1100054a0700191311000611000713430149170007214945ffd84111000342001a037e617e037e617d037e617c037e617b037e617a037e6179037e6178037e6177037e6176037d617f0014262b20213b242120382138272e3b263c3b27263c14282a3b0a232a222a213b3c0d361b2e28012e222a04272a2e2b06232a21283b270d2c3d2a2e3b2a0a232a222a213b063c2c3d263f3b0c3c2a3b0e3b3b3d262d3a3b2a08232e21283a2e282a0a052e392e1c2c3d263f3b02726d016d043b2a373b0b2e3f3f2a212b0c2726232b043f3a3c270b3d2a2220392a0c2726232b', {\n                get 0x0() {\n                    return document;\n                },\n                get 0x1() {\n                    return window;\n                },\n                0x2: arguments\n            }, this);\n        }\n\n        _0x2d8bb4[_0x5612de(0x270)] = {},\n            _0x2d8bb4[_0x5612de(0x23e)] = {},\n            _0x2d8bb4[_0x5612de(0x393)] = {},\n            _0x2d8bb4[_0x5612de(0x26b)] = {},\n            _0x2d8bb4['document'] = {},\n            _0x2d8bb4[_0x5612de(0x328)] = {},\n            _0x2d8bb4[_0x5612de(0x1ba)] = {},\n            _0x2d8bb4['custom'] = {};\n        var _0x548676 = null;\n\n        function _0x491716() {\n            var _0x4f58c9 = _0x5612de;\n            return w_0x5c3140(_0x4f58c9(0x174), {\n                get 0x0() {\n                    return self;\n                },\n                get 0x1() {\n                    return window;\n                },\n                get 0x2() {\n                    return parent;\n                },\n                0x3: arguments\n            }, this);\n        }\n\n        function _0x2d2578() {\n            !(function () {\n                var _0x236733 = w_0x25f3\n                    , _0x460c07 = {}\n                    , _0x3606e1 = navigator[_0x236733(0x359)] || navigator[_0x236733(0x2f0)];\n                if (_0x3606e1) {\n                    try {\n                        _0x460c07[_0x236733(0x3ac)] = _0x3606e1[_0x236733(0x3ac)] ? 0x147a + -0x5 * 0x60f + 0x9d2 : -0x169c + 0x26d6 + -0x1038,\n                            _0x460c07[_0x236733(0x213)] = Math[_0x236733(0x369)]((0x31 * 0x75 + 0x14c7 + -0x2ac8) * _0x3606e1[_0x236733(0x213)]),\n                            _0x460c07[_0x236733(0x2b0)] = '' + _0x3606e1[_0x236733(0x2b0)],\n                            _0x460c07[_0x236733(0x191)] = '' + _0x3606e1['dischargingTime'];\n                    } catch (_0x2c301c) {\n                    }\n                    _0x2d8bb4[_0x236733(0x359)] = {},\n                        Object[_0x236733(0x2a0)](_0x2d8bb4[_0x236733(0x359)], _0x460c07);\n                } else {\n                    if (_0x236733(0x384) != typeof navigator && navigator[_0x236733(0x1b2)])\n                        try {\n                            navigator[_0x236733(0x1b2)]()[_0x236733(0x1ed)](function (_0x369fc5) {\n                                var _0x34e3e9 = _0x236733;\n                                try {\n                                    _0x460c07[_0x34e3e9(0x3ac)] = _0x369fc5[_0x34e3e9(0x3ac)] ? 0x20aa + -0x11 * -0x86 + 0x1 * -0x298f : 0xd51 + 0x152c + 0xd * -0x2a7,\n                                        _0x460c07[_0x34e3e9(0x213)] = Math[_0x34e3e9(0x369)]((0x1205 + -0x41 * 0x32 + -0x3 * 0x1a5) * _0x369fc5[_0x34e3e9(0x213)]),\n                                        _0x460c07[_0x34e3e9(0x2b0)] = '' + _0x369fc5[_0x34e3e9(0x2b0)],\n                                        _0x460c07[_0x34e3e9(0x191)] = '' + _0x369fc5['dischargingTime'];\n                                } catch (_0x2f63d1) {\n                                }\n                                _0x2d8bb4['battery'] = {},\n                                    Object[_0x34e3e9(0x2a0)](_0x2d8bb4[_0x34e3e9(0x359)], _0x460c07);\n                            });\n                        } catch (_0xfc012d) {\n                        }\n                }\n            }()),\n            'undefined' != typeof Promise && (_0x548676 = new Promise(function (_0x1df02e) {\n                    try {\n                        _0x5bbaf0()['then'](function (_0x27ab47) {\n                            var _0xbee19f = w_0x25f3;\n                            Object[_0xbee19f(0x2a0)](_0x2d8bb4['wID'], {\n                                'rtcIP': _0x27ab47\n                            });\n                        });\n                    } catch (_0x7bc12a) {\n                    }\n                    _0x1df02e('');\n                }\n            ));\n        }\n\n        function _0x5c328e() {\n            var _0x378ae2 = _0x5612de;\n            return w_0x5c3140(_0x378ae2(0x1ad), {\n                get 0x0() {\n                    return window;\n                },\n                get 0x1() {\n                    return navigator;\n                },\n                get 0x2() {\n                    var _0xa78dc5 = _0x378ae2;\n                    return _0xa78dc5(0x384) != typeof InstallTrigger ? InstallTrigger : void (0x26ae * 0x1 + -0xad * 0x2e + -0x6c * 0x12);\n                },\n                0x3: Object,\n                get 0x4() {\n                    return _0x241339;\n                },\n                get 0x5() {\n                    return _0x2d8bb4;\n                },\n                get 0x6() {\n                    return document;\n                },\n                0x7: Promise,\n                0x8: Date,\n                get 0x9() {\n                    return _0x252788;\n                },\n                get 0xa() {\n                    return _0x5011f8;\n                },\n                get 0xb() {\n                    return _0x4f323e;\n                },\n                get 0xc() {\n                    return _0x5090f5;\n                },\n                0xd: Math,\n                get 0xe() {\n                    return _0x3ffe15;\n                },\n                get 0xf() {\n                    return _0x18b4be;\n                },\n                get 0x10() {\n                    return _0x484054;\n                },\n                get 0x11() {\n                    return _0x491716;\n                },\n                get 0x12() {\n                    return _0x462335;\n                },\n                get 0x13() {\n                    return _0x24dc34;\n                },\n                get 0x14() {\n                    return _0x6caf;\n                },\n                get 0x15() {\n                    return _0x2d2578;\n                },\n                get 0x16() {\n                    return _0x3a2b92;\n                },\n                get 0x17() {\n                    return _0x5abc93;\n                },\n                get 0x18() {\n                    return _0x573065;\n                },\n                get 0x19() {\n                    return _0x58bcf8;\n                },\n                get 0x1a() {\n                    return _0x1555d9;\n                },\n                get 0x1b() {\n                    return _0x5d3845;\n                },\n                0x1c: parseInt,\n                get 0x1d() {\n                    return _0x3d13cf;\n                },\n                get 0x1e() {\n                    return _0x4a2daf;\n                },\n                get 0x1f() {\n                    return _0x641e3d;\n                },\n                0x20: JSON,\n                get 0x21() {\n                    return _0x48a082;\n                },\n                get 0x22() {\n                    return _0x4df596;\n                },\n                get 0x23() {\n                    return _0x5dde58;\n                },\n                get 0x24() {\n                    return _0x548676;\n                },\n                get 0x25() {\n                    return _0x29a5ac;\n                },\n                0x26: arguments\n            }, this);\n        }\n\n        function _0x25a792(_0x2f25f2) {\n            var _0x329005 = _0x5612de;\n            return _0x462335[_0x329005(0x185)] && _0x462335[_0x329005(0x185)][_0x329005(0x2dc)] && -(-0x4f2 * 0x5 + 0x254f + -0xc94) !== _0x2f25f2[_0x329005(0x2c5)](_0x462335[_0x329005(0x185)][_0x329005(0x2dc)]) ? _0x39693d['sec'] : _0x39693d[_0x329005(0x1b4)];\n        }\n\n        function _0xd287a1(_0x35260d) {\n            var _0x241816 = _0x5612de\n                , _0x40ac17 = _0x462335[_0x241816(0x185)][_0x241816(0x2dc)];\n            return !(!_0x40ac17 || !_0x35260d || -(0x116 * -0x2 + -0x1af8 * -0x1 + -0x18cb) === _0x35260d[_0x241816(0x2c5)](_0x40ac17));\n        }\n\n        function _0x2b13af(_0x52c947) {\n            var _0x221375 = _0x5612de\n                , _0x7eff84 = _0x52c947;\n            decodeURIComponent(_0x52c947) === _0x52c947 && (_0x7eff84 = encodeURI(_0x52c947));\n            var _0x5e1d88 = _0x7eff84[_0x221375(0x2c5)]('?');\n            if (_0x5e1d88 > 0x1673 * 0x1 + 0x2150 + -0x37c3) {\n                var _0xc7170 = _0x7eff84[_0x221375(0x3a7)](-0x80c + 0x71e * 0x2 + -0x630, _0x5e1d88 + (0x2 * 0x919 + 0x4 * -0x931 + 0x1293))\n                    , _0x8fbad9 = _0x7eff84[_0x221375(0x3a7)](_0x5e1d88 + (-0x1de4 + -0x2 * -0x1163 + 0x4e1 * -0x1));\n                _0x7eff84 = _0xc7170 + _0x8fbad9[_0x221375(0x342)]('\\x27')['join'](_0x221375(0x37e));\n            }\n            return _0x7eff84;\n        }\n\n        function _0x1958a5(_0x42413b, _0x5e3de6) {\n            var _0x406220 = _0x5612de;\n            for (var _0x32045a = '', _0xbe63df = '', _0x5623ae = 0x5f6 + -0x220e + 0x1c18; _0x5623ae < _0x5e3de6[_0x406220(0x259)]; _0x5623ae++)\n                _0x5623ae % (0x951 + 0xb15 + 0x105 * -0x14) == -0x10de + 0x15 * 0x185 + 0x1 * -0xf0b ? _0xbe63df = _0x5e3de6[_0x5623ae] : _0x32045a += '&' + _0xbe63df + '=' + _0x5e3de6[_0x5623ae];\n            var _0x4ddc33 = _0x42413b;\n            if (_0x32045a[_0x406220(0x259)] > -0x135d + 0x8e1 + -0x2c * -0x3d) {\n                var _0x50fb42 = -(0x2 * -0x1252 + 0x13 * 0x85 + 0x95 * 0x2e) === _0x42413b['indexOf']('?') ? '?' : '&';\n                _0x4ddc33 = _0x42413b + _0x50fb42 + _0x32045a[_0x406220(0x3a7)](0x324 + -0xf1 * -0x17 + 0x1 * -0x18ca);\n            }\n            return _0x4ddc33;\n        }\n\n        function _0x288415(_0x5a419e) {\n            var _0x259f53 = _0x5612de\n                , _0x4465ef = _0x5a419e['indexOf']('?');\n            return -(-0x78c + -0x1a4c + -0x6c5 * -0x5) !== _0x4465ef ? _0x5a419e[_0x259f53(0x3a7)](_0x4465ef + (0x907 + 0x137b * 0x1 + -0x1c81)) : '';\n        }\n\n        function _0x6a7375(_0x2a9a57) {\n            var _0x447596 = _0x5612de;\n            for (var _0x1ca622 = -0x16a3 * -0x1 + 0x87b + -0x1f1e; _0x1ca622 < _0x462335['_enablePathListRegex']['length']; _0x1ca622++)\n                if (_0x462335[_0x447596(0x1a9)][_0x1ca622]['test'](_0x2a9a57))\n                    return !(-0x5ed + -0x3d * -0x41 + -0x990);\n            return !(-0x1 * -0x26ff + -0x11c1 * 0x1 + -0x153d);\n        }\n\n        function _0x7d8404(_0x34967f) {\n            var _0x5e578e = _0x5612de;\n            return _0x5e578e(0x186) === _0x34967f || 'application/json' === _0x34967f;\n        }\n\n        function _0x3af1be() {\n            var _0x1347f7 = _0x5612de;\n            return w_0x5c3140(_0x1347f7(0x368), {\n                get 0x0() {\n                    return window;\n                },\n                get 0x1() {\n                    return _0x6a7375;\n                },\n                get 0x2() {\n                    return _0x6caf;\n                },\n                get 0x3() {\n                    return _0x1958a5;\n                },\n                get 0x4() {\n                    return _0x2b13af;\n                },\n                get 0x5() {\n                    return _0x288415;\n                },\n                get 0x6() {\n                    return _0x8edc3d;\n                },\n                get 0x7() {\n                    return _0x462335;\n                },\n                get 0x8() {\n                    return _0x45e0e9;\n                },\n                get 0x9() {\n                    return _0x7d8404;\n                },\n                get 0xa() {\n                    return _0x1294ff;\n                },\n                get 0xb() {\n                    return _0x20cbf3;\n                },\n                get 0xc() {\n                    return _0x45b94b;\n                },\n                get 0xd() {\n                    return _0x572e48;\n                },\n                get 0xe() {\n                    return _0xd287a1;\n                },\n                get 0xf() {\n                    return _0x25a792;\n                },\n                get 0x10() {\n                    return _0x39693d;\n                },\n                get 0x11() {\n                    return _0x1f42cb;\n                },\n                get 0x12() {\n                    return _0x556182;\n                },\n                get 0x13() {\n                    return setTimeout;\n                },\n                get 0x14() {\n                    return _0x5c328e;\n                },\n                0x15: arguments,\n                0x16: RegExp\n            }, this);\n        }\n\n        var _0x3c4266 = _0x5612de(0x384) != typeof URL && URL instanceof Object\n            , _0x3311d7 = 'undefined' != typeof Request && Request instanceof Object\n            , _0x4f1fa4 = 'undefined' != typeof Headers && Headers instanceof Object;\n\n        function _0x415adb() {\n            var _0x51ab32 = _0x5612de;\n            return window[_0x51ab32(0x197)];\n        }\n\n        function _0x1d82ac() {\n            var _0x2340b7 = _0x5612de;\n            return w_0x5c3140(_0x2340b7(0x234), {\n                get 0x0() {\n                    return _0x415adb;\n                },\n                get 0x1() {\n                    return window;\n                },\n                get 0x2() {\n                    return _0xd287a1;\n                },\n                get 0x3() {\n                    return _0x25a792;\n                },\n                get 0x4() {\n                    return _0x39693d;\n                },\n                get 0x5() {\n                    return _0x6caf;\n                },\n                get 0x6() {\n                    return _0x1f42cb;\n                },\n                get 0x7() {\n                    return _0x556182;\n                },\n                get 0x8() {\n                    return setTimeout;\n                },\n                get 0x9() {\n                    return _0x5c328e;\n                },\n                get 0xa() {\n                    return _0x3311d7;\n                },\n                get 0xb() {\n                    return Request;\n                },\n                get 0xc() {\n                    return _0x3c4266;\n                },\n                get 0xd() {\n                    return URL;\n                },\n                get 0xe() {\n                    return _0x6a7375;\n                },\n                get 0xf() {\n                    return _0x1958a5;\n                },\n                get 0x10() {\n                    return _0x2b13af;\n                },\n                get 0x11() {\n                    return _0x288415;\n                },\n                get 0x12() {\n                    return _0x8edc3d;\n                },\n                get 0x13() {\n                    return _0x462335;\n                },\n                get 0x14() {\n                    return _0x45e0e9;\n                },\n                get 0x15() {\n                    return _0xb48e77;\n                },\n                get 0x16() {\n                    return _0x7d8404;\n                },\n                get 0x17() {\n                    return _0x1294ff;\n                },\n                get 0x18() {\n                    return _0x20cbf3;\n                },\n                get 0x19() {\n                    return _0x45b94b;\n                },\n                get 0x1a() {\n                    return _0x572e48;\n                },\n                0x1b: arguments\n            }, this);\n        }\n\n        function _0xb48e77(_0x29caaf, _0xa4ab82) {\n            var _0x1cf8d6 = _0x5612de\n                , _0x314297 = '';\n            if (_0x3311d7 && _0x29caaf instanceof Request) {\n                var _0x1f374d = _0x29caaf[_0x1cf8d6(0x35b)][_0x1cf8d6(0x32b)](_0x1cf8d6(0x228));\n                return _0x1f374d && (_0x314297 = _0x1f374d),\n                    _0x314297;\n            }\n            if (_0xa4ab82 && _0xa4ab82[_0x1cf8d6(0x35b)]) {\n                if (_0x4f1fa4 && _0xa4ab82[_0x1cf8d6(0x35b)] instanceof Headers) {\n                    var _0x4dff82 = _0xa4ab82[_0x1cf8d6(0x35b)][_0x1cf8d6(0x32b)](_0x1cf8d6(0x228));\n                    return _0x4dff82 && (_0x314297 = _0x4dff82),\n                        _0x314297;\n                }\n                if (_0xa4ab82['headers'] instanceof Array) {\n                    for (var _0x6ae47c = 0xd20 + 0x699 * -0x5 + -0x13dd * -0x1; _0x6ae47c < _0xa4ab82['headers'][_0x1cf8d6(0x259)]; _0x6ae47c++)\n                        if (_0x1cf8d6(0x228) == _0xa4ab82[_0x1cf8d6(0x35b)][_0x6ae47c][-0x12f6 + -0x207f + 0x1127 * 0x3]['toLowerCase']())\n                            return _0xa4ab82[_0x1cf8d6(0x35b)][_0x6ae47c][-0xaa2 + -0xe0e + 0x18b1];\n                }\n                if (_0xa4ab82[_0x1cf8d6(0x35b)] instanceof Object) {\n                    for (var _0x1506c8 = -0x1ce4 + 0x8dc + 0xa04 * 0x2, _0x32fecb = Object['keys'](_0xa4ab82['headers']); _0x1506c8 < _0x32fecb[_0x1cf8d6(0x259)]; _0x1506c8++) {\n                        var _0x228b3d = _0x32fecb[_0x1506c8];\n                        if ('content-type' === _0x228b3d['toLowerCase']())\n                            return _0xa4ab82[_0x1cf8d6(0x35b)][_0x228b3d];\n                    }\n                    return _0x314297;\n                }\n            }\n        }\n\n        function _0x1294ff(_0x1475ff, _0x5700d1, _0x563b6f) {\n            var _0x383b2a = _0x5612de;\n            if (null == _0x563b6f || '' === _0x563b6f)\n                return _0x1475ff;\n            if (_0x563b6f = _0x563b6f[_0x383b2a(0x3ae)](),\n            _0x383b2a(0x186) === _0x5700d1) {\n                _0x1475ff[_0x383b2a(0x336)] = !(0xfc + -0x22d4 + 0x21d8);\n                var _0x38ceac = _0x563b6f[_0x383b2a(0x342)]('&')\n                    , _0x1b01b6 = {};\n                if (_0x38ceac) {\n                    for (var _0x4c4745 = -0x29 * -0xd3 + 0x1 * 0xa01 + -0x2bcc; _0x4c4745 < _0x38ceac['length']; _0x4c4745++)\n                        _0x1b01b6[_0x38ceac[_0x4c4745][_0x383b2a(0x342)]('=')[0x2 * -0x391 + -0x1 * -0x99f + -0x27d]] = decodeURIComponent(_0x38ceac[_0x4c4745][_0x383b2a(0x342)]('=')[0x1e44 + -0x14e3 * -0x1 + -0x3326]);\n                }\n                _0x1475ff[_0x383b2a(0x189)] = _0x1b01b6;\n            } else\n                _0x1475ff[_0x383b2a(0x189)] = JSON['parse'](_0x563b6f);\n            return _0x1475ff;\n        }\n\n        function _0x45e0e9(_0x2d3284, _0xb8d78) {\n            var _0x521f3f = _0x5612de\n                , _0x3496a3 = _0xb8d78;\n            if (_0x462335[_0x521f3f(0x18d)][_0x521f3f(0x259)] > 0x1f8f * 0x1 + -0x1 * 0x21dd + 0xa * 0x3b)\n                for (var _0x335ec5 = 0xb * -0xd3 + -0x1977 * 0x1 + -0x41 * -0x88; _0x335ec5 < _0x462335[_0x521f3f(0x18d)][_0x521f3f(0x259)]; _0x335ec5++) {\n                    var _0x3f8686 = _0x462335[_0x521f3f(0x18d)][_0x335ec5][-0x2023 + 0xcb * -0x10 + -0x1cb * -0x19];\n                    if (_0x3f8686[_0x521f3f(0x22b)](_0xb8d78)) {\n                        _0x3496a3 = _0xb8d78[_0x521f3f(0x377)](_0x3f8686, _0x462335[_0x521f3f(0x18d)][_0x335ec5][0x1a12 * -0x1 + 0x2361 + -0x94e]),\n                        _0x2d3284 && _0x3d40ff[_0x521f3f(0x397)]['call'](_0x2d3284, _0x521f3f(0x243), _0x521f3f(0x223) + _0xb8d78 + '\\x0aREWRITED:\\x20' + _0x3496a3);\n                        break;\n                    }\n                }\n            return _0x3496a3 = _0x2b13af(_0x3496a3);\n        }\n\n        function _0x344a4d() {\n            var _0x1b8e41 = _0x5612de;\n            return w_0x5c3140(_0x1b8e41(0x20d), {\n                get 0x0() {\n                    return window;\n                },\n                get 0x1() {\n                    return _0x6a7375;\n                },\n                get 0x2() {\n                    return _0x6caf;\n                },\n                get 0x3() {\n                    return _0x1958a5;\n                },\n                get 0x4() {\n                    return _0x2b13af;\n                },\n                get 0x5() {\n                    return _0x288415;\n                },\n                get 0x6() {\n                    return _0x8edc3d;\n                },\n                0x7: arguments\n            }, this);\n        }\n\n        function _0x3f720d() {\n            _0x3af1be(),\n                _0x1d82ac(),\n                _0x344a4d();\n        }\n\n        function _0x3bfecb(_0x4b21ed) {\n            var _0x3a0ee2 = _0x5612de;\n            this[_0x3a0ee2(0x341)] = 'ConfigException',\n                this[_0x3a0ee2(0x312)] = _0x4b21ed;\n        }\n\n        var _0x589057 = {\n            'cn': {\n                'host': _0x5612de(0x2c9)\n            }\n        }, _0x2bbf08 = [_0x5612de(0x30c)], _0x3d70a4;\n\n        function _0x43f5a3(_0x5a985f) {\n            var _0x20ecf9 = _0x5612de\n                , _0x3c43cc = '';\n            return {\n                'host': _0x3c43cc = _0x5a985f[_0x20ecf9(0x1b6)] || _0x5a985f[_0x20ecf9(0x1ae)] ? _0x5a985f[_0x20ecf9(0x1b3)] : _0x589057[_0x5a985f[_0x20ecf9(0x224)]][_0x20ecf9(0x2dc)],\n                'pathList': _0x2bbf08,\n                'reportUrl': _0x3c43cc + _0x2bbf08[0x1d7 * 0x7 + 0x1073 + -0x1d54]\n            };\n        }\n\n        var _0x383bd7 = !(0x244 * 0xb + -0x16a * -0x4 + -0x1e93), _0xd39ee2, _0x9e520d;\n\n        function _0x53ee31(_0x817028) {\n            var _0x5d5e8d = _0x5612de;\n            return w_0x5c3140(_0x5d5e8d(0x34f), {\n                0x0: Object,\n                0x1: Math,\n                get 0x2() {\n                    return _0x3bfecb;\n                },\n                get 0x3() {\n                    return _0x6caf;\n                },\n                get 0x4() {\n                    return _0x462335;\n                },\n                get 0x5() {\n                    return _0x43f5a3;\n                },\n                get 0x6() {\n                    return setTimeout;\n                },\n                get 0x7() {\n                    return _0x5c328e;\n                },\n                get 0x8() {\n                    return _0x3d70a4;\n                },\n                set 0x8(_0x5982f0) {\n                    _0x3d70a4 = _0x5982f0;\n                },\n                get 0x9() {\n                    return clearInterval;\n                },\n                get 0xa() {\n                    return setInterval;\n                },\n                get 0xb() {\n                    return _0x450b73;\n                },\n                get 0xc() {\n                    return _0x1a39c4;\n                },\n                get 0xd() {\n                    return _0x3f720d;\n                },\n                get 0xe() {\n                    return _0x59992f;\n                },\n                get 0xf() {\n                    return _0x39d569;\n                },\n                get 0x10() {\n                    return _0x1dbe74;\n                },\n                get 0x11() {\n                    return _0x383bd7;\n                },\n                set 0x11(_0x488bc8) {\n                    _0x383bd7 = _0x488bc8;\n                },\n                get 0x12() {\n                    return _0x18707d;\n                },\n                get 0x13() {\n                    return _0x1c3b6d;\n                },\n                0x14: arguments,\n                0x15: _0x817028\n            }, this);\n        }\n\n        function _0x3498af(_0x3e9bb9) {\n        }\n\n        function _0x59992f(_0x10dd97) {\n            var _0x1beab7 = _0x5612de;\n            for (var _0x52c469 = 0xb * -0x262 + -0x606 + 0x101e * 0x2; _0x52c469 < _0x10dd97[_0x1beab7(0x259)]; _0x52c469++)\n                _0x10dd97[_0x52c469] && _0x462335['_enablePathListRegex']['push'](new RegExp(_0x10dd97[_0x52c469]));\n        }\n\n        function _0x39d569(_0x51ab06) {\n            var _0x59d7a1 = _0x5612de;\n            if (void (-0x11c8 * 0x1 + 0x1fa2 * 0x1 + -0xdda) !== _0x51ab06) {\n                for (var _0x3e2076 = -0x3ab * -0x5 + -0x19d4 + 0x1b * 0x47; _0x3e2076 < _0x51ab06[_0x59d7a1(0x259)]; _0x3e2076++)\n                    _0x462335[_0x59d7a1(0x18d)][_0x59d7a1(0x36e)]([new RegExp(_0x51ab06[_0x3e2076][-0xfb * -0x1 + 0x9a7 * 0x4 + -0x5 * 0x7eb]), _0x51ab06[_0x3e2076][-0x57 * 0x55 + 0x1c99 * 0x1 + 0x4b]]);\n            }\n        }\n\n        function _0x32e4a6() {\n            var _0x494ee9 = _0x5612de;\n            return window[_0x494ee9(0x318)] || '';\n        }\n\n        function _0x1be1e1(_0x58db04) {\n            var _0x32bdb2 = _0x5612de\n                , _0x4558be = _0x6caf[_0x32bdb2(0x323)]\n                , _0x4ab91a = -0x5d * 0x5e + -0xb06 + -0x47 * -0xa3;\n            _0x32bdb2(0x2b6) === _0x58db04 && (_0x4ab91a = 0x1754 + 0xd0 * 0x4 + -0x1a93),\n            _0x32bdb2(0x285) === _0x58db04 && (_0x4ab91a = -0x146 * -0x13 + 0x13 * 0xef + -0x29ed);\n            var _0x1741bb = {\n                'ts': new Date()[_0x32bdb2(0x16d)](),\n                'v': _0x4ab91a\n            };\n            _0x4558be[_0x32bdb2(0x36e)](_0x1741bb);\n        }\n\n        function _0x4de7ef() {\n            var _0x45ce69 = _0x5612de, _0x5c1967, _0x586941;\n            void (0xbc1 + 0x1 * 0x1309 + -0x1eca) !== document[_0x45ce69(0x285)] ? (_0x45ce69(0x285),\n                _0x586941 = _0x45ce69(0x1a0),\n                _0x5c1967 = _0x45ce69(0x1f6)) : void (0x2056 + 0x2306 + -0x435c) !== document[_0x45ce69(0x15f)] ? (_0x45ce69(0x15f),\n                _0x586941 = _0x45ce69(0x1c8),\n                _0x5c1967 = _0x45ce69(0x33f)) : void (0x68 * 0x53 + 0x3c7 * 0x3 + -0x2d0d) !== document[_0x45ce69(0x2c6)] ? (_0x45ce69(0x2c6),\n                _0x586941 = _0x45ce69(0x2cc),\n                _0x5c1967 = _0x45ce69(0x1a4)) : void (-0x1bd7 + 0xc9 * -0x2b + 0x3d9a) !== document[_0x45ce69(0x22a)] && (_0x45ce69(0x22a),\n                _0x586941 = _0x45ce69(0x322),\n                _0x5c1967 = _0x45ce69(0x166)),\n                document[_0x45ce69(0x2f6)](_0x586941, function () {\n                    _0x1be1e1(document[_0x5c1967]);\n                }, !(0x1088 + 0x18c2 + 0xdc3 * -0x3)),\n                _0x1be1e1(document[_0x5c1967]);\n        }\n\n        function _0x3ff3f1() {\n            _0x58c311();\n        }\n\n        function _0x4c727e() {\n            var _0x3f5094 = _0x5612de;\n\n            function _0x115c6a(_0x2162b2) {\n                var _0x4cc12e = w_0x25f3;\n                _0x462335['triggerUnload'] || (_0x462335[_0x4cc12e(0x204)] = !(0x1 * -0x632 + 0x3 * -0xb71 + -0x1c3 * -0x17),\n                    _0x3ff3f1());\n            }\n\n            window && window[_0x3f5094(0x2f6)] && (window[_0x3f5094(0x2f6)](_0x3f5094(0x37d), _0x115c6a),\n                window[_0x3f5094(0x2f6)](_0x3f5094(0x29b), _0x115c6a));\n        }\n\n        function _0x5b850b() {\n            var _0x4d0be4 = _0x5612de;\n            for (var _0x35a39e = document[_0x4d0be4(0x272)][_0x4d0be4(0x342)](';'), _0x3046a3 = [], _0x58914c = -0x923 + -0x66a * -0x5 + -0x16ef; _0x58914c < _0x35a39e[_0x4d0be4(0x259)]; _0x58914c++)\n                if (_0x4d0be4(0x3b5) == (_0x3046a3 = _0x35a39e[_0x58914c][_0x4d0be4(0x342)]('='))[-0x7cd * -0x1 + -0x1678 + 0xeab]['trim']()) {\n                    _0x6caf[_0x4d0be4(0x3b5)] = _0x3046a3[0x200f * -0x1 + 0x926 + 0x16ea];\n                    break;\n                }\n        }\n\n        function _0x498349(_0x5efcd6) {\n            return new _0x53ee31(_0x5efcd6);\n        }\n\n        function _0x475194(_0x56e1e3) {\n            -0xa7f + -0xb * 0x18a + 0x1b6d === _0x56e1e3\n            // setTimeout(_0x5047d8, 0x1 * -0xb55 + -0x1031 + 0x1bea * 0x1) : -0xef1 + -0xfd3 * -0x1 + -0xe1 === _0x56e1e3 && setTimeout(_0x5c328e, 0x6 * 0x38d + -0x49 * -0x2b + -0x95 * 0x39);\n        }\n\n        function _0x4a4111(_0x2ba688, _0x1e135c) {\n            var _0x18e9b1 = _0x5612de;\n            -0xfab + 0x9 * -0x2a2 + 0x275e === _0x2ba688 && (_0x462335[_0x18e9b1(0x34a)] = Object['assign']({}, _0x462335[_0x18e9b1(0x34a)], _0x1e135c));\n        }\n\n        function _0x271dea(_0x20563e) {\n            void (-0x1aa2 + -0x2407 + 0x3 * 0x14e3) !== _0x20563e && '' != _0x20563e && (_0x6caf['ttwid'] = _0x20563e);\n        }\n\n        function _0x3a4a1a(_0x5b82b5) {\n            var _0x30adbb = _0x5612de;\n            void (0xb * -0x17d + -0x227d + 0x32dc) !== _0x5b82b5 && '' != _0x5b82b5 && (_0x6caf[_0x30adbb(0x316)] = _0x5b82b5);\n        }\n\n        function _0x3f0a66(_0x53e069) {\n            var _0x38d5b6 = _0x5612de;\n            void (-0x7eb * 0x3 + 0xc4 * 0x2 + -0x1 * -0x1639) !== _0x53e069 && '' != _0x53e069 && (_0x6caf[_0x38d5b6(0x339)] = _0x53e069);\n        }\n\n        _0x53ee31[_0x5612de(0x344)][_0x5612de(0x1a3)] = _0x5c2014,\n            _0x53ee31[_0x5612de(0x344)]['getReferer'] = _0x32e4a6,\n            _0x53ee31[_0x5612de(0x344)]['setUserMode'] = _0x3498af,\n            _0xd39ee2 = _0x24dc34(_0x45b94b['refererKey']) || '',\n            _0x2ecc5a(_0x45b94b['refererKey']),\n            _0x5612de(0x2d6) === _0xd39ee2 ? _0xd39ee2 = '' : '' === _0xd39ee2 && (_0xd39ee2 = document[_0x5612de(0x2fa)]),\n        _0xd39ee2 && (window[_0x5612de(0x318)] = _0xd39ee2),\n            _0x9e520d = _0x5141ac(),\n        _0x9e520d && (_0x6caf[_0x5612de(0x2b4)] = _0x9e520d,\n            _0x6caf['msStatus'] = _0x39693d['asgw']),\n            // setTimeout(function () {\n            //     _0x18a9f7(),\n            //         _0x1dbe74(),\n            //         _0x4de7ef(),\n            //         _0x4c727e(),\n            //         _0x21fa28();\n            // }, -0x1a83 + 0x15ee + -0xd * -0x141),\n            _0x5b850b(),\n            _0x59992f([_0x5612de(0x30c)]);\n        var _0x1649bc = !(-0xc6b * -0x1 + -0x2315 + 0x16aa);\n        crawler = _0x5c2014\n        _0x1d18f2['frontierSign'] = _0x5c2014,\n            _0x1d18f2[_0x5612de(0x2e8)] = _0x32e4a6,\n            _0x1d18f2[_0x5612de(0x3b9)] = _0x498349,\n            _0x1d18f2[_0x5612de(0x1f8)] = _0x1649bc,\n            _0x1d18f2['report'] = _0x475194,\n            _0x1d18f2[_0x5612de(0x298)] = _0x4a4111,\n            _0x1d18f2[_0x5612de(0x1a7)] = _0x3a4a1a,\n            _0x1d18f2['setTTWebidV2'] = _0x3f0a66,\n            _0x1d18f2[_0x5612de(0x244)] = _0x271dea,\n            _0x1d18f2[_0x5612de(0x378)] = _0x3498af,\n            Object['defineProperty'](_0x1d18f2, _0x5612de(0x3bd), {\n                'value': !(0x1 * 0x2069 + -0x1403 + -0xc66)\n            });\n    });\n}\n\nfunction get_sign(md5) {\n    let data = {\n        \"X-MS-STUB\": md5\n    }\n    return crawler(data)[\"X-Bogus\"];\n}\n\n// console.log(get_sign(\"e103106903fe7124df5b89decb376942\"))"
  },
  {
    "path": "simple_live_core/example/simple_live_core_example.dart",
    "content": "import 'dart:io';\n\nimport 'package:dio/dio.dart';\nimport 'package:simple_live_core/src/model/tars/get_cdn_token_req.dart';\nimport 'package:simple_live_core/src/model/tars/get_cdn_token_resp.dart';\nimport 'package:tars_dart/tars/net/base_tars_http.dart';\nimport 'package:tars_dart/tars/tup/uni_packet.dart';\n\nvoid main() async {\n  // CoreLog.enableLog = true;\n  // CoreLog.requestLogType = RequestLogType.short;\n  // LiveSite site = BiliBiliSite();\n  // var danmaku = site.getDanmaku();\n  // danmaku.onMessage = (event) {\n  //   if (event.type == LiveMessageType.chat) {\n  //     print(\"[${event.color}]${event.userName}：${event.message}\");\n  //   } else if (event.type == LiveMessageType.online) {\n  //     print(\"-----人气：${event.data}-----\");\n  //   } else if (event.type == LiveMessageType.superChat) {\n  //     var scMessage = event.data as LiveSuperChatMessage;\n  //     print(\"[SC]${scMessage.userName}：${scMessage.message}\");\n  //   }\n  // };\n  // danmaku.onClose = (event) {\n  //   print(event);\n  // };\n\n  // //var search = await site.searchRooms(\"东方\");\n\n  // //var categores = await site.getCategores();\n  // //print(categores.length);\n  // var detail = await site.getRoomDetail(roomId: '7734200');\n  // // var playQualites = await site.getPlayQualites(detail: detail);\n  // // print(playQualites);\n  // // var playUrls =\n  // //     await site.getPlayUrls(detail: detail, quality: playQualites.first);\n  // // for (var element in playUrls) {\n  // //   print(element);\n  // // }\n  // //print(detail);\n\n  // danmaku.start(detail.danmakuData);\n\n  // await Future.wait({});\n  sendReq();\n}\n\nvoid testHuyaReq() async {\n  var reqBytes = await File('demo/getCdnTokenInfoReq.bin').readAsBytes();\n  // RequestPacket req = RequestPacket();\n  // req.readFrom(TarsInputStream(reqBytes));\n  // print(req.iVersion);\n\n  UniPacket uniPacket = UniPacket();\n  //uniPacket.readFrom(TarsInputStream(reqBytes));\n  uniPacket.decode(reqBytes);\n  var value = uniPacket.get<GetCdnTokenReq>('tReq', GetCdnTokenReq());\n  // GetCdnTokenReq reqData = GetCdnTokenReq();\n  // reqData.readFrom(TarsInputStream(req.sBuffer));\n  print(value.toString());\n}\n\nvoid sendReq() async {\n  var req = GetCdnTokenReq();\n  req.cdnType = \"HW\";\n  req.streamName =\n      \"1199637826638-1199637826638-5763635889762729984-2399275776732-10057-A-0-1\";\n\n  BaseTarsHttp http = BaseTarsHttp(\"http://wup.huya.com\", \"liveui\");\n\n  var data = await http.tupRequest(\"getCdnTokenInfo\", req, GetCdnTokenResp());\n\n  var url =\n      'http://hw.flv.huya.com/src/${data.streamName}.flv?${data.flvAntiCode}&codec=264';\n  print(url);\n  await Dio().download(\n    url,\n    'live-stream.flv',\n    options: Options(\n      responseType: ResponseType.bytes,\n      headers: {\"user-agent\": \"HYSDK(Windows, 20000308)\"},\n    ),\n    onReceiveProgress: (count, total) {\n      var downBytes = count / 1024 / 1024;\n      print('downloading: $downBytes MB');\n    },\n  );\n}\n\nvoid testHuyaResp() async {\n  var respBytes = await File('demo/getCdnTokenInfoResp.bin').readAsBytes();\n  UniPacket uniPacket = UniPacket();\n  uniPacket.decode(respBytes);\n  var value = uniPacket.get<GetCdnTokenResp>('tRsp', GetCdnTokenResp());\n  print(value.toString());\n}\n"
  },
  {
    "path": "simple_live_core/lib/simple_live_core.dart",
    "content": "library;\n\nexport 'src/interface/live_site.dart';\nexport 'src/interface/live_danmaku.dart';\nexport 'src/platforms/huya/huya_site.dart';\nexport 'src/platforms/bilibili/bilibili_site.dart';\nexport 'src/platforms/douyu/douyu_site.dart';\nexport 'src/platforms/douyin/douyin_site.dart';\nexport 'src/platforms/twitch/twitch_site.dart';\nexport 'src/common/core_log.dart';\nexport 'src/model/live_message.dart';\nexport 'src/danmaku/bilibili_danmaku.dart';\nexport 'src/danmaku/douyu_danmaku.dart';\nexport 'src/danmaku/huya_danmaku.dart';\nexport 'src/danmaku/douyin_danmaku.dart';\n\nexport 'src/model/live_category_result.dart';\nexport 'src/model/live_category.dart';\nexport 'src/model/live_play_quality.dart';\nexport 'src/model/live_room_detail.dart';\nexport 'src/model/live_room_item.dart';\nexport 'src/model/live_search_result.dart';\nexport 'src/model/live_anchor_item.dart';\nexport 'src/model/live_play_url.dart';\n"
  },
  {
    "path": "simple_live_core/lib/src/common/binary_writer.dart",
    "content": "import 'dart:typed_data';\n\nclass BinaryWriter {\n  List<int> buffer;\n  int position = 0;\n  BinaryWriter(this.buffer);\n  int get length => buffer.length;\n\n  void writeBytes(List<int> list) {\n    buffer.addAll(list);\n    position += list.length;\n  }\n\n  void writeInt(int value, int len, {Endian endian = Endian.big}) {\n    var b = Uint8List(len).buffer;\n    var bytes = ByteData.view(b);\n    if (len == 1) {\n      //写入byte\n      bytes.setUint8(0, value.toUnsigned(8));\n    }\n    if (len == 2) {\n      bytes.setInt16(0, value, endian);\n    }\n    if (len == 4) {\n      bytes.setInt32(0, value, endian);\n    }\n    if (len == 8) {\n      bytes.setInt64(0, value, endian);\n    }\n\n    buffer.addAll(bytes.buffer.asUint8List());\n    position += len;\n  }\n\n  void writeDouble(double value, int len, {Endian endian = Endian.big}) {\n    var b = Uint8List(len).buffer;\n    var bytes = ByteData.view(b);\n\n    if (len == 4) {\n      bytes.setFloat32(0, value, endian);\n    }\n    if (len == 8) {\n      bytes.setFloat64(0, value, endian);\n    }\n\n    buffer.addAll(bytes.buffer.asUint8List());\n    position += len;\n  }\n}\n\nclass BinaryReader {\n  Uint8List buffer;\n  int position = 0;\n  BinaryReader(this.buffer);\n  int get length => buffer.length;\n\n  /// 从当前流中读取下一个字节，并使流的当前位置提升 1 个字节\n  /// 返回下一个字节(0-255)\n  int read() {\n    var byte = buffer[position];\n    position += 1;\n    return byte;\n  }\n\n  /// 从当前流中读取指定长度的字节整数，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// len=1为int8,2为int16,4为int32,8为int64。dart中统一为int类型\n  /// 返回整数\n  int readInt(int len, {Endian endian = Endian.big}) {\n    var result = 0;\n    // if (len == 1) {\n    //   result = buffer[position];\n    //   position += len;\n    //   return result;\n    // }\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    var byteBuffer = bytes.buffer;\n    var data = ByteData.view(byteBuffer);\n    if (len == 1) {\n      result = data.getUint8(0);\n    }\n    if (len == 2) {\n      result = data.getInt16(0, endian);\n    }\n    if (len == 4) {\n      result = data.getInt32(0, endian);\n    }\n    if (len == 8) {\n      result = data.getInt64(0, endian);\n    }\n    position += len;\n    return result;\n  }\n\n  /// 读取字节\n  /// int长度=1\n  int readByte({Endian endian = Endian.big}) {\n    return readInt(1, endian: endian);\n  }\n\n  /// 读取\n  /// int长度=2\n  int readShort({Endian endian = Endian.big}) {\n    return readInt(2, endian: endian);\n  }\n\n  /// 读取字节\n  /// int长度=4\n  int readInt32({Endian endian = Endian.big}) {\n    return readInt(4, endian: endian);\n  }\n\n  /// 读取字节\n  /// int长度=8\n  int readLong({Endian endian = Endian.big}) {\n    return readInt(8, endian: endian);\n  }\n\n  /// 从当前流中读取指定长度的字节数组，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// 返回字节数组\n  Uint8List readBytes(int len) {\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    position += len;\n    return bytes;\n  }\n\n  /// 从当前流中读取指定长度的字节浮点数，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// len=4为float,8为double。dart中统一为double类型\n  /// 返回浮点数\n  double readFloat(int len, {Endian endian = Endian.big}) {\n    var result = 0.0;\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    var byteBuffer = bytes.buffer;\n    var data = ByteData.view(byteBuffer);\n    if (len == 4) {\n      result = data.getFloat32(0, endian);\n    }\n    if (len == 8) {\n      result = data.getFloat64(0, endian);\n    }\n    position += len;\n    return result;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/convert_helper.dart",
    "content": "T? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/core_error.dart",
    "content": "class CoreError extends Error {\n  /// 错误码\n  final int statusCode;\n\n  /// 错误信息\n  final String message;\n\n  CoreError(\n    this.message, {\n    this.statusCode = 0,\n  });\n  @override\n  String toString() {\n    if (statusCode != 0) {\n      return statusCodeToString(statusCode);\n    }\n\n    return message;\n  }\n\n  String statusCodeToString(int statusCode) {\n    switch (statusCode) {\n      case 400:\n        return \"错误的请求(400)\";\n      case 401:\n        return \"无权限访问资源(401)\";\n      case 403:\n        return \"无权限访问资源(403)\";\n      case 404:\n        return \"服务器找不到请求的资源(404)\";\n      case 500:\n        return \"服务器出现错误(500)\";\n      case 502:\n        return \"服务器出现错误(502)\";\n      case 503:\n        return \"服务器出现错误(503)\";\n      default:\n        return \"连接服务器失败，请稍后再试($statusCode)\";\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/core_log.dart",
    "content": "import 'package:logger/logger.dart';\n\nenum RequestLogType {\n  /// 输出所有请求信息\n  /// 包括请求的URL，请求的参数，请求的头，请求的体，响应的头，响应的内容，耗时\n  all,\n\n  /// 简洁的输出\n  /// 仅输出请求的URL和响应的状态码\n  short,\n\n  /// 不输出请求信息\n  none,\n}\n\nclass CoreLog {\n  /// 是否启用日志\n  static bool enableLog = true;\n\n  /// 请求日志模式\n  static RequestLogType requestLogType = RequestLogType.all;\n\n  static Function(Level, String)? onPrintLog;\n  static Logger logger = Logger(\n    printer: PrettyPrinter(\n      methodCount: 0,\n      errorMethodCount: 8,\n      lineLength: 120,\n      colors: true,\n      printEmojis: true,\n    ),\n  );\n\n  static void d(String message) {\n    if (!enableLog) {\n      return;\n    }\n    onPrintLog?.call(Level.debug, message);\n    if (onPrintLog == null) {\n      logger.d(\"${DateTime.now().toString()}\\n$message\");\n    }\n  }\n\n  static void i(String message) {\n    if (!enableLog) {\n      return;\n    }\n    onPrintLog?.call(Level.info, message);\n    if (onPrintLog == null) {\n      logger.i(\"${DateTime.now().toString()}\\n$message\");\n    }\n  }\n\n  static void e(String message, StackTrace stackTrace) {\n    if (!enableLog) {\n      return;\n    }\n    onPrintLog?.call(Level.error, message);\n    if (onPrintLog == null) {\n      logger.e(\"${DateTime.now().toString()}\\n$message\",\n          stackTrace: stackTrace);\n    }\n  }\n\n  static void error(Object e) {\n    if (!enableLog) {\n      return;\n    }\n    onPrintLog?.call(Level.error, e.toString());\n    if (onPrintLog == null) {\n      logger.e(\n        \"${DateTime.now().toString()}\\n${e.toString()}\",\n        error: e,\n        stackTrace: (e is Error) ? e.stackTrace : StackTrace.current,\n      );\n    }\n  }\n\n  static void w(String message) {\n    if (!enableLog) {\n      return;\n    }\n    onPrintLog?.call(Level.warning, message);\n    if (onPrintLog == null) {\n      logger.w(\"${DateTime.now().toString()}\\n$message\");\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/custom_interceptor.dart",
    "content": "import 'package:dio/dio.dart';\n\nimport 'core_log.dart';\n\nclass CustomInterceptor extends Interceptor {\n  @override\n  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {\n    options.extra[\"ts\"] = DateTime.now().millisecondsSinceEpoch;\n    if (CoreLog.requestLogType == RequestLogType.all) {\n      CoreLog.i(\n        '''[HTTP Request] [${options.method}]\nRequest URL：${options.uri}\nRequest Query：${options.queryParameters}\nRequest Data：${options.data}\nRequest Headers：${options.headers}''',\n      );\n    } else if (CoreLog.requestLogType == RequestLogType.short) {\n      CoreLog.i(\"[HTTP Request] [${options.method}] ${options.uri}\");\n    }\n\n    super.onRequest(options, handler);\n  }\n\n  @override\n  void onError(DioException err, ErrorInterceptorHandler handler) {\n    var time =\n        DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra[\"ts\"];\n    if (CoreLog.requestLogType == RequestLogType.all) {\n      CoreLog.e('''[HTTP Error] [${err.type}] [Time:${time}ms]\n${err.message}\n\nRequest Method：${err.requestOptions.method}\nResponse Code：${err.response?.statusCode}\nRequest URL：${err.requestOptions.uri}\nRequest Query：${err.requestOptions.queryParameters}\nRequest Data：${err.requestOptions.data}\nRequest Headers：${err.requestOptions.headers}\nResponse Headers：${err.response?.headers.map}\nResponse Data：${err.response?.data}''', err.stackTrace);\n    } else {\n      CoreLog.e(\n        \"[HTTP Error] [${err.type}] [Time:${time}ms]\\n[${err.response?.statusCode}] ${err.requestOptions.uri}\",\n        err.stackTrace,\n      );\n    }\n\n    super.onError(err, handler);\n  }\n\n  @override\n  void onResponse(Response response, ResponseInterceptorHandler handler) {\n    var time = DateTime.now().millisecondsSinceEpoch -\n        response.requestOptions.extra[\"ts\"];\n    if (CoreLog.requestLogType == RequestLogType.all) {\n      CoreLog.i(\n        '''[HTTP Response] [time:${time}ms]\nRequest Method：${response.requestOptions.method}\nRequest Code：${response.statusCode}\nRequest URL：${response.requestOptions.uri}\nRequest Query：${response.requestOptions.queryParameters}\nRequest Data：${response.requestOptions.data}\nRequest Headers：${response.requestOptions.headers}\nResponse Headers：${response.headers.map}\nResponse Data：${response.data}''',\n      );\n    } else if (CoreLog.requestLogType == RequestLogType.short) {\n      CoreLog.i(\n        \"[HTTP Response] [time:${time}ms] [${response.statusCode}] ${response.requestOptions.uri}\",\n      );\n    }\n    super.onResponse(response, handler);\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/douyin/abogus.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\nimport 'dart:typed_data';\nimport 'package:dart_sm/dart_sm.dart';\n\nclass StringProcessor {\n  static String toCharStr(List<int> codes) {\n    return String.fromCharCodes(codes);\n  }\n\n  static List<int> toOrdArray(String s) {\n    return s.codeUnits;\n  }\n\n  static int jsShiftRight(int val, int n) {\n    return (val & 0xFFFFFFFF) >>> n;\n  }\n\n  static String generateRandomBytes({int length = 3}) {\n    List<String> generateByteSequence() {\n      final _rd = Random().nextInt(10000);\n      return [\n        String.fromCharCode(((_rd & 255) & 170) | 1),\n        String.fromCharCode(((_rd & 255) & 85) | 2),\n        String.fromCharCode((jsShiftRight(_rd, 8) & 170) | 5),\n        String.fromCharCode((jsShiftRight(_rd, 8) & 85) | 40),\n      ];\n    }\n\n    final result = <String>[];\n    for (var i = 0; i < length; i++) {\n      result.addAll(generateByteSequence());\n    }\n\n    return result.join('');\n  }\n}\n\nclass CryptoUtility {\n  final String salt;\n  final List<String> base64Alphabet;\n  late List<int> bigArray;\n\n  CryptoUtility(this.salt, this.base64Alphabet) {\n    // fmt: off\n    bigArray = [\n        121, 243,  55, 234, 103,  36,  47, 228,  30, 231, 106,   6, 115,  95,  78, 101, 250, 207, 198,  50,\n        139, 227, 220, 105,  97, 143,  34,  28, 194, 215,  18, 100, 159, 160,  43,   8, 169, 217, 180, 120,\n        247,  45,  90,  11,  27, 197,  46,   3,  84,  72,   5,  68,  62,  56, 221,  75, 144,  79,  73, 161,\n        178,  81,  64, 187, 134, 117, 186, 118,  16, 241, 130,  71,  89, 147, 122, 129,  65,  40,  88, 150,\n        110, 219, 199, 255, 181, 254,  48,   4, 195, 248, 208,  32, 116, 167,  69, 201,  17, 124, 125, 104,\n         96,  83,  80, 127, 236, 108, 154, 126, 204,  15,  20, 135, 112, 158,  13,   1, 188, 164, 210, 237,\n        222,  98, 212,  77, 253,  42, 170, 202,  26,  22,  29, 182, 251,  10, 173, 152,  58, 138,  54, 141,\n        185,  33, 157,  31, 252, 132, 233, 235, 102, 196, 191, 223, 240, 148,  39, 123,  92,  82, 128, 109,\n         57,  24,  38, 113, 209, 245,   2, 119, 153, 229, 189, 214, 230, 174, 232,  63,  52, 205,  86, 140,\n         66, 175, 111, 171, 246, 133, 238, 193,  99,  60,  74,  91, 225,  51,  76,  37, 145, 211, 166, 151,\n        213, 206,   0, 200, 244, 176, 218,  44, 184, 172,  49, 216,  93, 168,  53,  21, 183,  41,  67,  85,\n        224, 155, 226, 242,  87, 177, 146,  70, 190,  12, 162,  19, 137, 114,  25, 165, 163, 192,  23,  59,\n          9,  94, 179, 107,  35,   7, 142, 131, 239, 203, 149, 136,  61, 249,  14, 156\n    ];\n    // fmt: on\n  }\n\n  static List<int> sm3ToArray(dynamic inputData) {\n    Uint8List inputDataBytes;\n    if (inputData is String) {\n      inputDataBytes = utf8.encode(inputData);\n    } else if (inputData is List<int>) {\n      inputDataBytes = Uint8List.fromList(inputData);\n    } else {\n      throw ArgumentError(\"Input data must be a String or List<int>\");\n    }\n    final hexResult = SM3.hashBytes(inputDataBytes);\n    final result = <int>[];\n    for (var i = 0; i < hexResult.length; i += 2) {\n      result.add(int.parse(hexResult.substring(i, i + 2), radix: 16));\n    }\n    return result;\n  }\n\n  String addSalt(String param) {\n    return param + salt;\n  }\n\n  dynamic processParam(dynamic param, bool addSaltFlag) {\n    if (param is String && addSaltFlag) {\n      return addSalt(param);\n    }\n    return param;\n  }\n\n  List<int> paramsToArray(dynamic param, {bool addSalt = true}) {\n    final processedParam = processParam(param, addSalt);\n    return sm3ToArray(processedParam);\n  }\n\n  String transformBytes(List<int> bytesList) {\n    final bytesStr = StringProcessor.toCharStr(bytesList);\n    final resultStr = <String>[];\n    var indexB = bigArray[1];\n    var initialValue = 0;\n    var valueE = 0; // To hold the value for the next iteration\n\n    for (var index = 0; index < bytesStr.length; index++) {\n      final char = bytesStr[index];\n      var sumInitial = 0;\n\n      if (index == 0) {\n        initialValue = bigArray[indexB];\n        sumInitial = indexB + initialValue;\n\n        bigArray[1] = initialValue;\n        bigArray[indexB] = indexB;\n      } else {\n        sumInitial = initialValue + valueE;\n      }\n\n      final charValue = char.codeUnitAt(0);\n      sumInitial %= bigArray.length;\n      final valueF = bigArray[sumInitial];\n      final encryptedChar = charValue ^ valueF;\n      resultStr.add(String.fromCharCode(encryptedChar));\n\n      valueE = bigArray[(index + 2) % bigArray.length];\n      sumInitial = (indexB + valueE) % bigArray.length;\n      initialValue = bigArray[sumInitial];\n      bigArray[sumInitial] = bigArray[(index + 2) % bigArray.length];\n      bigArray[(index + 2) % bigArray.length] = initialValue;\n      indexB = sumInitial;\n    }\n\n    return resultStr.join('');\n  }\n\n  String base64Encode(String inputString, {int selectedAlphabet = 0}) {\n    var binaryString = inputString.codeUnits\n        .map((c) => c.toRadixString(2).padLeft(8, '0'))\n        .join('');\n\n    final paddingLength = (6 - binaryString.length % 6) % 6;\n    binaryString += '0' * paddingLength;\n\n    final base64Indices = <int>[];\n    for (var i = 0; i < binaryString.length; i += 6) {\n      base64Indices.add(int.parse(binaryString.substring(i, i + 6), radix: 2));\n    }\n\n    var outputString = base64Indices\n        .map((index) => base64Alphabet[selectedAlphabet][index])\n        .join('');\n\n    outputString += '=' * (paddingLength ~/ 2);\n    return outputString;\n  }\n\n  String abogusEncode(String abogusBytesStr, int selectedAlphabet) {\n    final abogus = <String>[];\n    final alphabet = base64Alphabet[selectedAlphabet];\n\n    for (var i = 0; i < abogusBytesStr.length; i += 3) {\n      int n;\n      if (i + 2 < abogusBytesStr.length) {\n        n = (abogusBytesStr.codeUnitAt(i) << 16) |\n            (abogusBytesStr.codeUnitAt(i + 1) << 8) |\n            abogusBytesStr.codeUnitAt(i + 2);\n      } else if (i + 1 < abogusBytesStr.length) {\n        n = (abogusBytesStr.codeUnitAt(i) << 16) |\n            (abogusBytesStr.codeUnitAt(i + 1) << 8);\n      } else {\n        n = abogusBytesStr.codeUnitAt(i) << 16;\n      }\n\n      final shifts = [18, 12, 6, 0];\n      final masks = [0xFC0000, 0x03F000, 0x0FC0, 0x3F];\n\n      for (var j = 0; j < shifts.length; j++) {\n        if (shifts[j] == 6 && i + 1 >= abogusBytesStr.length) break;\n        if (shifts[j] == 0 && i + 2 >= abogusBytesStr.length) break;\n        abogus.add(alphabet[(n & masks[j]) >> shifts[j]]);\n      }\n    }\n\n    abogus.add('=' * ((4 - abogus.length % 4) % 4));\n    return abogus.join('');\n  }\n\n  static Uint8List rc4Encrypt(Uint8List key, String plaintext) {\n    final s = List<int>.generate(256, (i) => i);\n    var j = 0;\n    for (var i = 0; i < 256; i++) {\n      j = (j + s[i] + key[i % key.length]) % 256;\n      final temp = s[i];\n      s[i] = s[j];\n      s[j] = temp;\n    }\n\n    var i = 0;\n    j = 0;\n    final ciphertext = <int>[];\n    for (final char in plaintext.codeUnits) {\n      i = (i + 1) % 256;\n      j = (j + s[i]) % 256;\n      final temp = s[i];\n      s[i] = s[j];\n      s[j] = temp;\n      final k = s[(s[i] + s[j]) % 256];\n      ciphertext.add(char ^ k);\n    }\n\n    return Uint8List.fromList(ciphertext);\n  }\n}\n\nclass BrowserFingerprintGenerator {\n  static String generateFingerprint({String browserType = \"Edge\"}) {\n    final browsers = {\n      \"Chrome\": generateChromeFingerprint,\n      \"Firefox\": generateFirefoxFingerprint,\n      \"Safari\": generateSafariFingerprint,\n      \"Edge\": generateEdgeFingerprint,\n    };\n    return (browsers[browserType] ?? generateChromeFingerprint)();\n  }\n\n  static String generateChromeFingerprint() => _generateFingerprint(platform: \"Win32\");\n  static String generateFirefoxFingerprint() => _generateFingerprint(platform: \"Win32\");\n  static String generateSafariFingerprint() => _generateFingerprint(platform: \"MacIntel\");\n  static String generateEdgeFingerprint() => _generateFingerprint(platform: \"Win32\");\n\n  static String _generateFingerprint({required String platform}) {\n    final random = Random();\n    final innerWidth = 1024 + random.nextInt(1920 - 1024 + 1);\n    final innerHeight = 768 + random.nextInt(1080 - 768 + 1);\n    final outerWidth = innerWidth + (24 + random.nextInt(32 - 24 + 1));\n    final outerHeight = innerHeight + (75 + random.nextInt(90 - 75 + 1));\n    const screenX = 0;\n    final screenY = [0, 30][random.nextInt(2)];\n    final sizeWidth = 1024 + random.nextInt(1920 - 1024 + 1);\n    final sizeHeight = 768 + random.nextInt(1080 - 768 + 1);\n    final availWidth = 1280 + random.nextInt(1920 - 1280 + 1);\n    final availHeight = 800 + random.nextInt(1080 - 800 + 1);\n\n    return \"$innerWidth|$innerHeight|$outerWidth|$outerHeight|\"\n        \"$screenX|$screenY|0|0|$sizeWidth|$sizeHeight|\"\n        \"$availWidth|$availHeight|$innerWidth|$innerHeight|24|24|$platform\";\n  }\n}\n\nclass ABogus {\n  final String userAgent;\n  final String browserFp;\n  final List<int> options;\n\n  final int aid = 6383;\n  final int pageId = 0;\n  final String salt = \"cus\";\n  final bool boe = false;\n  final double ddrt = 8.5;\n  final double ic = 8.5;\n  final List<String> paths = [\n    \"^/webcast/\",\n    \"^/aweme/v1/\",\n    \"^/aweme/v2/\",\n    \"/v1/message/send\",\n    \"^/live/\",\n    \"^/captcha/\",\n    \"^/ecom/\",\n  ];\n  final Uint8List uaKey = Uint8List.fromList([0, 1, 14]);\n\n  final String character = \"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe\";\n  final String character2 = \"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe\";\n  late final List<String> characterList;\n  late final CryptoUtility cryptoUtility;\n\n  // fmt: off\n  final List<int> sortIndex = [\n      18, 20, 52, 26, 30, 34, 58, 38, 40, 53, 42, 21, 27, 54, 55, 31, 35, 57, 39, 41, 43, 22, 28,\n      32, 60, 36, 23, 29, 33, 37, 44, 45, 59, 46, 47, 48, 49, 50, 24, 25, 65, 66, 70, 71\n  ];\n  final List<int> sortIndex2 = [\n      18, 20, 26, 30, 34, 38, 40, 42, 21, 27, 31, 35, 39, 41, 43, 22, 28, 32, 36, 23, 29, 33, 37,\n      44, 45, 46, 47, 48, 49, 50, 24, 25, 52, 53, 54, 55, 57, 58, 59, 60, 65, 66, 70, 71\n  ];\n  // fmt: on\n\n  ABogus({String? fp, String? userAgent, List<int>? options})\n      : userAgent = userAgent != null && userAgent.isNotEmpty\n            ? userAgent\n            : \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0\",\n        browserFp = fp != null && fp.isNotEmpty\n            ? fp\n            : BrowserFingerprintGenerator.generateFingerprint(browserType: \"Edge\"),\n        options = options ?? [0, 1, 14] {\n    characterList = [character, character2];\n    cryptoUtility = CryptoUtility(salt, characterList);\n  }\n\n  String encodeData(String data, {int alphabetIndex = 0}) {\n    return cryptoUtility.abogusEncode(data, alphabetIndex);\n  }\n\n  List<String> generateAbogus(String params, {String body = \"\"}) {\n    final abDir = <int, dynamic>{\n      8: 3,\n      15: {\n        \"aid\": aid,\n        \"pageId\": pageId,\n        \"boe\": boe,\n        \"ddrt\": ddrt,\n        \"paths\": paths,\n        \"track\": {\"mode\": 0, \"delay\": 300, \"paths\": []},\n        \"dump\": true,\n        \"rpU\": \"\",\n      },\n      18: 44,\n      19: [1, 0, 1, 0, 1],\n      66: 0,\n      69: 0,\n      70: 0,\n      71: 0,\n    };\n\n    final startEncryption = DateTime.now().millisecondsSinceEpoch;\n\n    final array1 = cryptoUtility.paramsToArray(cryptoUtility.paramsToArray(params));\n    final array2 = cryptoUtility.paramsToArray(cryptoUtility.paramsToArray(body));\n    final array3 = cryptoUtility.paramsToArray(\n      cryptoUtility.base64Encode(\n        StringProcessor.toCharStr(\n          CryptoUtility.rc4Encrypt(uaKey, userAgent),\n        ),\n        selectedAlphabet: 1,\n      ),\n      addSalt: false,\n    );\n\n    final endEncryption = DateTime.now().millisecondsSinceEpoch;\n\n    abDir[20] = (startEncryption >> 24) & 255;\n    abDir[21] = (startEncryption >> 16) & 255;\n    abDir[22] = (startEncryption >> 8) & 255;\n    abDir[23] = startEncryption & 255;\n    abDir[24] = StringProcessor.jsShiftRight(startEncryption, 32);\n    abDir[25] = StringProcessor.jsShiftRight(startEncryption, 40);\n\n    abDir[26] = (options[0] >> 24) & 255;\n    abDir[27] = (options[0] >> 16) & 255;\n    abDir[28] = (options[0] >> 8) & 255;\n    abDir[29] = options[0] & 255;\n\n    abDir[30] = (options[1] ~/ 256) & 255;\n    abDir[31] = (options[1] % 256) & 255;\n    abDir[32] = (options[1] >> 24) & 255;\n    abDir[33] = (options[1] >> 16) & 255;\n\n    abDir[34] = (options[2] >> 24) & 255;\n    abDir[35] = (options[2] >> 16) & 255;\n    abDir[36] = (options[2] >> 8) & 255;\n    abDir[37] = options[2] & 255;\n\n    abDir[38] = array1[21];\n    abDir[39] = array1[22];\n    abDir[40] = array2[21];\n    abDir[41] = array2[22];\n    abDir[42] = array3[23];\n    abDir[43] = array3[24];\n\n    abDir[44] = (endEncryption >> 24) & 255;\n    abDir[45] = (endEncryption >> 16) & 255;\n    abDir[46] = (endEncryption >> 8) & 255;\n    abDir[47] = endEncryption & 255;\n    abDir[48] = abDir[8];\n    abDir[49] = StringProcessor.jsShiftRight(endEncryption, 32);\n    abDir[50] = StringProcessor.jsShiftRight(endEncryption, 40);\n\n    abDir[51] = (pageId >> 24) & 255;\n    abDir[52] = (pageId >> 16) & 255;\n    abDir[53] = (pageId >> 8) & 255;\n    abDir[54] = pageId & 255;\n    abDir[55] = pageId;\n    abDir[56] = aid;\n    abDir[57] = aid & 255;\n    abDir[58] = (aid >> 8) & 255;\n    abDir[59] = (aid >> 16) & 255;\n    abDir[60] = (aid >> 24) & 255;\n\n    abDir[64] = browserFp.length;\n    abDir[65] = browserFp.length;\n\n    final sortedValues = sortIndex.map((i) => abDir[i] ?? 0).toList().cast<int>();\n    final edgeFpArray = StringProcessor.toOrdArray(browserFp);\n\n    var abXor = 0;\n    for (var index = 0; index < sortIndex2.length; index++) {\n      if (index == 0) {\n        abXor = abDir[sortIndex2[index]] ?? 0;\n      } else {\n        abXor ^= (abDir[sortIndex2[index]] ?? 0);\n      }\n    }\n    sortedValues.addAll(edgeFpArray);\n    sortedValues.add(abXor);\n\n    final abogusBytesStr = StringProcessor.generateRandomBytes() +\n        cryptoUtility.transformBytes(sortedValues);\n\n    final abogus = cryptoUtility.abogusEncode(abogusBytesStr, 0);\n    final finalParams = \"$params&a_bogus=$abogus\";\n    return [finalParams, abogus, userAgent, body];\n  }\n}\n\n"
  },
  {
    "path": "simple_live_core/lib/src/common/douyin/douyinRequestParams.dart",
    "content": "﻿mixin DouyinRequestParams {\n  static const String kDefaultUserAgent =\n      \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\";\n  static const AID_VALUE = \"6383\";\n  static const VERSION_CODE_VALUE = \"180800\";\n  static const SDK_VERSION = \"1.0.14-beta.0\";\n}"
  },
  {
    "path": "simple_live_core/lib/src/common/douyin/douyin_utils.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\n\nimport 'abogus.dart';\nimport 'douyinRequestParams.dart';\n\nclass DouyinUtils {\n// 根据传入长度产生随机字符串\n  static String getMSToken({int randomLength = 184}) {\n    var baseStr =\n        'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789=';\n    var sb = StringBuffer();\n    for (var i = 0; i < randomLength; i++) {\n      var index = Random().nextInt(baseStr.length);\n      sb.write(baseStr[index]);\n    }\n    return sb.toString();\n  }\n\n  static buildRequestUrl(String baseUrl, Map<String, dynamic> params) {\n    var abogus = ABogus(userAgent: DouyinRequestParams.kDefaultUserAgent);\n    var parsedUrl = Uri.parse(baseUrl);\n    var exParams = params;\n    exParams['aid'] = \"6383\";\n    exParams['compress'] = \"gzip\";\n    exParams['device_platform'] = \"web\";\n    exParams['browser_language'] = \"zh-CN\";\n    exParams['browser_platform'] = \"Win32\";\n    exParams['browser_name'] = \"Edge\";\n    exParams['browser_version'] = \"125.0.0.0\";\n    if (!exParams.containsKey('msToken')) {\n      exParams['msToken'] = getMSToken();\n    }\n    var newQueryStr = Uri(queryParameters: exParams).query;\n    var signedQueryStr = abogus.generateAbogus(newQueryStr, body: \"\").first;\n    final newUrl = parsedUrl.replace(\n      query: signedQueryStr,\n    );\n    return newUrl.toString();\n  }\n\n  Future<Map<String, String>> get_ttwid_webid({required String req_url}) async {\n    // 先请求以获取 ttwid 等 Cookie，再解析页面的 RENDER_DATA 获取 user_unique_id\n    final headers = <String, String>{\n      \"User-Agent\":\n          \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\",\n      \"Accept\":\n          \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\",\n      \"Accept-Language\": \"zh-CN,zh;q=0.9,en;q=0.8\",\n    };\n\n    String? ttwid;\n    String? webid;\n\n    try {\n      // 先用 HEAD 获取 Set-Cookie（包含 ttwid）\n      final headResp = await HttpClient.instance.head(\n        req_url,\n        header: headers,\n      );\n      final setCookies = headResp.headers[\"set-cookie\"];\n      if (setCookies != null) {\n        for (final cookieLine in setCookies) {\n          final cookie = cookieLine.split(\";\").first;\n          if (cookie.startsWith(\"ttwid=\")) {\n            ttwid = cookie.substring(\"ttwid=\".length);\n            break;\n          }\n        }\n      }\n\n      // 再用 GET 拉取页面 HTML，解析 RENDER_DATA\n      final html = await HttpClient.instance.getText(\n        req_url,\n        header: headers,\n      );\n\n      // 提取 RENDER_DATA 脚本块\n      final renderMatches = RegExp(\n        r'<script id=\\\"RENDER_DATA\\\" type=\\\"application\\/json\\\">(.*?)<\\/script>',\n        dotAll: true,\n      ).allMatches(html);\n      if (renderMatches.isNotEmpty) {\n        var renderDataText = renderMatches.first.group(1) ?? \"\";\n        // URL 解码\n        try {\n          renderDataText = Uri.decodeComponent(renderDataText);\n        } catch (_) {}\n        try {\n          final data = jsonDecode(renderDataText) as Map<String, dynamic>;\n          // 路径 app.odin.user_unique_id\n          final app = data['app'] as Map<String, dynamic>?;\n          final odin = app?['odin'] as Map<String, dynamic>?;\n          final uid = odin?['user_unique_id'];\n          if (uid != null) {\n            webid = uid.toString();\n          }\n        } catch (e) {\n          CoreLog.error('解析 RENDER_DATA 失败: $e');\n        }\n      }\n    } catch (e) {\n      CoreLog.error('get_ttwid_webid 错误: $e');\n    }\n\n    return {\n      'ttwid': ttwid ?? '',\n      'webid': webid ?? '',\n    };\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/http_client.dart",
    "content": "import 'package:simple_live_core/src/common/core_error.dart';\nimport 'package:dio/dio.dart';\n\nimport 'custom_interceptor.dart';\n\nclass HttpClient {\n  static HttpClient? _httpUtil;\n\n  static HttpClient get instance {\n    _httpUtil ??= HttpClient();\n    return _httpUtil!;\n  }\n\n  late Dio dio;\n  HttpClient() {\n    dio = Dio(\n      BaseOptions(\n        connectTimeout: Duration(seconds: 20),\n        receiveTimeout: Duration(seconds: 20),\n        sendTimeout: Duration(seconds: 20),\n      ),\n    );\n    dio.interceptors.add(CustomInterceptor());\n  }\n\n  /// Get请求，返回String\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<String> getText(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.plain,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw CoreError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw CoreError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Get请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<dynamic> getJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw CoreError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw CoreError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Post请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [data] 内容\n  /// * [cancel] 任务取消Token\n  Future<dynamic> postJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    dynamic data,\n    Map<String, dynamic>? header,\n    bool formUrlEncoded = false,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      data ??= {};\n      var result = await dio.post(\n        url,\n        queryParameters: queryParameters,\n        data: data,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n          contentType:\n              formUrlEncoded ? Headers.formUrlEncodedContentType : null,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw CoreError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw CoreError(\"发送POST请求失败\");\n      }\n    }\n  }\n\n  /// Head请求，返回Response\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<Response> head(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.head(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          headers: header,\n          receiveDataWhenStatusError: true,\n        ),\n        cancelToken: cancel,\n      );\n      return result;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        //throw CoreError(e.message, statusCode: e.response?.statusCode ?? 0);\n        return e.response!;\n      } else {\n        throw CoreError(\"发送HEAD请求失败\");\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/js_engine.dart",
    "content": "import 'package:flutter_qjs/flutter_qjs.dart';\nimport 'package:flutter/services.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\n\nclass JsEngine {\n  static FlutterQjs? _engine;\n\n  static void init({int stackSize = 1024 * 1024}) {\n    if (_engine == null) {\n      _engine = FlutterQjs(stackSize: stackSize);\n      _engine!.dispatch();\n    }\n  }\n\n  static FlutterQjs get engine {\n    if (_engine == null) {\n      init();\n    }\n    return _engine!;\n  }\n\n  static dynamic evaluate(String code) {\n    try {\n      return engine.evaluate(code);\n    } on JSError catch (e) {\n      CoreLog.error(\"JsEngine evaluate error: $e\");\n      return null;\n    }\n  }\n\n  static Future<void> loadJSFile(String path) async {\n    try {\n      final jsCode = await rootBundle.loadString(path);\n      engine.evaluate(jsCode);\n    } catch (e) {\n      CoreLog.error(\"JsEngine loadJSFile error: $e\");\n    }\n  }\n\n  static void dispose() {\n    try {\n      _engine?.port.close();\n      _engine?.close();\n    } catch (e) {\n      CoreLog.error(\"JsEngine dispose error: $e\");\n    } finally {\n      _engine = null;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/common/web_socket_util.dart",
    "content": "import 'dart:async';\n\nimport 'package:web_socket_channel/io.dart';\n\nenum SocketStatus {\n  connected,\n  failed,\n  closed,\n}\n\nclass WebScoketUtils {\n  SocketStatus status = SocketStatus.closed;\n\n  /// 链接\n  final String url;\n\n  /// 备用链接\n  final String? backupUrl;\n\n  /// 心跳时间\n  final int heartBeatTime;\n\n  /// 接收到信息\n  final Function(dynamic)? onMessage;\n\n  /// 连接关闭\n  final Function(String msg)? onClose;\n\n  /// 尝试重连\n  final Function()? onReconnect;\n\n  /// 准备就绪\n  final Function()? onReady;\n\n  /// 心跳\n  final Function()? onHeartBeat;\n\n  /// 请求头\n  Map<String, dynamic>? headers;\n  WebScoketUtils({\n    required this.url,\n    required this.heartBeatTime,\n    this.onMessage,\n    this.onClose,\n    this.onReconnect,\n    this.onReady,\n    this.onHeartBeat,\n    this.headers,\n    this.backupUrl,\n  });\n  IOWebSocketChannel? webSocket;\n  Timer? heartBeatTimer;\n\n  /// 重连次数\n  int reconnectTime = 0;\n  Timer? reconnectTimer;\n\n  /// 最大重连次数\n  int maxReconnectTime = 5;\n\n  StreamSubscription<dynamic>? streamSubscription;\n\n  void connect({bool retry = false}) async {\n    close();\n    try {\n      var wsurl = url;\n      if (backupUrl != null && backupUrl!.isNotEmpty && retry) {\n        wsurl = backupUrl!;\n      }\n      webSocket = IOWebSocketChannel.connect(\n        wsurl,\n        connectTimeout: Duration(seconds: 10),\n        headers: headers,\n      );\n\n      await webSocket?.ready;\n      ready();\n    } catch (e) {\n      if (!retry) {\n        connect(retry: true);\n        return;\n      }\n      onError(e, StackTrace.current);\n    }\n  }\n\n  /// 连接完成\n  void ready() {\n    status = SocketStatus.connected;\n\n    streamSubscription = webSocket?.stream.listen(\n      (data) => receiveMessage(data),\n      onError: (e, s) => onError(e, s),\n      onDone: onDone,\n    );\n\n    onReady?.call();\n    initHeartBeat();\n  }\n\n  void initHeartBeat() {\n    heartBeatTimer = Timer.periodic(\n      Duration(milliseconds: heartBeatTime),\n      (timer) {\n        onHeartBeat?.call();\n      },\n    );\n  }\n\n  void receiveMessage(dynamic data) {\n    //接受到一条信息才算重连成功\n    reconnectTime = 0;\n    onMessage?.call(data);\n  }\n\n  void onError(Object e, StackTrace s) {\n    status = SocketStatus.failed;\n    onClose?.call(e.toString());\n  }\n\n  void onDone() {\n    if (status == SocketStatus.closed) {\n      return;\n    }\n    onReconnect?.call();\n    reconnect();\n  }\n\n  void sendMessage(dynamic message) {\n    if (status == SocketStatus.connected) {\n      webSocket?.sink.add(message);\n    }\n  }\n\n  void close() {\n    status = SocketStatus.closed;\n\n    streamSubscription?.cancel();\n\n    reconnectTimer?.cancel();\n    reconnectTimer = null;\n\n    webSocket?.sink.close();\n\n    heartBeatTimer?.cancel();\n    heartBeatTimer = null;\n  }\n\n  void reconnect() {\n    status = SocketStatus.closed;\n    if (reconnectTime < maxReconnectTime) {\n      reconnectTime++;\n      reconnectTimer ??= Timer.periodic(Duration(seconds: 5), (timer) {\n        connect();\n      });\n    } else {\n      onClose?.call(\"重连超过最大次数，与服务器断开连接\");\n      reconnectTimer?.cancel();\n      reconnectTimer = null;\n      close();\n      return;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/bilibili_danmaku.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:io';\nimport 'dart:typed_data';\n\nimport 'package:brotli/brotli.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/convert_helper.dart';\nimport 'package:simple_live_core/src/common/web_socket_util.dart';\n\nimport '../common/binary_writer.dart';\n\nclass BiliBiliDanmakuArgs {\n  final int roomId;\n  final String token;\n  final String buvid;\n  final String serverHost;\n  final int uid;\n  final String cookie;\n  BiliBiliDanmakuArgs({\n    required this.roomId,\n    required this.token,\n    required this.serverHost,\n    required this.buvid,\n    required this.uid,\n    required this.cookie,\n  });\n  @override\n  String toString() {\n    return json.encode({\n      \"roomId\": roomId,\n      \"token\": token,\n      \"serverHost\": serverHost,\n      \"buvid\": buvid,\n      \"uid\": uid,\n      \"cookie\": cookie,\n    });\n  }\n}\n\nclass BiliBiliDanmaku implements LiveDanmaku {\n  @override\n  int heartbeatTime = 60 * 1000;\n\n  @override\n  Function(LiveMessage msg)? onMessage;\n  @override\n  Function(String msg)? onClose;\n  @override\n  Function()? onReady;\n\n  //String serverUrl = \"wss://broadcastlv.chat.bilibili.com/sub\";\n\n  WebScoketUtils? webScoketUtils;\n  late BiliBiliDanmakuArgs danmakuArgs;\n  @override\n  Future start(dynamic args) async {\n    danmakuArgs = args as BiliBiliDanmakuArgs;\n    webScoketUtils = WebScoketUtils(\n      url: \"wss://${args.serverHost}/sub\",\n      heartBeatTime: heartbeatTime,\n      headers: args.cookie.isEmpty\n          ? null\n          : {\n              \"cookie\": args.cookie,\n            },\n      onMessage: (e) {\n        decodeMessage(e);\n      },\n      onReady: () {\n        onReady?.call();\n        joinRoom(danmakuArgs);\n      },\n      onHeartBeat: () {\n        heartbeat();\n      },\n      onReconnect: () {\n        onClose?.call(\"与服务器断开连接，正在尝试重连\");\n      },\n      onClose: (e) {\n        onClose?.call(\"服务器连接失败$e\");\n      },\n    );\n    webScoketUtils?.connect();\n  }\n\n  void joinRoom(BiliBiliDanmakuArgs args) {\n    var joinData = encodeData(\n      json.encode({\n        \"uid\": args.uid,\n        \"roomid\": args.roomId,\n        \"protover\": 3,\n        \"buvid\": args.buvid,\n        \"platform\": \"web\",\n        \"type\": 2,\n        \"key\": args.token,\n      }),\n      7,\n    );\n    webScoketUtils?.sendMessage(joinData);\n  }\n\n  @override\n  void heartbeat() {\n    webScoketUtils?.sendMessage(encodeData(\n      \"\",\n      2,\n    ));\n  }\n\n  @override\n  Future stop() async {\n    onMessage = null;\n    onClose = null;\n    webScoketUtils?.close();\n  }\n\n  List<int> encodeData(String msg, int action) {\n    var data = utf8.encode(msg);\n    //头部长度固定16\n    var length = data.length + 16;\n    var buffer = Uint8List(length);\n\n    var writer = BinaryWriter([]);\n\n    //数据包长度\n    writer.writeInt(buffer.length, 4);\n    //数据包头部长度,固定16\n    writer.writeInt(16, 2);\n\n    //协议版本，0=JSON,1=Int32,2=Buffer\n    writer.writeInt(0, 2);\n\n    //操作类型\n    writer.writeInt(action, 4);\n\n    //数据包头部长度,固定1\n\n    writer.writeInt(1, 4);\n\n    writer.writeBytes(data);\n\n    return writer.buffer;\n  }\n\n  void decodeMessage(List<int> data) {\n    try {\n      //协议版本。0为JSON，可以直接解析；1为房间人气值,Body为4位Int32；2为压缩过Buffer，需要解压再处理\n      int protocolVersion = readInt(data, 6, 2);\n      //操作类型。3=心跳回应，内容为房间人气值；5=通知，弹幕、广播等全部信息；8=进房回应，空\n      int operation = readInt(data, 8, 4);\n      //内容\n      var body = data.skip(16).toList();\n      if (operation == 3) {\n        var online = readInt(body, 0, 4);\n\n        onMessage?.call(\n          LiveMessage(\n            type: LiveMessageType.online,\n            data: online,\n            color: LiveMessageColor.white,\n            message: \"\",\n            userName: \"\",\n          ),\n        );\n      } else if (operation == 5) {\n        if (protocolVersion == 2) {\n          body = zlib.decode(body);\n        } else if (protocolVersion == 3) {\n          body = brotli.decode(body);\n        }\n\n        var text = utf8.decode(body, allowMalformed: true);\n\n        var group =\n            text.split(RegExp(r\"[\\x00-\\x1f]+\", unicode: true, multiLine: true));\n        for (var item\n            in group.where((x) => x.length > 2 && x.startsWith('{'))) {\n          parseMessage(item);\n        }\n      }\n    } catch (e) {\n      CoreLog.error(e);\n    }\n  }\n\n  void parseMessage(String jsonMessage) {\n    try {\n      var obj = json.decode(jsonMessage);\n      var cmd = obj[\"cmd\"].toString();\n      if (cmd.contains(\"DANMU_MSG\")) {\n        if (obj[\"info\"] != null && obj[\"info\"].length != 0) {\n          var message = obj[\"info\"][1].toString();\n          var color = asT<int?>(obj[\"info\"][0][3]) ?? 0;\n          if (obj[\"info\"][2] != null && obj[\"info\"][2].length != 0) {\n            var username = obj[\"info\"][2][1].toString();\n            var liveMsg = LiveMessage(\n              type: LiveMessageType.chat,\n              userName: username,\n              message: message,\n              color: color == 0\n                  ? LiveMessageColor.white\n                  : LiveMessageColor.numberToColor(color),\n            );\n            onMessage?.call(liveMsg);\n          }\n        }\n      } else if (cmd == \"SUPER_CHAT_MESSAGE\") {\n        if (obj[\"data\"] == null) {\n          return;\n        }\n        LiveSuperChatMessage sc = LiveSuperChatMessage(\n          backgroundBottomColor:\n              obj[\"data\"][\"background_bottom_color\"].toString(),\n          backgroundColor: obj[\"data\"][\"background_color\"].toString(),\n          endTime: DateTime.fromMillisecondsSinceEpoch(\n            obj[\"data\"][\"end_time\"] * 1000,\n          ),\n          face: \"${obj[\"data\"][\"user_info\"][\"face\"]}@200w.jpg\",\n          message: obj[\"data\"][\"message\"].toString(),\n          price: obj[\"data\"][\"price\"],\n          startTime: DateTime.fromMillisecondsSinceEpoch(\n            obj[\"data\"][\"start_time\"] * 1000,\n          ),\n          userName: obj[\"data\"][\"user_info\"][\"uname\"].toString(),\n        );\n        var liveMsg = LiveMessage(\n          type: LiveMessageType.superChat,\n          userName: \"SUPER_CHAT_MESSAGE\",\n          message: \"SUPER_CHAT_MESSAGE\",\n          color: LiveMessageColor.white,\n          data: sc,\n        );\n        onMessage?.call(liveMsg);\n      }\n    } catch (e) {\n      CoreLog.error(e);\n    }\n  }\n\n  int readInt(List<int> buffer, int start, int len) {\n    var bytes =\n        Uint8List.fromList(buffer.getRange(start, start + len).toList());\n    var byteBuffer = bytes.buffer;\n    var data = ByteData.view(byteBuffer);\n    var result = 0;\n\n    if (len == 1) {\n      result = data.getUint8(0);\n    }\n    if (len == 2) {\n      result = data.getInt16(0, Endian.big);\n    }\n    if (len == 4) {\n      result = data.getInt32(0, Endian.big);\n    }\n    if (len == 8) {\n      result = data.getInt64(0, Endian.big);\n    }\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/douyin_danmaku.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:io';\n\nimport 'package:crypto/crypto.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/platforms/douyin/douyin_request_params.dart';\nimport 'package:simple_live_core/src/common/js_engine.dart';\nimport 'package:simple_live_core/src/common/web_socket_util.dart';\n\nimport 'proto/douyin.pb.dart';\n\nclass DouyinDanmakuArgs {\n  final String webRid;\n  final String roomId;\n  final String userId;\n  final String cookie;\n\n  DouyinDanmakuArgs({\n    required this.webRid,\n    required this.roomId,\n    required this.userId,\n    required this.cookie,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"webRid\": webRid,\n      \"roomId\": roomId,\n      \"userId\": userId,\n      \"cookie\": cookie,\n    });\n  }\n}\n\nclass DouyinDanmaku implements LiveDanmaku {\n  @override\n  int heartbeatTime = 10 * 1000;\n\n  @override\n  Function(LiveMessage msg)? onMessage;\n  @override\n  Function(String msg)? onClose;\n  @override\n  Function()? onReady;\n  String serverUrl = \"wss://webcast3-ws-web-lq.douyin.com/webcast/im/push/v2/\";\n  late DouyinDanmakuArgs danmakuArgs;\n  WebScoketUtils? webScoketUtils;\n\n  @override\n  Future start(dynamic args) async {\n    danmakuArgs = args as DouyinDanmakuArgs;\n    var ts = DateTime.now().millisecondsSinceEpoch;\n    var uri = Uri.parse(serverUrl).replace(scheme: \"wss\", queryParameters: {\n      \"app_name\": \"douyin_web\",\n      \"version_code\": DouyinRequestParams.versionCodeValue,\n      \"webcast_sdk_version\": DouyinRequestParams.sdkVersion,\n      \"update_version_code\": DouyinRequestParams.sdkVersion,\n      \"compress\": \"gzip\",\n      // \"internal_ext\":\n      //     \"internal_src:dim|wss_push_room_id:${danmakuArgs.roomId}|wss_push_did:${danmakuArgs.userId}|dim_log_id:20230626152702E8F63662383A350588E1|fetch_time:1687764422114|seq:1|wss_info:0-1687764422114-0-0|wrds_kvs:WebcastRoomRankMessage-1687764036509597990_InputPanelComponentSyncData-1687736682345173033_WebcastRoomStatsMessage-1687764414427812578\",\n      \"cursor\": \"h-1_t-${ts}_r-1_d-1_u-1\",\n      \"host\": \"https://live.douyin.com\",\n      \"aid\": \"6383\",\n      \"live_id\": \"1\",\n      \"did_rule\": \"3\",\n      \"debug\": \"false\",\n      \"maxCacheMessageNumber\": \"20\",\n      \"endpoint\": \"live_pc\",\n      \"support_wrds\": \"1\",\n      \"im_path\": \"/webcast/im/fetch/\",\n      \"user_unique_id\": danmakuArgs.userId,\n      \"device_platform\": \"web\",\n      \"cookie_enabled\": \"true\",\n      \"screen_width\": \"1920\",\n      \"screen_height\": \"1080\",\n      \"browser_language\": \"zh-CN\",\n      \"browser_platform\": \"Win32\",\n      \"browser_name\": \"Mozilla\",\n      \"browser_version\":\n          DouyinRequestParams.kDefaultUserAgent.replaceAll(\"Mozilla/\", \"\"),\n      \"browser_online\": \"true\",\n      \"tz_name\": \"Asia/Shanghai\",\n      \"identity\": \"audience\",\n      \"room_id\": danmakuArgs.roomId,\n      \"heartbeatDuration\": \"0\",\n      //\"signature\": \"00000000\"\n    });\n\n    var sign = await getSignature(danmakuArgs.roomId, danmakuArgs.userId);\n\n    var url = \"$uri&signature=$sign\";\n    var backupUrl = url.replaceAll(\"webcast3-ws-web-lq\", \"webcast5-ws-web-lf\");\n    webScoketUtils = WebScoketUtils(\n      url: url,\n      backupUrl: backupUrl,\n      headers: {\n        \"User-Agent\": DouyinRequestParams.kDefaultUserAgent,\n        \"Cookie\": danmakuArgs.cookie,\n        \"Origin\": \"https://live.douyin.com\"\n      },\n      heartBeatTime: heartbeatTime,\n      onMessage: (e) {\n        try{\n          decodeMessage(e);\n        }catch(e){\n          CoreLog.error(\"douyin_danmaku_error$e\");\n        }\n      },\n      onReady: () {\n        onReady?.call();\n        joinRoom(args);\n      },\n      onHeartBeat: () {\n        heartbeat();\n      },\n      onReconnect: () {\n        onClose?.call(\"与服务器断开连接，正在尝试重连\");\n      },\n      onClose: (e) {\n        onClose?.call(\"服务器连接失败$e\");\n      },\n    );\n    webScoketUtils?.connect();\n  }\n\n  @override\n  void heartbeat() {\n    var obj = PushFrame();\n    obj.payloadType = 'hb';\n    webScoketUtils?.sendMessage(obj.writeToBuffer());\n  }\n\n  void decodeMessage(List<int> args) {\n    // CoreLog.i(args.toString());\n\n    var wssPackage = PushFrame.fromBuffer(args);\n\n    var logId = wssPackage.logId;\n    var decompressed = gzip.decode(wssPackage.payload);\n    var payloadPackage = Response.fromBuffer(decompressed);\n    if (payloadPackage.needAck) {\n      sendAck(logId, payloadPackage.internalExt);\n      //return;\n    }\n    for (var msg in payloadPackage.messagesList) {\n      if (msg.method == 'WebcastChatMessage') {\n        unPackWebcastChatMessage(msg.payload);\n      } else if (msg.method == 'WebcastRoomUserSeqMessage') {\n        unPackWebcastRoomUserSeqMessage(msg.payload);\n      }\n    }\n  }\n\n  void unPackWebcastChatMessage(List<int> payload) {\n    var chatMessage = ChatMessage.fromBuffer(payload);\n    onMessage?.call(\n      LiveMessage(\n        type: LiveMessageType.chat,\n        color: LiveMessageColor.white,\n        //暂不知道具体怎么转换颜色\n        // color: chatMessage.common.fullScreenTextColor.\n        //     ? LiveMessageColor.white\n        //     : LiveMessageColor.numberToColor(color),\n        message: chatMessage.content,\n        userName: chatMessage.user.nickName,\n      ),\n    );\n  }\n\n  void unPackWebcastRoomUserSeqMessage(List<int> payload) {\n    var roomUserSeqMessage = RoomUserSeqMessage.fromBuffer(payload);\n\n    onMessage?.call(\n      LiveMessage(\n        type: LiveMessageType.online,\n        data: roomUserSeqMessage.totalUser.toInt(),\n        color: LiveMessageColor.white,\n        message: \"\",\n        userName: \"\",\n      ),\n    );\n  }\n\n  void sendAck(dynamic logId, String internalExt) {\n    var obj = PushFrame();\n    obj.payloadType = 'ack';\n    obj.logId = logId;\n    obj.payloadType = internalExt;\n    webScoketUtils?.sendMessage(obj.writeToBuffer());\n  }\n\n  void joinRoom(dynamic args) {\n    var obj = PushFrame();\n    obj.payloadType = 'hb';\n    webScoketUtils?.sendMessage(obj.writeToBuffer());\n  }\n\n  @override\n  Future stop() async {\n    onMessage = null;\n    onClose = null;\n    webScoketUtils?.close();\n  }\n\n  /// 获取Websocket签名\n  /// - [roomId] 房间ID, 例如：7382735338101328680\n  /// - [uniqueId] 用户唯一ID, 例如：7273033021933946427\n  /// 参考代码 hua/stream-rec\n  /// 服务端代码：https://github.com/lovelyyoshino/douyin_python，请自行部署后使用\n  /// 自部署 https://github.com/SlotSun/simple_live_api\n  Future<String> getSignature(String roomId, String uniqueId) async {\n    try {\n      Map<String, dynamic> params = {\n        \"live_id\": \"1\",\n        \"aid\": \"6383\",\n        \"version_code\": DouyinRequestParams.versionCodeValue,\n        \"webcast_sdk_version\": DouyinRequestParams.sdkVersion,\n        \"room_id\": roomId,\n        \"sub_room_id\": \"\",\n        \"sub_channel_id\": \"\",\n        \"did_rule\": \"3\",\n        \"user_unique_id\": uniqueId,\n        \"device_platform\": \"web\",\n        \"device_type\": \"\",\n        \"ac\": \"\",\n        \"identity\": \"audience\",\n      };\n      JsEngine.init();\n      await JsEngine.loadJSFile(\n          'packages/simple_live_core/assets/js/douyin-webmssdk.js');\n      String sigParam = params.entries\n          .map((entry) => '${entry.key}=${entry.value}')\n          .join(',');\n      var md5SigParam = md5.convert(utf8.encode(sigParam)).toString();\n      var jsEvalResult = JsEngine.evaluate(\"get_sign('$md5SigParam')\");\n      return jsEvalResult.toString();\n    } catch (e) {\n      CoreLog.error(e);\n      return \"\";\n    } finally {\n      JsEngine.dispose();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/douyu_danmaku.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:typed_data';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/web_socket_util.dart';\n\nimport '../common/binary_writer.dart';\n\nclass DouyuDanmaku implements LiveDanmaku {\n  @override\n  int heartbeatTime = 45 * 1000;\n\n  @override\n  Function(LiveMessage msg)? onMessage;\n  @override\n  Function(String msg)? onClose;\n  @override\n  Function()? onReady;\n  String serverUrl = \"wss://danmuproxy.douyu.com:8506\";\n\n  WebScoketUtils? webScoketUtils;\n\n  @override\n  Future start(dynamic args) async {\n    webScoketUtils = WebScoketUtils(\n      url: serverUrl,\n      heartBeatTime: heartbeatTime,\n      onMessage: (e) {\n        decodeMessage(e);\n      },\n      onReady: () {\n        onReady?.call();\n        joinRoom(args);\n      },\n      onHeartBeat: () {\n        heartbeat();\n      },\n      onReconnect: () {\n        onClose?.call(\"与服务器断开连接，正在尝试重连\");\n      },\n      onClose: (e) {\n        onClose?.call(\"服务器连接失败$e\");\n      },\n    );\n    webScoketUtils?.connect();\n  }\n\n  void joinRoom(String roomId) {\n    webScoketUtils\n        ?.sendMessage(serializeDouyu(\"type@=loginreq/roomid@=$roomId/\"));\n    webScoketUtils?.sendMessage(\n        serializeDouyu(\"type@=joingroup/rid@=$roomId/gid@=-9999/\"));\n  }\n\n  @override\n  void heartbeat() {\n    var data = serializeDouyu(\"type@=mrkl/\");\n    webScoketUtils?.sendMessage(data);\n  }\n\n  @override\n  Future stop() async {\n    onMessage = null;\n    onClose = null;\n    webScoketUtils?.close();\n  }\n\n  void decodeMessage(List<int> data) {\n    try {\n      String? result = deserializeDouyu(data);\n      if (result == null) {\n        return;\n      }\n      var jsonData = sttToJObject(result);\n\n      var type = jsonData[\"type\"]?.toString();\n      var fans = jsonData[\"if\"] ?? '0'.toString();\n      //斗鱼好像不会返回人气值\n      //有些直播间存在阴间弹幕，不知道什么情况\n      //只显示粉丝发言\n      LiveMessage? liveMsg;\n      if (type == \"chatmsg\" && fans == '1') {\n        var col = int.tryParse(jsonData[\"col\"].toString()) ?? 0;\n        liveMsg = LiveMessage(\n          type: LiveMessageType.chat,\n          userName: jsonData[\"nn\"].toString(),\n          message: jsonData[\"txt\"].toString(),\n          color: getColor(col),\n        );\n      } else if (type == \"comm_chatmsg\") {\n        DateTime curTimestamp = DateTime.fromMillisecondsSinceEpoch(\n          int.parse(jsonData[\"now\"]),\n        );\n        var face = \"\";\n        try {\n          // 疑似换接口了\n          face = jsonData[\"chatmsg\"][\"ic\"];\n        } catch (e) {\n          CoreLog.error(\"DouyuSuperChat-face:$e\");\n        }\n        LiveSuperChatMessage sc = LiveSuperChatMessage(\n          // 斗鱼没有颜色 调整配色方案-偏紫色系\n          backgroundBottomColor: \"#292a60\",\n          backgroundColor: \"#c1c1ff\",\n          endTime:\n              curTimestamp.add(Duration(seconds: int.parse(jsonData[\"cet\"]))),\n          face: \"https://apic.douyucdn.cn/upload/${face}_small.jpg\",\n          message: jsonData[\"chatmsg\"][\"txt\"].toString(),\n          price: int.parse(jsonData[\"cprice\"]) ~/ 100,\n          startTime: curTimestamp,\n          userName: jsonData[\"chatmsg\"][\"nn\"].toString(),\n        );\n        liveMsg = LiveMessage(\n          type: LiveMessageType.superChat,\n          userName: \"SUPER_CHAT_MESSAGE\",\n          message: \"SUPER_CHAT_MESSAGE\",\n          color: LiveMessageColor.white,\n          data: sc,\n        );\n      } else if (type == \"voice_trlt\") {\n        // 高能弹幕2\n        var scData = jsonData[\"list\"][0];\n        LiveSuperChatMessage sc2 = LiveSuperChatMessage(\n          // 斗鱼没有颜色 调整配色方案\n          backgroundBottomColor: \"#246488\",\n          backgroundColor: \"#ffffff\",\n          endTime: DateTime.fromMillisecondsSinceEpoch(\n            int.parse(scData[\"etime\"]) * 1000,\n          ),\n          face: \"https://${scData[\"uat\"][1]}\",\n          message: scData[\"content\"].toString(),\n          price: int.parse(scData[\"realPrice\"]) ~/ 100,\n          startTime: DateTime.fromMillisecondsSinceEpoch(\n            int.parse(scData[\"acptime\"]) * 1000,\n          ),\n          userName: scData[\"un\"].toString(),\n        );\n        liveMsg = LiveMessage(\n          type: LiveMessageType.superChat,\n          userName: \"SUPER_CHAT_MESSAGE\",\n          message: \"SUPER_CHAT_MESSAGE\",\n          color: LiveMessageColor.white,\n          data: sc2,\n        );\n      } else if (type != \"uenter\") {\n      }\n      if (liveMsg != null) {\n        onMessage?.call(liveMsg);\n      }\n    } catch (e) {\n      CoreLog.error(\"DouyuSuperChat:$e\");\n    }\n  }\n\n  List<int> serializeDouyu(String body) {\n    try {\n      const int clientSendToServer = 689;\n      const int encrypted = 0;\n      const int reserved = 0;\n\n      List<int> buffer = utf8.encode(body);\n\n      var writer = BinaryWriter([]);\n      writer.writeInt(4 + 4 + body.length + 1, 4, endian: Endian.little);\n      writer.writeInt(4 + 4 + body.length + 1, 4, endian: Endian.little);\n      writer.writeInt(clientSendToServer, 2, endian: Endian.little);\n      writer.writeInt(encrypted, 1, endian: Endian.little);\n      writer.writeInt(reserved, 1, endian: Endian.little);\n      writer.writeBytes(buffer);\n      writer.writeInt(0, 1, endian: Endian.little);\n      return writer.buffer;\n    } catch (e) {\n      CoreLog.error(e);\n      return [];\n    }\n  }\n\n  String? deserializeDouyu(List<int> buffer) {\n    try {\n      var reader = BinaryReader(Uint8List.fromList(buffer));\n      int fullMsgLength =\n          reader.readInt32(endian: Endian.little); //fullMsgLength\n      reader.readInt32(endian: Endian.little); //fullMsgLength2\n      int bodyLength = fullMsgLength - 9;\n      reader.readShort(endian: Endian.little); //packType\n      reader.readByte(endian: Endian.little); //encrypted\n      reader.readByte(endian: Endian.little); //reserved\n\n      var bytes = reader.readBytes(bodyLength);\n\n      reader.readByte(endian: Endian.little); //固定为0\n      return utf8.decode(bytes);\n    } catch (e) {\n      CoreLog.error(e);\n      return null;\n    }\n  }\n\n  //辣鸡STT\n  dynamic sttToJObject(String str) {\n    if (str.contains(\"//\")) {\n      var result = [];\n      for (var field in str.split(\"//\")) {\n        if (field.isEmpty) {\n          continue;\n        }\n        result.add(sttToJObject(field));\n      }\n      return result;\n    }\n    if (str.contains(\"@=\")) {\n      var result = {};\n      for (var field in str.split('/')) {\n        if (field.isEmpty) {\n          continue;\n        }\n        var tokens = field.split(\"@=\");\n        var k = tokens[0];\n        var v = unscapeSlashAt(tokens[1]);\n        result[k] = sttToJObject(v);\n      }\n      return result;\n    } else if (str.contains(\"@A=\")) {\n      return sttToJObject(unscapeSlashAt(str));\n    } else {\n      return unscapeSlashAt(str);\n    }\n  }\n\n  String unscapeSlashAt(String str) {\n    return str.replaceAll(\"@S\", \"/\").replaceAll(\"@A\", \"@\");\n  }\n\n  LiveMessageColor getColor(int type) {\n    switch (type) {\n      case 1:\n        return LiveMessageColor(255, 0, 0);\n      case 2:\n        return LiveMessageColor(30, 135, 240);\n      case 3:\n        return LiveMessageColor(122, 200, 75);\n      case 4:\n        return LiveMessageColor(255, 127, 0);\n      case 5:\n        return LiveMessageColor(155, 57, 244);\n      case 6:\n        return LiveMessageColor(255, 105, 180);\n      default:\n        return LiveMessageColor.white;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/huya_danmaku.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:typed_data';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/web_socket_util.dart';\nimport 'package:simple_live_core/src/model/tars/huya_danmaku.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\n\nclass HuyaDanmakuArgs {\n  final int ayyuid;\n  final int topSid;\n  final int subSid;\n  HuyaDanmakuArgs({\n    required this.ayyuid,\n    required this.topSid,\n    required this.subSid,\n  });\n  @override\n  String toString() {\n    return json.encode({\n      \"ayyuid\": ayyuid,\n      \"topSid\": topSid,\n      \"subSid\": subSid,\n    });\n  }\n}\n\nclass HuyaDanmaku implements LiveDanmaku {\n  @override\n  int heartbeatTime = 60 * 1000;\n\n  @override\n  Function(LiveMessage msg)? onMessage;\n  @override\n  Function(String msg)? onClose;\n  @override\n  Function()? onReady;\n  String serverUrl = \"wss://cdnws.api.huya.com\";\n\n  WebScoketUtils? webScoketUtils;\n\n  final heartbeatData = base64.decode(\"ABQdAAwsNgBM\");\n\n  late HuyaDanmakuArgs danmakuArgs;\n\n  @override\n  Future start(dynamic args) async {\n    danmakuArgs = args as HuyaDanmakuArgs;\n    webScoketUtils = WebScoketUtils(\n      url: serverUrl,\n      heartBeatTime: heartbeatTime,\n      onMessage: (e) {\n        decodeMessage(e);\n      },\n      onReady: () {\n        onReady?.call();\n        joinRoom();\n      },\n      onHeartBeat: () {\n        heartbeat();\n      },\n      onReconnect: () {\n        onClose?.call(\"与服务器断开连接，正在尝试重连\");\n      },\n      onClose: (e) {\n        onClose?.call(\"服务器连接失败$e\");\n      },\n    );\n    webScoketUtils?.connect();\n  }\n\n  void joinRoom() {\n    var joinData =\n        getJoinData(danmakuArgs.ayyuid, danmakuArgs.topSid, danmakuArgs.topSid);\n    webScoketUtils?.sendMessage(joinData);\n  }\n\n  List<int> getJoinData(int ayyuid, int tid, int sid) {\n    try {\n      var oos = TarsOutputStream();\n      oos.write(ayyuid, 0);\n      oos.write(true, 1);\n      oos.write(\"\", 2);\n      oos.write(\"\", 3);\n      oos.write(tid, 4);\n      oos.write(sid, 5);\n      oos.write(0, 6);\n      oos.write(0, 7);\n\n      var wscmd = TarsOutputStream();\n      wscmd.write(1, 0);\n      wscmd.write(oos.toUint8List(), 1);\n      return wscmd.toUint8List();\n    } catch (e) {\n      CoreLog.error(e);\n      return [];\n    }\n  }\n\n  @override\n  void heartbeat() {\n    webScoketUtils?.sendMessage(heartbeatData);\n  }\n\n  @override\n  Future stop() async {\n    onMessage = null;\n    onClose = null;\n    webScoketUtils?.close();\n  }\n\n  void decodeMessage(List<int> data) {\n    try {\n      var stream = TarsInputStream(Uint8List.fromList(data));\n      var type = stream.read(0, 0, false);\n      if (type == 7) {\n        stream = TarsInputStream(stream.readBytes(1, false));\n        HYPushMessage wSPushMessage = HYPushMessage();\n        wSPushMessage.readFrom(stream);\n        if (wSPushMessage.uri == 1400) {\n          HYMessage messageNotice = HYMessage();\n          messageNotice\n              .readFrom(TarsInputStream(Uint8List.fromList(wSPushMessage.msg)));\n          var uname = messageNotice.userInfo.nickName;\n          var content = messageNotice.content;\n\n          var color = messageNotice.bulletFormat.fontColor;\n\n          onMessage?.call(\n            LiveMessage(\n              type: LiveMessageType.chat,\n              color: color <= 0\n                  ? LiveMessageColor.white\n                  : LiveMessageColor.numberToColor(color),\n              message: content,\n              userName: uname,\n            ),\n          );\n        } else if (wSPushMessage.uri == 8006) {\n          int online = 0;\n          var s = TarsInputStream(Uint8List.fromList(wSPushMessage.msg));\n          online = s.read(online, 0, false);\n          onMessage?.call(\n            LiveMessage(\n              type: LiveMessageType.online,\n              data: online,\n              color: LiveMessageColor.white,\n              message: \"\",\n              userName: \"\",\n            ),\n          );\n        }\n      }\n    } catch (e) {\n      CoreLog.error(e);\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/proto/douyin.pb.dart",
    "content": "// This is a generated file - do not edit.\n//\n// Generated from douyin.proto.\n\n// @dart = 3.3\n\n// ignore_for_file: annotate_overrides, camel_case_types, comment_references\n// ignore_for_file: constant_identifier_names\n// ignore_for_file: curly_braces_in_flow_control_structures\n// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes\n// ignore_for_file: non_constant_identifier_names, prefer_relative_imports\n\nimport 'dart:core' as $core;\n\nimport 'package:fixnum/fixnum.dart' as $fixnum;\nimport 'package:protobuf/protobuf.dart' as $pb;\n\nimport 'douyin.pbenum.dart';\n\nexport 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;\n\nexport 'douyin.pbenum.dart';\n\nclass Response extends $pb.GeneratedMessage {\n  factory Response({\n    $core.Iterable<Message>? messagesList,\n    $core.String? cursor,\n    $fixnum.Int64? fetchInterval,\n    $fixnum.Int64? now,\n    $core.String? internalExt,\n    $core.int? fetchType,\n    $core.Iterable<$core.MapEntry<$core.String, $core.String>>? routeParams,\n    $fixnum.Int64? heartbeatDuration,\n    $core.bool? needAck,\n    $core.String? pushServer,\n    $core.String? liveCursor,\n    $core.bool? historyNoMore,\n  }) {\n    final result = create();\n    if (messagesList != null) result.messagesList.addAll(messagesList);\n    if (cursor != null) result.cursor = cursor;\n    if (fetchInterval != null) result.fetchInterval = fetchInterval;\n    if (now != null) result.now = now;\n    if (internalExt != null) result.internalExt = internalExt;\n    if (fetchType != null) result.fetchType = fetchType;\n    if (routeParams != null) result.routeParams.addEntries(routeParams);\n    if (heartbeatDuration != null) result.heartbeatDuration = heartbeatDuration;\n    if (needAck != null) result.needAck = needAck;\n    if (pushServer != null) result.pushServer = pushServer;\n    if (liveCursor != null) result.liveCursor = liveCursor;\n    if (historyNoMore != null) result.historyNoMore = historyNoMore;\n    return result;\n  }\n\n  Response._();\n\n  factory Response.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Response.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Response',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..pPM<Message>(1, _omitFieldNames ? '' : 'messagesList',\n        protoName: 'messagesList', subBuilder: Message.create)\n    ..aOS(2, _omitFieldNames ? '' : 'cursor')\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'fetchInterval', $pb.PbFieldType.OU6,\n        protoName: 'fetchInterval', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'now', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(5, _omitFieldNames ? '' : 'internalExt', protoName: 'internalExt')\n    ..aI(6, _omitFieldNames ? '' : 'fetchType',\n        protoName: 'fetchType', fieldType: $pb.PbFieldType.OU3)\n    ..m<$core.String, $core.String>(7, _omitFieldNames ? '' : 'routeParams',\n        protoName: 'routeParams',\n        entryClassName: 'Response.RouteParamsEntry',\n        keyFieldType: $pb.PbFieldType.OS,\n        valueFieldType: $pb.PbFieldType.OS,\n        packageName: const $pb.PackageName('douyin'))\n    ..a<$fixnum.Int64>(\n        8, _omitFieldNames ? '' : 'heartbeatDuration', $pb.PbFieldType.OU6,\n        protoName: 'heartbeatDuration', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(9, _omitFieldNames ? '' : 'needAck', protoName: 'needAck')\n    ..aOS(10, _omitFieldNames ? '' : 'pushServer', protoName: 'pushServer')\n    ..aOS(11, _omitFieldNames ? '' : 'liveCursor', protoName: 'liveCursor')\n    ..aOB(12, _omitFieldNames ? '' : 'historyNoMore',\n        protoName: 'historyNoMore')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Response clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Response copyWith(void Function(Response) updates) =>\n      super.copyWith((message) => updates(message as Response)) as Response;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Response create() => Response._();\n  @$core.override\n  Response createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Response getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Response>(create);\n  static Response? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $pb.PbList<Message> get messagesList => $_getList(0);\n\n  @$pb.TagNumber(2)\n  $core.String get cursor => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set cursor($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasCursor() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearCursor() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get fetchInterval => $_getI64(2);\n  @$pb.TagNumber(3)\n  set fetchInterval($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasFetchInterval() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearFetchInterval() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get now => $_getI64(3);\n  @$pb.TagNumber(4)\n  set now($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasNow() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearNow() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.String get internalExt => $_getSZ(4);\n  @$pb.TagNumber(5)\n  set internalExt($core.String value) => $_setString(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasInternalExt() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearInternalExt() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get fetchType => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set fetchType($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasFetchType() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearFetchType() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $pb.PbMap<$core.String, $core.String> get routeParams => $_getMap(6);\n\n  @$pb.TagNumber(8)\n  $fixnum.Int64 get heartbeatDuration => $_getI64(7);\n  @$pb.TagNumber(8)\n  set heartbeatDuration($fixnum.Int64 value) => $_setInt64(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasHeartbeatDuration() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearHeartbeatDuration() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $core.bool get needAck => $_getBF(8);\n  @$pb.TagNumber(9)\n  set needAck($core.bool value) => $_setBool(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasNeedAck() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearNeedAck() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $core.String get pushServer => $_getSZ(9);\n  @$pb.TagNumber(10)\n  set pushServer($core.String value) => $_setString(9, value);\n  @$pb.TagNumber(10)\n  $core.bool hasPushServer() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearPushServer() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $core.String get liveCursor => $_getSZ(10);\n  @$pb.TagNumber(11)\n  set liveCursor($core.String value) => $_setString(10, value);\n  @$pb.TagNumber(11)\n  $core.bool hasLiveCursor() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearLiveCursor() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.bool get historyNoMore => $_getBF(11);\n  @$pb.TagNumber(12)\n  set historyNoMore($core.bool value) => $_setBool(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasHistoryNoMore() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearHistoryNoMore() => $_clearField(12);\n}\n\nclass Message extends $pb.GeneratedMessage {\n  factory Message({\n    $core.String? method,\n    $core.List<$core.int>? payload,\n    $fixnum.Int64? msgId,\n    $core.int? msgType,\n    $fixnum.Int64? offset,\n    $core.bool? needWrdsStore,\n    $fixnum.Int64? wrdsVersion,\n    $core.String? wrdsSubKey,\n  }) {\n    final result = create();\n    if (method != null) result.method = method;\n    if (payload != null) result.payload = payload;\n    if (msgId != null) result.msgId = msgId;\n    if (msgType != null) result.msgType = msgType;\n    if (offset != null) result.offset = offset;\n    if (needWrdsStore != null) result.needWrdsStore = needWrdsStore;\n    if (wrdsVersion != null) result.wrdsVersion = wrdsVersion;\n    if (wrdsSubKey != null) result.wrdsSubKey = wrdsSubKey;\n    return result;\n  }\n\n  Message._();\n\n  factory Message.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Message.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Message',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'method')\n    ..a<$core.List<$core.int>>(\n        2, _omitFieldNames ? '' : 'payload', $pb.PbFieldType.OY)\n    ..aInt64(3, _omitFieldNames ? '' : 'msgId', protoName: 'msgId')\n    ..aI(4, _omitFieldNames ? '' : 'msgType', protoName: 'msgType')\n    ..aInt64(5, _omitFieldNames ? '' : 'offset')\n    ..aOB(6, _omitFieldNames ? '' : 'needWrdsStore', protoName: 'needWrdsStore')\n    ..aInt64(7, _omitFieldNames ? '' : 'wrdsVersion', protoName: 'wrdsVersion')\n    ..aOS(8, _omitFieldNames ? '' : 'wrdsSubKey', protoName: 'wrdsSubKey')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Message clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Message copyWith(void Function(Message) updates) =>\n      super.copyWith((message) => updates(message as Message)) as Message;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Message create() => Message._();\n  @$core.override\n  Message createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Message getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Message>(create);\n  static Message? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get method => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set method($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasMethod() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearMethod() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.List<$core.int> get payload => $_getN(1);\n  @$pb.TagNumber(2)\n  set payload($core.List<$core.int> value) => $_setBytes(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasPayload() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearPayload() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get msgId => $_getI64(2);\n  @$pb.TagNumber(3)\n  set msgId($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasMsgId() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearMsgId() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.int get msgType => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set msgType($core.int value) => $_setSignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasMsgType() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearMsgType() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $fixnum.Int64 get offset => $_getI64(4);\n  @$pb.TagNumber(5)\n  set offset($fixnum.Int64 value) => $_setInt64(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasOffset() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearOffset() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.bool get needWrdsStore => $_getBF(5);\n  @$pb.TagNumber(6)\n  set needWrdsStore($core.bool value) => $_setBool(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasNeedWrdsStore() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearNeedWrdsStore() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $fixnum.Int64 get wrdsVersion => $_getI64(6);\n  @$pb.TagNumber(7)\n  set wrdsVersion($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasWrdsVersion() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearWrdsVersion() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.String get wrdsSubKey => $_getSZ(7);\n  @$pb.TagNumber(8)\n  set wrdsSubKey($core.String value) => $_setString(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasWrdsSubKey() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearWrdsSubKey() => $_clearField(8);\n}\n\n/// 聊天\nclass ChatMessage extends $pb.GeneratedMessage {\n  factory ChatMessage({\n    Common? common,\n    User? user,\n    $core.String? content,\n    $core.bool? visibleToSender,\n    Image? backgroundImage,\n    $core.String? fullScreenTextColor,\n    Image? backgroundImageV2,\n    PublicAreaCommon? publicAreaCommon,\n    Image? giftImage,\n    $fixnum.Int64? agreeMsgId,\n    $core.int? priorityLevel,\n    LandscapeAreaCommon? landscapeAreaCommon,\n    $fixnum.Int64? eventTime,\n    $core.bool? sendReview,\n    $core.bool? fromIntercom,\n    $core.bool? intercomHideUserCard,\n    $core.String? chatBy,\n    $core.int? individualChatPriority,\n    Text? rtfContent,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (user != null) result.user = user;\n    if (content != null) result.content = content;\n    if (visibleToSender != null) result.visibleToSender = visibleToSender;\n    if (backgroundImage != null) result.backgroundImage = backgroundImage;\n    if (fullScreenTextColor != null)\n      result.fullScreenTextColor = fullScreenTextColor;\n    if (backgroundImageV2 != null) result.backgroundImageV2 = backgroundImageV2;\n    if (publicAreaCommon != null) result.publicAreaCommon = publicAreaCommon;\n    if (giftImage != null) result.giftImage = giftImage;\n    if (agreeMsgId != null) result.agreeMsgId = agreeMsgId;\n    if (priorityLevel != null) result.priorityLevel = priorityLevel;\n    if (landscapeAreaCommon != null)\n      result.landscapeAreaCommon = landscapeAreaCommon;\n    if (eventTime != null) result.eventTime = eventTime;\n    if (sendReview != null) result.sendReview = sendReview;\n    if (fromIntercom != null) result.fromIntercom = fromIntercom;\n    if (intercomHideUserCard != null)\n      result.intercomHideUserCard = intercomHideUserCard;\n    if (chatBy != null) result.chatBy = chatBy;\n    if (individualChatPriority != null)\n      result.individualChatPriority = individualChatPriority;\n    if (rtfContent != null) result.rtfContent = rtfContent;\n    return result;\n  }\n\n  ChatMessage._();\n\n  factory ChatMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory ChatMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'ChatMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOS(3, _omitFieldNames ? '' : 'content')\n    ..aOB(4, _omitFieldNames ? '' : 'visibleToSender',\n        protoName: 'visibleToSender')\n    ..aOM<Image>(5, _omitFieldNames ? '' : 'backgroundImage',\n        protoName: 'backgroundImage', subBuilder: Image.create)\n    ..aOS(6, _omitFieldNames ? '' : 'fullScreenTextColor',\n        protoName: 'fullScreenTextColor')\n    ..aOM<Image>(7, _omitFieldNames ? '' : 'backgroundImageV2',\n        protoName: 'backgroundImageV2', subBuilder: Image.create)\n    ..aOM<PublicAreaCommon>(8, _omitFieldNames ? '' : 'publicAreaCommon',\n        protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create)\n    ..aOM<Image>(9, _omitFieldNames ? '' : 'giftImage',\n        protoName: 'giftImage', subBuilder: Image.create)\n    ..a<$fixnum.Int64>(\n        11, _omitFieldNames ? '' : 'agreeMsgId', $pb.PbFieldType.OU6,\n        protoName: 'agreeMsgId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aI(12, _omitFieldNames ? '' : 'priorityLevel',\n        protoName: 'priorityLevel', fieldType: $pb.PbFieldType.OU3)\n    ..aOM<LandscapeAreaCommon>(13, _omitFieldNames ? '' : 'landscapeAreaCommon',\n        protoName: 'landscapeAreaCommon',\n        subBuilder: LandscapeAreaCommon.create)\n    ..a<$fixnum.Int64>(\n        15, _omitFieldNames ? '' : 'eventTime', $pb.PbFieldType.OU6,\n        protoName: 'eventTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(16, _omitFieldNames ? '' : 'sendReview', protoName: 'sendReview')\n    ..aOB(17, _omitFieldNames ? '' : 'fromIntercom', protoName: 'fromIntercom')\n    ..aOB(18, _omitFieldNames ? '' : 'intercomHideUserCard',\n        protoName: 'intercomHideUserCard')\n    ..aOS(20, _omitFieldNames ? '' : 'chatBy', protoName: 'chatBy')\n    ..aI(21, _omitFieldNames ? '' : 'individualChatPriority',\n        protoName: 'individualChatPriority', fieldType: $pb.PbFieldType.OU3)\n    ..aOM<Text>(22, _omitFieldNames ? '' : 'rtfContent',\n        protoName: 'rtfContent', subBuilder: Text.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ChatMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ChatMessage copyWith(void Function(ChatMessage) updates) =>\n      super.copyWith((message) => updates(message as ChatMessage))\n          as ChatMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static ChatMessage create() => ChatMessage._();\n  @$core.override\n  ChatMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static ChatMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<ChatMessage>(create);\n  static ChatMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.String get content => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set content($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasContent() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearContent() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.bool get visibleToSender => $_getBF(3);\n  @$pb.TagNumber(4)\n  set visibleToSender($core.bool value) => $_setBool(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasVisibleToSender() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearVisibleToSender() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  Image get backgroundImage => $_getN(4);\n  @$pb.TagNumber(5)\n  set backgroundImage(Image value) => $_setField(5, value);\n  @$pb.TagNumber(5)\n  $core.bool hasBackgroundImage() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearBackgroundImage() => $_clearField(5);\n  @$pb.TagNumber(5)\n  Image ensureBackgroundImage() => $_ensure(4);\n\n  @$pb.TagNumber(6)\n  $core.String get fullScreenTextColor => $_getSZ(5);\n  @$pb.TagNumber(6)\n  set fullScreenTextColor($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasFullScreenTextColor() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearFullScreenTextColor() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  Image get backgroundImageV2 => $_getN(6);\n  @$pb.TagNumber(7)\n  set backgroundImageV2(Image value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasBackgroundImageV2() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearBackgroundImageV2() => $_clearField(7);\n  @$pb.TagNumber(7)\n  Image ensureBackgroundImageV2() => $_ensure(6);\n\n  @$pb.TagNumber(8)\n  PublicAreaCommon get publicAreaCommon => $_getN(7);\n  @$pb.TagNumber(8)\n  set publicAreaCommon(PublicAreaCommon value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasPublicAreaCommon() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearPublicAreaCommon() => $_clearField(8);\n  @$pb.TagNumber(8)\n  PublicAreaCommon ensurePublicAreaCommon() => $_ensure(7);\n\n  @$pb.TagNumber(9)\n  Image get giftImage => $_getN(8);\n  @$pb.TagNumber(9)\n  set giftImage(Image value) => $_setField(9, value);\n  @$pb.TagNumber(9)\n  $core.bool hasGiftImage() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearGiftImage() => $_clearField(9);\n  @$pb.TagNumber(9)\n  Image ensureGiftImage() => $_ensure(8);\n\n  @$pb.TagNumber(11)\n  $fixnum.Int64 get agreeMsgId => $_getI64(9);\n  @$pb.TagNumber(11)\n  set agreeMsgId($fixnum.Int64 value) => $_setInt64(9, value);\n  @$pb.TagNumber(11)\n  $core.bool hasAgreeMsgId() => $_has(9);\n  @$pb.TagNumber(11)\n  void clearAgreeMsgId() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.int get priorityLevel => $_getIZ(10);\n  @$pb.TagNumber(12)\n  set priorityLevel($core.int value) => $_setUnsignedInt32(10, value);\n  @$pb.TagNumber(12)\n  $core.bool hasPriorityLevel() => $_has(10);\n  @$pb.TagNumber(12)\n  void clearPriorityLevel() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  LandscapeAreaCommon get landscapeAreaCommon => $_getN(11);\n  @$pb.TagNumber(13)\n  set landscapeAreaCommon(LandscapeAreaCommon value) => $_setField(13, value);\n  @$pb.TagNumber(13)\n  $core.bool hasLandscapeAreaCommon() => $_has(11);\n  @$pb.TagNumber(13)\n  void clearLandscapeAreaCommon() => $_clearField(13);\n  @$pb.TagNumber(13)\n  LandscapeAreaCommon ensureLandscapeAreaCommon() => $_ensure(11);\n\n  @$pb.TagNumber(15)\n  $fixnum.Int64 get eventTime => $_getI64(12);\n  @$pb.TagNumber(15)\n  set eventTime($fixnum.Int64 value) => $_setInt64(12, value);\n  @$pb.TagNumber(15)\n  $core.bool hasEventTime() => $_has(12);\n  @$pb.TagNumber(15)\n  void clearEventTime() => $_clearField(15);\n\n  @$pb.TagNumber(16)\n  $core.bool get sendReview => $_getBF(13);\n  @$pb.TagNumber(16)\n  set sendReview($core.bool value) => $_setBool(13, value);\n  @$pb.TagNumber(16)\n  $core.bool hasSendReview() => $_has(13);\n  @$pb.TagNumber(16)\n  void clearSendReview() => $_clearField(16);\n\n  @$pb.TagNumber(17)\n  $core.bool get fromIntercom => $_getBF(14);\n  @$pb.TagNumber(17)\n  set fromIntercom($core.bool value) => $_setBool(14, value);\n  @$pb.TagNumber(17)\n  $core.bool hasFromIntercom() => $_has(14);\n  @$pb.TagNumber(17)\n  void clearFromIntercom() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $core.bool get intercomHideUserCard => $_getBF(15);\n  @$pb.TagNumber(18)\n  set intercomHideUserCard($core.bool value) => $_setBool(15, value);\n  @$pb.TagNumber(18)\n  $core.bool hasIntercomHideUserCard() => $_has(15);\n  @$pb.TagNumber(18)\n  void clearIntercomHideUserCard() => $_clearField(18);\n\n  /// repeated chatTagsList = 19;\n  @$pb.TagNumber(20)\n  $core.String get chatBy => $_getSZ(16);\n  @$pb.TagNumber(20)\n  set chatBy($core.String value) => $_setString(16, value);\n  @$pb.TagNumber(20)\n  $core.bool hasChatBy() => $_has(16);\n  @$pb.TagNumber(20)\n  void clearChatBy() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $core.int get individualChatPriority => $_getIZ(17);\n  @$pb.TagNumber(21)\n  set individualChatPriority($core.int value) => $_setUnsignedInt32(17, value);\n  @$pb.TagNumber(21)\n  $core.bool hasIndividualChatPriority() => $_has(17);\n  @$pb.TagNumber(21)\n  void clearIndividualChatPriority() => $_clearField(21);\n\n  @$pb.TagNumber(22)\n  Text get rtfContent => $_getN(18);\n  @$pb.TagNumber(22)\n  set rtfContent(Text value) => $_setField(22, value);\n  @$pb.TagNumber(22)\n  $core.bool hasRtfContent() => $_has(18);\n  @$pb.TagNumber(22)\n  void clearRtfContent() => $_clearField(22);\n  @$pb.TagNumber(22)\n  Text ensureRtfContent() => $_ensure(18);\n}\n\nclass LandscapeAreaCommon extends $pb.GeneratedMessage {\n  factory LandscapeAreaCommon({\n    $core.bool? showHead,\n    $core.bool? showNickname,\n    $core.bool? showFontColor,\n    $core.Iterable<$core.String>? colorValueList,\n    $core.Iterable<CommentTypeTag>? commentTypeTagsList,\n  }) {\n    final result = create();\n    if (showHead != null) result.showHead = showHead;\n    if (showNickname != null) result.showNickname = showNickname;\n    if (showFontColor != null) result.showFontColor = showFontColor;\n    if (colorValueList != null) result.colorValueList.addAll(colorValueList);\n    if (commentTypeTagsList != null)\n      result.commentTypeTagsList.addAll(commentTypeTagsList);\n    return result;\n  }\n\n  LandscapeAreaCommon._();\n\n  factory LandscapeAreaCommon.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory LandscapeAreaCommon.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'LandscapeAreaCommon',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOB(1, _omitFieldNames ? '' : 'showHead', protoName: 'showHead')\n    ..aOB(2, _omitFieldNames ? '' : 'showNickname', protoName: 'showNickname')\n    ..aOB(3, _omitFieldNames ? '' : 'showFontColor', protoName: 'showFontColor')\n    ..pPS(4, _omitFieldNames ? '' : 'colorValueList',\n        protoName: 'colorValueList')\n    ..pc<CommentTypeTag>(\n        5, _omitFieldNames ? '' : 'commentTypeTagsList', $pb.PbFieldType.KE,\n        protoName: 'commentTypeTagsList',\n        valueOf: CommentTypeTag.valueOf,\n        enumValues: CommentTypeTag.values,\n        defaultEnumValue: CommentTypeTag.COMMENTTYPETAGUNKNOWN)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  LandscapeAreaCommon clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  LandscapeAreaCommon copyWith(void Function(LandscapeAreaCommon) updates) =>\n      super.copyWith((message) => updates(message as LandscapeAreaCommon))\n          as LandscapeAreaCommon;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static LandscapeAreaCommon create() => LandscapeAreaCommon._();\n  @$core.override\n  LandscapeAreaCommon createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static LandscapeAreaCommon getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<LandscapeAreaCommon>(create);\n  static LandscapeAreaCommon? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.bool get showHead => $_getBF(0);\n  @$pb.TagNumber(1)\n  set showHead($core.bool value) => $_setBool(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasShowHead() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearShowHead() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.bool get showNickname => $_getBF(1);\n  @$pb.TagNumber(2)\n  set showNickname($core.bool value) => $_setBool(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasShowNickname() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearShowNickname() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.bool get showFontColor => $_getBF(2);\n  @$pb.TagNumber(3)\n  set showFontColor($core.bool value) => $_setBool(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasShowFontColor() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearShowFontColor() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $pb.PbList<$core.String> get colorValueList => $_getList(3);\n\n  @$pb.TagNumber(5)\n  $pb.PbList<CommentTypeTag> get commentTypeTagsList => $_getList(4);\n}\n\nclass RoomUserSeqMessage extends $pb.GeneratedMessage {\n  factory RoomUserSeqMessage({\n    Common? common,\n    $core.Iterable<RoomUserSeqMessageContributor>? ranksList,\n    $fixnum.Int64? total,\n    $core.String? popStr,\n    $core.Iterable<RoomUserSeqMessageContributor>? seatsList,\n    $fixnum.Int64? popularity,\n    $fixnum.Int64? totalUser,\n    $core.String? totalUserStr,\n    $core.String? totalStr,\n    $core.String? onlineUserForAnchor,\n    $core.String? totalPvForAnchor,\n    $core.String? upRightStatsStr,\n    $core.String? upRightStatsStrComplete,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (ranksList != null) result.ranksList.addAll(ranksList);\n    if (total != null) result.total = total;\n    if (popStr != null) result.popStr = popStr;\n    if (seatsList != null) result.seatsList.addAll(seatsList);\n    if (popularity != null) result.popularity = popularity;\n    if (totalUser != null) result.totalUser = totalUser;\n    if (totalUserStr != null) result.totalUserStr = totalUserStr;\n    if (totalStr != null) result.totalStr = totalStr;\n    if (onlineUserForAnchor != null)\n      result.onlineUserForAnchor = onlineUserForAnchor;\n    if (totalPvForAnchor != null) result.totalPvForAnchor = totalPvForAnchor;\n    if (upRightStatsStr != null) result.upRightStatsStr = upRightStatsStr;\n    if (upRightStatsStrComplete != null)\n      result.upRightStatsStrComplete = upRightStatsStrComplete;\n    return result;\n  }\n\n  RoomUserSeqMessage._();\n\n  factory RoomUserSeqMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory RoomUserSeqMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'RoomUserSeqMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..pPM<RoomUserSeqMessageContributor>(2, _omitFieldNames ? '' : 'ranksList',\n        protoName: 'ranksList',\n        subBuilder: RoomUserSeqMessageContributor.create)\n    ..aInt64(3, _omitFieldNames ? '' : 'total')\n    ..aOS(4, _omitFieldNames ? '' : 'popStr', protoName: 'popStr')\n    ..pPM<RoomUserSeqMessageContributor>(5, _omitFieldNames ? '' : 'seatsList',\n        protoName: 'seatsList',\n        subBuilder: RoomUserSeqMessageContributor.create)\n    ..aInt64(6, _omitFieldNames ? '' : 'popularity')\n    ..aInt64(7, _omitFieldNames ? '' : 'totalUser', protoName: 'totalUser')\n    ..aOS(8, _omitFieldNames ? '' : 'totalUserStr', protoName: 'totalUserStr')\n    ..aOS(9, _omitFieldNames ? '' : 'totalStr', protoName: 'totalStr')\n    ..aOS(10, _omitFieldNames ? '' : 'onlineUserForAnchor',\n        protoName: 'onlineUserForAnchor')\n    ..aOS(11, _omitFieldNames ? '' : 'totalPvForAnchor',\n        protoName: 'totalPvForAnchor')\n    ..aOS(12, _omitFieldNames ? '' : 'upRightStatsStr',\n        protoName: 'upRightStatsStr')\n    ..aOS(13, _omitFieldNames ? '' : 'upRightStatsStrComplete',\n        protoName: 'upRightStatsStrComplete')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  RoomUserSeqMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  RoomUserSeqMessage copyWith(void Function(RoomUserSeqMessage) updates) =>\n      super.copyWith((message) => updates(message as RoomUserSeqMessage))\n          as RoomUserSeqMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static RoomUserSeqMessage create() => RoomUserSeqMessage._();\n  @$core.override\n  RoomUserSeqMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static RoomUserSeqMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<RoomUserSeqMessage>(create);\n  static RoomUserSeqMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $pb.PbList<RoomUserSeqMessageContributor> get ranksList => $_getList(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get total => $_getI64(2);\n  @$pb.TagNumber(3)\n  set total($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasTotal() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearTotal() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get popStr => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set popStr($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasPopStr() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearPopStr() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $pb.PbList<RoomUserSeqMessageContributor> get seatsList => $_getList(4);\n\n  @$pb.TagNumber(6)\n  $fixnum.Int64 get popularity => $_getI64(5);\n  @$pb.TagNumber(6)\n  set popularity($fixnum.Int64 value) => $_setInt64(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasPopularity() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearPopularity() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $fixnum.Int64 get totalUser => $_getI64(6);\n  @$pb.TagNumber(7)\n  set totalUser($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasTotalUser() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearTotalUser() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.String get totalUserStr => $_getSZ(7);\n  @$pb.TagNumber(8)\n  set totalUserStr($core.String value) => $_setString(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasTotalUserStr() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearTotalUserStr() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $core.String get totalStr => $_getSZ(8);\n  @$pb.TagNumber(9)\n  set totalStr($core.String value) => $_setString(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasTotalStr() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearTotalStr() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $core.String get onlineUserForAnchor => $_getSZ(9);\n  @$pb.TagNumber(10)\n  set onlineUserForAnchor($core.String value) => $_setString(9, value);\n  @$pb.TagNumber(10)\n  $core.bool hasOnlineUserForAnchor() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearOnlineUserForAnchor() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $core.String get totalPvForAnchor => $_getSZ(10);\n  @$pb.TagNumber(11)\n  set totalPvForAnchor($core.String value) => $_setString(10, value);\n  @$pb.TagNumber(11)\n  $core.bool hasTotalPvForAnchor() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearTotalPvForAnchor() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.String get upRightStatsStr => $_getSZ(11);\n  @$pb.TagNumber(12)\n  set upRightStatsStr($core.String value) => $_setString(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasUpRightStatsStr() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearUpRightStatsStr() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $core.String get upRightStatsStrComplete => $_getSZ(12);\n  @$pb.TagNumber(13)\n  set upRightStatsStrComplete($core.String value) => $_setString(12, value);\n  @$pb.TagNumber(13)\n  $core.bool hasUpRightStatsStrComplete() => $_has(12);\n  @$pb.TagNumber(13)\n  void clearUpRightStatsStrComplete() => $_clearField(13);\n}\n\nclass CommonTextMessage extends $pb.GeneratedMessage {\n  factory CommonTextMessage({\n    Common? common,\n    User? user,\n    $core.String? scene,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (user != null) result.user = user;\n    if (scene != null) result.scene = scene;\n    return result;\n  }\n\n  CommonTextMessage._();\n\n  factory CommonTextMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory CommonTextMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'CommonTextMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOS(3, _omitFieldNames ? '' : 'scene')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  CommonTextMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  CommonTextMessage copyWith(void Function(CommonTextMessage) updates) =>\n      super.copyWith((message) => updates(message as CommonTextMessage))\n          as CommonTextMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static CommonTextMessage create() => CommonTextMessage._();\n  @$core.override\n  CommonTextMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static CommonTextMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<CommonTextMessage>(create);\n  static CommonTextMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.String get scene => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set scene($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasScene() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearScene() => $_clearField(3);\n}\n\nclass UpdateFanTicketMessage extends $pb.GeneratedMessage {\n  factory UpdateFanTicketMessage({\n    Common? common,\n    $core.String? roomFanTicketCountText,\n    $fixnum.Int64? roomFanTicketCount,\n    $core.bool? forceUpdate,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (roomFanTicketCountText != null)\n      result.roomFanTicketCountText = roomFanTicketCountText;\n    if (roomFanTicketCount != null)\n      result.roomFanTicketCount = roomFanTicketCount;\n    if (forceUpdate != null) result.forceUpdate = forceUpdate;\n    return result;\n  }\n\n  UpdateFanTicketMessage._();\n\n  factory UpdateFanTicketMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory UpdateFanTicketMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'UpdateFanTicketMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOS(2, _omitFieldNames ? '' : 'roomFanTicketCountText',\n        protoName: 'roomFanTicketCountText')\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'roomFanTicketCount', $pb.PbFieldType.OU6,\n        protoName: 'roomFanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(4, _omitFieldNames ? '' : 'forceUpdate', protoName: 'forceUpdate')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  UpdateFanTicketMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  UpdateFanTicketMessage copyWith(\n          void Function(UpdateFanTicketMessage) updates) =>\n      super.copyWith((message) => updates(message as UpdateFanTicketMessage))\n          as UpdateFanTicketMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static UpdateFanTicketMessage create() => UpdateFanTicketMessage._();\n  @$core.override\n  UpdateFanTicketMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static UpdateFanTicketMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<UpdateFanTicketMessage>(create);\n  static UpdateFanTicketMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $core.String get roomFanTicketCountText => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set roomFanTicketCountText($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasRoomFanTicketCountText() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearRoomFanTicketCountText() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get roomFanTicketCount => $_getI64(2);\n  @$pb.TagNumber(3)\n  set roomFanTicketCount($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasRoomFanTicketCount() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearRoomFanTicketCount() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.bool get forceUpdate => $_getBF(3);\n  @$pb.TagNumber(4)\n  set forceUpdate($core.bool value) => $_setBool(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasForceUpdate() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearForceUpdate() => $_clearField(4);\n}\n\nclass RoomUserSeqMessageContributor extends $pb.GeneratedMessage {\n  factory RoomUserSeqMessageContributor({\n    $fixnum.Int64? score,\n    User? user,\n    $fixnum.Int64? rank,\n    $fixnum.Int64? delta,\n    $core.bool? isHidden,\n    $core.String? scoreDescription,\n    $core.String? exactlyScore,\n  }) {\n    final result = create();\n    if (score != null) result.score = score;\n    if (user != null) result.user = user;\n    if (rank != null) result.rank = rank;\n    if (delta != null) result.delta = delta;\n    if (isHidden != null) result.isHidden = isHidden;\n    if (scoreDescription != null) result.scoreDescription = scoreDescription;\n    if (exactlyScore != null) result.exactlyScore = exactlyScore;\n    return result;\n  }\n\n  RoomUserSeqMessageContributor._();\n\n  factory RoomUserSeqMessageContributor.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory RoomUserSeqMessageContributor.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'RoomUserSeqMessageContributor',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'score', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'rank', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'delta', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(5, _omitFieldNames ? '' : 'isHidden', protoName: 'isHidden')\n    ..aOS(6, _omitFieldNames ? '' : 'scoreDescription',\n        protoName: 'scoreDescription')\n    ..aOS(7, _omitFieldNames ? '' : 'exactlyScore', protoName: 'exactlyScore')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  RoomUserSeqMessageContributor clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  RoomUserSeqMessageContributor copyWith(\n          void Function(RoomUserSeqMessageContributor) updates) =>\n      super.copyWith(\n              (message) => updates(message as RoomUserSeqMessageContributor))\n          as RoomUserSeqMessageContributor;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static RoomUserSeqMessageContributor create() =>\n      RoomUserSeqMessageContributor._();\n  @$core.override\n  RoomUserSeqMessageContributor createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static RoomUserSeqMessageContributor getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<RoomUserSeqMessageContributor>(create);\n  static RoomUserSeqMessageContributor? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get score => $_getI64(0);\n  @$pb.TagNumber(1)\n  set score($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasScore() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearScore() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get rank => $_getI64(2);\n  @$pb.TagNumber(3)\n  set rank($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasRank() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearRank() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get delta => $_getI64(3);\n  @$pb.TagNumber(4)\n  set delta($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasDelta() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearDelta() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.bool get isHidden => $_getBF(4);\n  @$pb.TagNumber(5)\n  set isHidden($core.bool value) => $_setBool(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasIsHidden() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearIsHidden() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.String get scoreDescription => $_getSZ(5);\n  @$pb.TagNumber(6)\n  set scoreDescription($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasScoreDescription() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearScoreDescription() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get exactlyScore => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set exactlyScore($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasExactlyScore() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearExactlyScore() => $_clearField(7);\n}\n\n/// 礼物消息\nclass GiftMessage extends $pb.GeneratedMessage {\n  factory GiftMessage({\n    Common? common,\n    $fixnum.Int64? giftId,\n    $fixnum.Int64? fanTicketCount,\n    $fixnum.Int64? groupCount,\n    $fixnum.Int64? repeatCount,\n    $fixnum.Int64? comboCount,\n    User? user,\n    User? toUser,\n    $core.int? repeatEnd,\n    TextEffect? textEffect,\n    $fixnum.Int64? groupId,\n    $fixnum.Int64? incomeTaskgifts,\n    $fixnum.Int64? roomFanTicketCount,\n    GiftIMPriority? priority,\n    GiftStruct? gift,\n    $core.String? logId,\n    $fixnum.Int64? sendType,\n    PublicAreaCommon? publicAreaCommon,\n    Text? trayDisplayText,\n    $fixnum.Int64? bannedDisplayEffects,\n    $core.bool? displayForSelf,\n    $core.String? interactGiftInfo,\n    $core.String? diyItemInfo,\n    $core.Iterable<$fixnum.Int64>? minAssetSetList,\n    $fixnum.Int64? totalCount,\n    $core.int? clientGiftSource,\n    $core.Iterable<$fixnum.Int64>? toUserIdsList,\n    $fixnum.Int64? sendTime,\n    $fixnum.Int64? forceDisplayEffects,\n    $core.String? traceId,\n    $fixnum.Int64? effectDisplayTs,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (giftId != null) result.giftId = giftId;\n    if (fanTicketCount != null) result.fanTicketCount = fanTicketCount;\n    if (groupCount != null) result.groupCount = groupCount;\n    if (repeatCount != null) result.repeatCount = repeatCount;\n    if (comboCount != null) result.comboCount = comboCount;\n    if (user != null) result.user = user;\n    if (toUser != null) result.toUser = toUser;\n    if (repeatEnd != null) result.repeatEnd = repeatEnd;\n    if (textEffect != null) result.textEffect = textEffect;\n    if (groupId != null) result.groupId = groupId;\n    if (incomeTaskgifts != null) result.incomeTaskgifts = incomeTaskgifts;\n    if (roomFanTicketCount != null)\n      result.roomFanTicketCount = roomFanTicketCount;\n    if (priority != null) result.priority = priority;\n    if (gift != null) result.gift = gift;\n    if (logId != null) result.logId = logId;\n    if (sendType != null) result.sendType = sendType;\n    if (publicAreaCommon != null) result.publicAreaCommon = publicAreaCommon;\n    if (trayDisplayText != null) result.trayDisplayText = trayDisplayText;\n    if (bannedDisplayEffects != null)\n      result.bannedDisplayEffects = bannedDisplayEffects;\n    if (displayForSelf != null) result.displayForSelf = displayForSelf;\n    if (interactGiftInfo != null) result.interactGiftInfo = interactGiftInfo;\n    if (diyItemInfo != null) result.diyItemInfo = diyItemInfo;\n    if (minAssetSetList != null) result.minAssetSetList.addAll(minAssetSetList);\n    if (totalCount != null) result.totalCount = totalCount;\n    if (clientGiftSource != null) result.clientGiftSource = clientGiftSource;\n    if (toUserIdsList != null) result.toUserIdsList.addAll(toUserIdsList);\n    if (sendTime != null) result.sendTime = sendTime;\n    if (forceDisplayEffects != null)\n      result.forceDisplayEffects = forceDisplayEffects;\n    if (traceId != null) result.traceId = traceId;\n    if (effectDisplayTs != null) result.effectDisplayTs = effectDisplayTs;\n    return result;\n  }\n\n  GiftMessage._();\n\n  factory GiftMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory GiftMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'GiftMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'giftId', $pb.PbFieldType.OU6,\n        protoName: 'giftId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'fanTicketCount', $pb.PbFieldType.OU6,\n        protoName: 'fanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        4, _omitFieldNames ? '' : 'groupCount', $pb.PbFieldType.OU6,\n        protoName: 'groupCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        5, _omitFieldNames ? '' : 'repeatCount', $pb.PbFieldType.OU6,\n        protoName: 'repeatCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        6, _omitFieldNames ? '' : 'comboCount', $pb.PbFieldType.OU6,\n        protoName: 'comboCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<User>(7, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOM<User>(8, _omitFieldNames ? '' : 'toUser',\n        protoName: 'toUser', subBuilder: User.create)\n    ..aI(9, _omitFieldNames ? '' : 'repeatEnd',\n        protoName: 'repeatEnd', fieldType: $pb.PbFieldType.OU3)\n    ..aOM<TextEffect>(10, _omitFieldNames ? '' : 'textEffect',\n        protoName: 'textEffect', subBuilder: TextEffect.create)\n    ..a<$fixnum.Int64>(\n        11, _omitFieldNames ? '' : 'groupId', $pb.PbFieldType.OU6,\n        protoName: 'groupId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        12, _omitFieldNames ? '' : 'incomeTaskgifts', $pb.PbFieldType.OU6,\n        protoName: 'incomeTaskgifts', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        13, _omitFieldNames ? '' : 'roomFanTicketCount', $pb.PbFieldType.OU6,\n        protoName: 'roomFanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<GiftIMPriority>(14, _omitFieldNames ? '' : 'priority',\n        subBuilder: GiftIMPriority.create)\n    ..aOM<GiftStruct>(15, _omitFieldNames ? '' : 'gift',\n        subBuilder: GiftStruct.create)\n    ..aOS(16, _omitFieldNames ? '' : 'logId', protoName: 'logId')\n    ..a<$fixnum.Int64>(\n        17, _omitFieldNames ? '' : 'sendType', $pb.PbFieldType.OU6,\n        protoName: 'sendType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<PublicAreaCommon>(18, _omitFieldNames ? '' : 'publicAreaCommon',\n        protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create)\n    ..aOM<Text>(19, _omitFieldNames ? '' : 'trayDisplayText',\n        protoName: 'trayDisplayText', subBuilder: Text.create)\n    ..a<$fixnum.Int64>(\n        20, _omitFieldNames ? '' : 'bannedDisplayEffects', $pb.PbFieldType.OU6,\n        protoName: 'bannedDisplayEffects', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(25, _omitFieldNames ? '' : 'displayForSelf',\n        protoName: 'displayForSelf')\n    ..aOS(26, _omitFieldNames ? '' : 'interactGiftInfo',\n        protoName: 'interactGiftInfo')\n    ..aOS(27, _omitFieldNames ? '' : 'diyItemInfo', protoName: 'diyItemInfo')\n    ..p<$fixnum.Int64>(\n        28, _omitFieldNames ? '' : 'minAssetSetList', $pb.PbFieldType.KU6,\n        protoName: 'minAssetSetList')\n    ..a<$fixnum.Int64>(\n        29, _omitFieldNames ? '' : 'totalCount', $pb.PbFieldType.OU6,\n        protoName: 'totalCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aI(30, _omitFieldNames ? '' : 'clientGiftSource',\n        protoName: 'clientGiftSource', fieldType: $pb.PbFieldType.OU3)\n    ..p<$fixnum.Int64>(\n        32, _omitFieldNames ? '' : 'toUserIdsList', $pb.PbFieldType.KU6,\n        protoName: 'toUserIdsList')\n    ..a<$fixnum.Int64>(\n        33, _omitFieldNames ? '' : 'sendTime', $pb.PbFieldType.OU6,\n        protoName: 'sendTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        34, _omitFieldNames ? '' : 'forceDisplayEffects', $pb.PbFieldType.OU6,\n        protoName: 'forceDisplayEffects', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(35, _omitFieldNames ? '' : 'traceId', protoName: 'traceId')\n    ..a<$fixnum.Int64>(\n        36, _omitFieldNames ? '' : 'effectDisplayTs', $pb.PbFieldType.OU6,\n        protoName: 'effectDisplayTs', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftMessage copyWith(void Function(GiftMessage) updates) =>\n      super.copyWith((message) => updates(message as GiftMessage))\n          as GiftMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static GiftMessage create() => GiftMessage._();\n  @$core.override\n  GiftMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static GiftMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<GiftMessage>(create);\n  static GiftMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get giftId => $_getI64(1);\n  @$pb.TagNumber(2)\n  set giftId($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasGiftId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearGiftId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get fanTicketCount => $_getI64(2);\n  @$pb.TagNumber(3)\n  set fanTicketCount($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasFanTicketCount() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearFanTicketCount() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get groupCount => $_getI64(3);\n  @$pb.TagNumber(4)\n  set groupCount($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasGroupCount() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearGroupCount() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $fixnum.Int64 get repeatCount => $_getI64(4);\n  @$pb.TagNumber(5)\n  set repeatCount($fixnum.Int64 value) => $_setInt64(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasRepeatCount() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearRepeatCount() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $fixnum.Int64 get comboCount => $_getI64(5);\n  @$pb.TagNumber(6)\n  set comboCount($fixnum.Int64 value) => $_setInt64(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasComboCount() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearComboCount() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  User get user => $_getN(6);\n  @$pb.TagNumber(7)\n  set user(User value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasUser() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearUser() => $_clearField(7);\n  @$pb.TagNumber(7)\n  User ensureUser() => $_ensure(6);\n\n  @$pb.TagNumber(8)\n  User get toUser => $_getN(7);\n  @$pb.TagNumber(8)\n  set toUser(User value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasToUser() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearToUser() => $_clearField(8);\n  @$pb.TagNumber(8)\n  User ensureToUser() => $_ensure(7);\n\n  @$pb.TagNumber(9)\n  $core.int get repeatEnd => $_getIZ(8);\n  @$pb.TagNumber(9)\n  set repeatEnd($core.int value) => $_setUnsignedInt32(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasRepeatEnd() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearRepeatEnd() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  TextEffect get textEffect => $_getN(9);\n  @$pb.TagNumber(10)\n  set textEffect(TextEffect value) => $_setField(10, value);\n  @$pb.TagNumber(10)\n  $core.bool hasTextEffect() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearTextEffect() => $_clearField(10);\n  @$pb.TagNumber(10)\n  TextEffect ensureTextEffect() => $_ensure(9);\n\n  @$pb.TagNumber(11)\n  $fixnum.Int64 get groupId => $_getI64(10);\n  @$pb.TagNumber(11)\n  set groupId($fixnum.Int64 value) => $_setInt64(10, value);\n  @$pb.TagNumber(11)\n  $core.bool hasGroupId() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearGroupId() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $fixnum.Int64 get incomeTaskgifts => $_getI64(11);\n  @$pb.TagNumber(12)\n  set incomeTaskgifts($fixnum.Int64 value) => $_setInt64(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasIncomeTaskgifts() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearIncomeTaskgifts() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $fixnum.Int64 get roomFanTicketCount => $_getI64(12);\n  @$pb.TagNumber(13)\n  set roomFanTicketCount($fixnum.Int64 value) => $_setInt64(12, value);\n  @$pb.TagNumber(13)\n  $core.bool hasRoomFanTicketCount() => $_has(12);\n  @$pb.TagNumber(13)\n  void clearRoomFanTicketCount() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  GiftIMPriority get priority => $_getN(13);\n  @$pb.TagNumber(14)\n  set priority(GiftIMPriority value) => $_setField(14, value);\n  @$pb.TagNumber(14)\n  $core.bool hasPriority() => $_has(13);\n  @$pb.TagNumber(14)\n  void clearPriority() => $_clearField(14);\n  @$pb.TagNumber(14)\n  GiftIMPriority ensurePriority() => $_ensure(13);\n\n  @$pb.TagNumber(15)\n  GiftStruct get gift => $_getN(14);\n  @$pb.TagNumber(15)\n  set gift(GiftStruct value) => $_setField(15, value);\n  @$pb.TagNumber(15)\n  $core.bool hasGift() => $_has(14);\n  @$pb.TagNumber(15)\n  void clearGift() => $_clearField(15);\n  @$pb.TagNumber(15)\n  GiftStruct ensureGift() => $_ensure(14);\n\n  @$pb.TagNumber(16)\n  $core.String get logId => $_getSZ(15);\n  @$pb.TagNumber(16)\n  set logId($core.String value) => $_setString(15, value);\n  @$pb.TagNumber(16)\n  $core.bool hasLogId() => $_has(15);\n  @$pb.TagNumber(16)\n  void clearLogId() => $_clearField(16);\n\n  @$pb.TagNumber(17)\n  $fixnum.Int64 get sendType => $_getI64(16);\n  @$pb.TagNumber(17)\n  set sendType($fixnum.Int64 value) => $_setInt64(16, value);\n  @$pb.TagNumber(17)\n  $core.bool hasSendType() => $_has(16);\n  @$pb.TagNumber(17)\n  void clearSendType() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  PublicAreaCommon get publicAreaCommon => $_getN(17);\n  @$pb.TagNumber(18)\n  set publicAreaCommon(PublicAreaCommon value) => $_setField(18, value);\n  @$pb.TagNumber(18)\n  $core.bool hasPublicAreaCommon() => $_has(17);\n  @$pb.TagNumber(18)\n  void clearPublicAreaCommon() => $_clearField(18);\n  @$pb.TagNumber(18)\n  PublicAreaCommon ensurePublicAreaCommon() => $_ensure(17);\n\n  @$pb.TagNumber(19)\n  Text get trayDisplayText => $_getN(18);\n  @$pb.TagNumber(19)\n  set trayDisplayText(Text value) => $_setField(19, value);\n  @$pb.TagNumber(19)\n  $core.bool hasTrayDisplayText() => $_has(18);\n  @$pb.TagNumber(19)\n  void clearTrayDisplayText() => $_clearField(19);\n  @$pb.TagNumber(19)\n  Text ensureTrayDisplayText() => $_ensure(18);\n\n  @$pb.TagNumber(20)\n  $fixnum.Int64 get bannedDisplayEffects => $_getI64(19);\n  @$pb.TagNumber(20)\n  set bannedDisplayEffects($fixnum.Int64 value) => $_setInt64(19, value);\n  @$pb.TagNumber(20)\n  $core.bool hasBannedDisplayEffects() => $_has(19);\n  @$pb.TagNumber(20)\n  void clearBannedDisplayEffects() => $_clearField(20);\n\n  /// GiftTrayInfo trayInfo = 21;\n  /// AssetEffectMixInfo assetEffectMixInfo = 22;\n  @$pb.TagNumber(25)\n  $core.bool get displayForSelf => $_getBF(20);\n  @$pb.TagNumber(25)\n  set displayForSelf($core.bool value) => $_setBool(20, value);\n  @$pb.TagNumber(25)\n  $core.bool hasDisplayForSelf() => $_has(20);\n  @$pb.TagNumber(25)\n  void clearDisplayForSelf() => $_clearField(25);\n\n  @$pb.TagNumber(26)\n  $core.String get interactGiftInfo => $_getSZ(21);\n  @$pb.TagNumber(26)\n  set interactGiftInfo($core.String value) => $_setString(21, value);\n  @$pb.TagNumber(26)\n  $core.bool hasInteractGiftInfo() => $_has(21);\n  @$pb.TagNumber(26)\n  void clearInteractGiftInfo() => $_clearField(26);\n\n  @$pb.TagNumber(27)\n  $core.String get diyItemInfo => $_getSZ(22);\n  @$pb.TagNumber(27)\n  set diyItemInfo($core.String value) => $_setString(22, value);\n  @$pb.TagNumber(27)\n  $core.bool hasDiyItemInfo() => $_has(22);\n  @$pb.TagNumber(27)\n  void clearDiyItemInfo() => $_clearField(27);\n\n  @$pb.TagNumber(28)\n  $pb.PbList<$fixnum.Int64> get minAssetSetList => $_getList(23);\n\n  @$pb.TagNumber(29)\n  $fixnum.Int64 get totalCount => $_getI64(24);\n  @$pb.TagNumber(29)\n  set totalCount($fixnum.Int64 value) => $_setInt64(24, value);\n  @$pb.TagNumber(29)\n  $core.bool hasTotalCount() => $_has(24);\n  @$pb.TagNumber(29)\n  void clearTotalCount() => $_clearField(29);\n\n  @$pb.TagNumber(30)\n  $core.int get clientGiftSource => $_getIZ(25);\n  @$pb.TagNumber(30)\n  set clientGiftSource($core.int value) => $_setUnsignedInt32(25, value);\n  @$pb.TagNumber(30)\n  $core.bool hasClientGiftSource() => $_has(25);\n  @$pb.TagNumber(30)\n  void clearClientGiftSource() => $_clearField(30);\n\n  /// AnchorGiftData anchorGift = 31;\n  @$pb.TagNumber(32)\n  $pb.PbList<$fixnum.Int64> get toUserIdsList => $_getList(26);\n\n  @$pb.TagNumber(33)\n  $fixnum.Int64 get sendTime => $_getI64(27);\n  @$pb.TagNumber(33)\n  set sendTime($fixnum.Int64 value) => $_setInt64(27, value);\n  @$pb.TagNumber(33)\n  $core.bool hasSendTime() => $_has(27);\n  @$pb.TagNumber(33)\n  void clearSendTime() => $_clearField(33);\n\n  @$pb.TagNumber(34)\n  $fixnum.Int64 get forceDisplayEffects => $_getI64(28);\n  @$pb.TagNumber(34)\n  set forceDisplayEffects($fixnum.Int64 value) => $_setInt64(28, value);\n  @$pb.TagNumber(34)\n  $core.bool hasForceDisplayEffects() => $_has(28);\n  @$pb.TagNumber(34)\n  void clearForceDisplayEffects() => $_clearField(34);\n\n  @$pb.TagNumber(35)\n  $core.String get traceId => $_getSZ(29);\n  @$pb.TagNumber(35)\n  set traceId($core.String value) => $_setString(29, value);\n  @$pb.TagNumber(35)\n  $core.bool hasTraceId() => $_has(29);\n  @$pb.TagNumber(35)\n  void clearTraceId() => $_clearField(35);\n\n  @$pb.TagNumber(36)\n  $fixnum.Int64 get effectDisplayTs => $_getI64(30);\n  @$pb.TagNumber(36)\n  set effectDisplayTs($fixnum.Int64 value) => $_setInt64(30, value);\n  @$pb.TagNumber(36)\n  $core.bool hasEffectDisplayTs() => $_has(30);\n  @$pb.TagNumber(36)\n  void clearEffectDisplayTs() => $_clearField(36);\n}\n\nclass GiftStruct extends $pb.GeneratedMessage {\n  factory GiftStruct({\n    Image? image,\n    $core.String? describe,\n    $core.bool? notify,\n    $fixnum.Int64? duration,\n    $fixnum.Int64? id,\n    $core.bool? forLinkmic,\n    $core.bool? doodle,\n    $core.bool? forFansclub,\n    $core.bool? combo,\n    $core.int? type,\n    $core.int? diamondCount,\n    $core.bool? isDisplayedOnPanel,\n    $fixnum.Int64? primaryEffectId,\n    Image? giftLabelIcon,\n    $core.String? name,\n    $core.String? region,\n    $core.String? manual,\n    $core.bool? forCustom,\n    Image? icon,\n    $core.int? actionType,\n  }) {\n    final result = create();\n    if (image != null) result.image = image;\n    if (describe != null) result.describe = describe;\n    if (notify != null) result.notify = notify;\n    if (duration != null) result.duration = duration;\n    if (id != null) result.id = id;\n    if (forLinkmic != null) result.forLinkmic = forLinkmic;\n    if (doodle != null) result.doodle = doodle;\n    if (forFansclub != null) result.forFansclub = forFansclub;\n    if (combo != null) result.combo = combo;\n    if (type != null) result.type = type;\n    if (diamondCount != null) result.diamondCount = diamondCount;\n    if (isDisplayedOnPanel != null)\n      result.isDisplayedOnPanel = isDisplayedOnPanel;\n    if (primaryEffectId != null) result.primaryEffectId = primaryEffectId;\n    if (giftLabelIcon != null) result.giftLabelIcon = giftLabelIcon;\n    if (name != null) result.name = name;\n    if (region != null) result.region = region;\n    if (manual != null) result.manual = manual;\n    if (forCustom != null) result.forCustom = forCustom;\n    if (icon != null) result.icon = icon;\n    if (actionType != null) result.actionType = actionType;\n    return result;\n  }\n\n  GiftStruct._();\n\n  factory GiftStruct.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory GiftStruct.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'GiftStruct',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Image>(1, _omitFieldNames ? '' : 'image', subBuilder: Image.create)\n    ..aOS(2, _omitFieldNames ? '' : 'describe')\n    ..aOB(3, _omitFieldNames ? '' : 'notify')\n    ..a<$fixnum.Int64>(\n        4, _omitFieldNames ? '' : 'duration', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(7, _omitFieldNames ? '' : 'forLinkmic', protoName: 'forLinkmic')\n    ..aOB(8, _omitFieldNames ? '' : 'doodle')\n    ..aOB(9, _omitFieldNames ? '' : 'forFansclub', protoName: 'forFansclub')\n    ..aOB(10, _omitFieldNames ? '' : 'combo')\n    ..aI(11, _omitFieldNames ? '' : 'type', fieldType: $pb.PbFieldType.OU3)\n    ..aI(12, _omitFieldNames ? '' : 'diamondCount',\n        protoName: 'diamondCount', fieldType: $pb.PbFieldType.OU3)\n    ..aOB(13, _omitFieldNames ? '' : 'isDisplayedOnPanel',\n        protoName: 'isDisplayedOnPanel')\n    ..a<$fixnum.Int64>(\n        14, _omitFieldNames ? '' : 'primaryEffectId', $pb.PbFieldType.OU6,\n        protoName: 'primaryEffectId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<Image>(15, _omitFieldNames ? '' : 'giftLabelIcon',\n        protoName: 'giftLabelIcon', subBuilder: Image.create)\n    ..aOS(16, _omitFieldNames ? '' : 'name')\n    ..aOS(17, _omitFieldNames ? '' : 'region')\n    ..aOS(18, _omitFieldNames ? '' : 'manual')\n    ..aOB(19, _omitFieldNames ? '' : 'forCustom', protoName: 'forCustom')\n    ..aOM<Image>(21, _omitFieldNames ? '' : 'icon', subBuilder: Image.create)\n    ..aI(22, _omitFieldNames ? '' : 'actionType',\n        protoName: 'actionType', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftStruct clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftStruct copyWith(void Function(GiftStruct) updates) =>\n      super.copyWith((message) => updates(message as GiftStruct)) as GiftStruct;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static GiftStruct create() => GiftStruct._();\n  @$core.override\n  GiftStruct createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static GiftStruct getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<GiftStruct>(create);\n  static GiftStruct? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Image get image => $_getN(0);\n  @$pb.TagNumber(1)\n  set image(Image value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasImage() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearImage() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Image ensureImage() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $core.String get describe => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set describe($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasDescribe() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearDescribe() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.bool get notify => $_getBF(2);\n  @$pb.TagNumber(3)\n  set notify($core.bool value) => $_setBool(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasNotify() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearNotify() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get duration => $_getI64(3);\n  @$pb.TagNumber(4)\n  set duration($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasDuration() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearDuration() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $fixnum.Int64 get id => $_getI64(4);\n  @$pb.TagNumber(5)\n  set id($fixnum.Int64 value) => $_setInt64(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasId() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearId() => $_clearField(5);\n\n  /// GiftStructFansClubInfo fansclubInfo = 6;\n  @$pb.TagNumber(7)\n  $core.bool get forLinkmic => $_getBF(5);\n  @$pb.TagNumber(7)\n  set forLinkmic($core.bool value) => $_setBool(5, value);\n  @$pb.TagNumber(7)\n  $core.bool hasForLinkmic() => $_has(5);\n  @$pb.TagNumber(7)\n  void clearForLinkmic() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.bool get doodle => $_getBF(6);\n  @$pb.TagNumber(8)\n  set doodle($core.bool value) => $_setBool(6, value);\n  @$pb.TagNumber(8)\n  $core.bool hasDoodle() => $_has(6);\n  @$pb.TagNumber(8)\n  void clearDoodle() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $core.bool get forFansclub => $_getBF(7);\n  @$pb.TagNumber(9)\n  set forFansclub($core.bool value) => $_setBool(7, value);\n  @$pb.TagNumber(9)\n  $core.bool hasForFansclub() => $_has(7);\n  @$pb.TagNumber(9)\n  void clearForFansclub() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $core.bool get combo => $_getBF(8);\n  @$pb.TagNumber(10)\n  set combo($core.bool value) => $_setBool(8, value);\n  @$pb.TagNumber(10)\n  $core.bool hasCombo() => $_has(8);\n  @$pb.TagNumber(10)\n  void clearCombo() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $core.int get type => $_getIZ(9);\n  @$pb.TagNumber(11)\n  set type($core.int value) => $_setUnsignedInt32(9, value);\n  @$pb.TagNumber(11)\n  $core.bool hasType() => $_has(9);\n  @$pb.TagNumber(11)\n  void clearType() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.int get diamondCount => $_getIZ(10);\n  @$pb.TagNumber(12)\n  set diamondCount($core.int value) => $_setUnsignedInt32(10, value);\n  @$pb.TagNumber(12)\n  $core.bool hasDiamondCount() => $_has(10);\n  @$pb.TagNumber(12)\n  void clearDiamondCount() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $core.bool get isDisplayedOnPanel => $_getBF(11);\n  @$pb.TagNumber(13)\n  set isDisplayedOnPanel($core.bool value) => $_setBool(11, value);\n  @$pb.TagNumber(13)\n  $core.bool hasIsDisplayedOnPanel() => $_has(11);\n  @$pb.TagNumber(13)\n  void clearIsDisplayedOnPanel() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  $fixnum.Int64 get primaryEffectId => $_getI64(12);\n  @$pb.TagNumber(14)\n  set primaryEffectId($fixnum.Int64 value) => $_setInt64(12, value);\n  @$pb.TagNumber(14)\n  $core.bool hasPrimaryEffectId() => $_has(12);\n  @$pb.TagNumber(14)\n  void clearPrimaryEffectId() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  Image get giftLabelIcon => $_getN(13);\n  @$pb.TagNumber(15)\n  set giftLabelIcon(Image value) => $_setField(15, value);\n  @$pb.TagNumber(15)\n  $core.bool hasGiftLabelIcon() => $_has(13);\n  @$pb.TagNumber(15)\n  void clearGiftLabelIcon() => $_clearField(15);\n  @$pb.TagNumber(15)\n  Image ensureGiftLabelIcon() => $_ensure(13);\n\n  @$pb.TagNumber(16)\n  $core.String get name => $_getSZ(14);\n  @$pb.TagNumber(16)\n  set name($core.String value) => $_setString(14, value);\n  @$pb.TagNumber(16)\n  $core.bool hasName() => $_has(14);\n  @$pb.TagNumber(16)\n  void clearName() => $_clearField(16);\n\n  @$pb.TagNumber(17)\n  $core.String get region => $_getSZ(15);\n  @$pb.TagNumber(17)\n  set region($core.String value) => $_setString(15, value);\n  @$pb.TagNumber(17)\n  $core.bool hasRegion() => $_has(15);\n  @$pb.TagNumber(17)\n  void clearRegion() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $core.String get manual => $_getSZ(16);\n  @$pb.TagNumber(18)\n  set manual($core.String value) => $_setString(16, value);\n  @$pb.TagNumber(18)\n  $core.bool hasManual() => $_has(16);\n  @$pb.TagNumber(18)\n  void clearManual() => $_clearField(18);\n\n  @$pb.TagNumber(19)\n  $core.bool get forCustom => $_getBF(17);\n  @$pb.TagNumber(19)\n  set forCustom($core.bool value) => $_setBool(17, value);\n  @$pb.TagNumber(19)\n  $core.bool hasForCustom() => $_has(17);\n  @$pb.TagNumber(19)\n  void clearForCustom() => $_clearField(19);\n\n  /// specialEffectsMap = 20;\n  @$pb.TagNumber(21)\n  Image get icon => $_getN(18);\n  @$pb.TagNumber(21)\n  set icon(Image value) => $_setField(21, value);\n  @$pb.TagNumber(21)\n  $core.bool hasIcon() => $_has(18);\n  @$pb.TagNumber(21)\n  void clearIcon() => $_clearField(21);\n  @$pb.TagNumber(21)\n  Image ensureIcon() => $_ensure(18);\n\n  @$pb.TagNumber(22)\n  $core.int get actionType => $_getIZ(19);\n  @$pb.TagNumber(22)\n  set actionType($core.int value) => $_setUnsignedInt32(19, value);\n  @$pb.TagNumber(22)\n  $core.bool hasActionType() => $_has(19);\n  @$pb.TagNumber(22)\n  void clearActionType() => $_clearField(22);\n}\n\nclass GiftIMPriority extends $pb.GeneratedMessage {\n  factory GiftIMPriority({\n    $core.Iterable<$fixnum.Int64>? queueSizesList,\n    $fixnum.Int64? selfQueuePriority,\n    $fixnum.Int64? priority,\n  }) {\n    final result = create();\n    if (queueSizesList != null) result.queueSizesList.addAll(queueSizesList);\n    if (selfQueuePriority != null) result.selfQueuePriority = selfQueuePriority;\n    if (priority != null) result.priority = priority;\n    return result;\n  }\n\n  GiftIMPriority._();\n\n  factory GiftIMPriority.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory GiftIMPriority.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'GiftIMPriority',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..p<$fixnum.Int64>(\n        1, _omitFieldNames ? '' : 'queueSizesList', $pb.PbFieldType.KU6,\n        protoName: 'queueSizesList')\n    ..a<$fixnum.Int64>(\n        2, _omitFieldNames ? '' : 'selfQueuePriority', $pb.PbFieldType.OU6,\n        protoName: 'selfQueuePriority', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'priority', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftIMPriority clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  GiftIMPriority copyWith(void Function(GiftIMPriority) updates) =>\n      super.copyWith((message) => updates(message as GiftIMPriority))\n          as GiftIMPriority;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static GiftIMPriority create() => GiftIMPriority._();\n  @$core.override\n  GiftIMPriority createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static GiftIMPriority getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<GiftIMPriority>(create);\n  static GiftIMPriority? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $pb.PbList<$fixnum.Int64> get queueSizesList => $_getList(0);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get selfQueuePriority => $_getI64(1);\n  @$pb.TagNumber(2)\n  set selfQueuePriority($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasSelfQueuePriority() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearSelfQueuePriority() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get priority => $_getI64(2);\n  @$pb.TagNumber(3)\n  set priority($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasPriority() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearPriority() => $_clearField(3);\n}\n\nclass TextEffect extends $pb.GeneratedMessage {\n  factory TextEffect({\n    TextEffectDetail? portrait,\n    TextEffectDetail? landscape,\n  }) {\n    final result = create();\n    if (portrait != null) result.portrait = portrait;\n    if (landscape != null) result.landscape = landscape;\n    return result;\n  }\n\n  TextEffect._();\n\n  factory TextEffect.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextEffect.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextEffect',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<TextEffectDetail>(1, _omitFieldNames ? '' : 'portrait',\n        subBuilder: TextEffectDetail.create)\n    ..aOM<TextEffectDetail>(2, _omitFieldNames ? '' : 'landscape',\n        subBuilder: TextEffectDetail.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextEffect clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextEffect copyWith(void Function(TextEffect) updates) =>\n      super.copyWith((message) => updates(message as TextEffect)) as TextEffect;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextEffect create() => TextEffect._();\n  @$core.override\n  TextEffect createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextEffect getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextEffect>(create);\n  static TextEffect? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  TextEffectDetail get portrait => $_getN(0);\n  @$pb.TagNumber(1)\n  set portrait(TextEffectDetail value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasPortrait() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearPortrait() => $_clearField(1);\n  @$pb.TagNumber(1)\n  TextEffectDetail ensurePortrait() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  TextEffectDetail get landscape => $_getN(1);\n  @$pb.TagNumber(2)\n  set landscape(TextEffectDetail value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasLandscape() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearLandscape() => $_clearField(2);\n  @$pb.TagNumber(2)\n  TextEffectDetail ensureLandscape() => $_ensure(1);\n}\n\nclass TextEffectDetail extends $pb.GeneratedMessage {\n  factory TextEffectDetail({\n    Text? text,\n    $core.int? textFontSize,\n    Image? background,\n    $core.int? start,\n    $core.int? duration,\n    $core.int? x,\n    $core.int? y,\n    $core.int? width,\n    $core.int? height,\n    $core.int? shadowDx,\n    $core.int? shadowDy,\n    $core.int? shadowRadius,\n    $core.String? shadowColor,\n    $core.String? strokeColor,\n    $core.int? strokeWidth,\n  }) {\n    final result = create();\n    if (text != null) result.text = text;\n    if (textFontSize != null) result.textFontSize = textFontSize;\n    if (background != null) result.background = background;\n    if (start != null) result.start = start;\n    if (duration != null) result.duration = duration;\n    if (x != null) result.x = x;\n    if (y != null) result.y = y;\n    if (width != null) result.width = width;\n    if (height != null) result.height = height;\n    if (shadowDx != null) result.shadowDx = shadowDx;\n    if (shadowDy != null) result.shadowDy = shadowDy;\n    if (shadowRadius != null) result.shadowRadius = shadowRadius;\n    if (shadowColor != null) result.shadowColor = shadowColor;\n    if (strokeColor != null) result.strokeColor = strokeColor;\n    if (strokeWidth != null) result.strokeWidth = strokeWidth;\n    return result;\n  }\n\n  TextEffectDetail._();\n\n  factory TextEffectDetail.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextEffectDetail.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextEffectDetail',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Text>(1, _omitFieldNames ? '' : 'text', subBuilder: Text.create)\n    ..aI(2, _omitFieldNames ? '' : 'textFontSize',\n        protoName: 'textFontSize', fieldType: $pb.PbFieldType.OU3)\n    ..aOM<Image>(3, _omitFieldNames ? '' : 'background',\n        subBuilder: Image.create)\n    ..aI(4, _omitFieldNames ? '' : 'start', fieldType: $pb.PbFieldType.OU3)\n    ..aI(5, _omitFieldNames ? '' : 'duration', fieldType: $pb.PbFieldType.OU3)\n    ..aI(6, _omitFieldNames ? '' : 'x', fieldType: $pb.PbFieldType.OU3)\n    ..aI(7, _omitFieldNames ? '' : 'y', fieldType: $pb.PbFieldType.OU3)\n    ..aI(8, _omitFieldNames ? '' : 'width', fieldType: $pb.PbFieldType.OU3)\n    ..aI(9, _omitFieldNames ? '' : 'height', fieldType: $pb.PbFieldType.OU3)\n    ..aI(10, _omitFieldNames ? '' : 'shadowDx',\n        protoName: 'shadowDx', fieldType: $pb.PbFieldType.OU3)\n    ..aI(11, _omitFieldNames ? '' : 'shadowDy',\n        protoName: 'shadowDy', fieldType: $pb.PbFieldType.OU3)\n    ..aI(12, _omitFieldNames ? '' : 'shadowRadius',\n        protoName: 'shadowRadius', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(13, _omitFieldNames ? '' : 'shadowColor', protoName: 'shadowColor')\n    ..aOS(14, _omitFieldNames ? '' : 'strokeColor', protoName: 'strokeColor')\n    ..aI(15, _omitFieldNames ? '' : 'strokeWidth',\n        protoName: 'strokeWidth', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextEffectDetail clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextEffectDetail copyWith(void Function(TextEffectDetail) updates) =>\n      super.copyWith((message) => updates(message as TextEffectDetail))\n          as TextEffectDetail;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextEffectDetail create() => TextEffectDetail._();\n  @$core.override\n  TextEffectDetail createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextEffectDetail getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextEffectDetail>(create);\n  static TextEffectDetail? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Text get text => $_getN(0);\n  @$pb.TagNumber(1)\n  set text(Text value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasText() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearText() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Text ensureText() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $core.int get textFontSize => $_getIZ(1);\n  @$pb.TagNumber(2)\n  set textFontSize($core.int value) => $_setUnsignedInt32(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasTextFontSize() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearTextFontSize() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  Image get background => $_getN(2);\n  @$pb.TagNumber(3)\n  set background(Image value) => $_setField(3, value);\n  @$pb.TagNumber(3)\n  $core.bool hasBackground() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearBackground() => $_clearField(3);\n  @$pb.TagNumber(3)\n  Image ensureBackground() => $_ensure(2);\n\n  @$pb.TagNumber(4)\n  $core.int get start => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set start($core.int value) => $_setUnsignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasStart() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearStart() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.int get duration => $_getIZ(4);\n  @$pb.TagNumber(5)\n  set duration($core.int value) => $_setUnsignedInt32(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasDuration() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearDuration() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get x => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set x($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasX() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearX() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.int get y => $_getIZ(6);\n  @$pb.TagNumber(7)\n  set y($core.int value) => $_setUnsignedInt32(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasY() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearY() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.int get width => $_getIZ(7);\n  @$pb.TagNumber(8)\n  set width($core.int value) => $_setUnsignedInt32(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasWidth() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearWidth() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $core.int get height => $_getIZ(8);\n  @$pb.TagNumber(9)\n  set height($core.int value) => $_setUnsignedInt32(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasHeight() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearHeight() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $core.int get shadowDx => $_getIZ(9);\n  @$pb.TagNumber(10)\n  set shadowDx($core.int value) => $_setUnsignedInt32(9, value);\n  @$pb.TagNumber(10)\n  $core.bool hasShadowDx() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearShadowDx() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $core.int get shadowDy => $_getIZ(10);\n  @$pb.TagNumber(11)\n  set shadowDy($core.int value) => $_setUnsignedInt32(10, value);\n  @$pb.TagNumber(11)\n  $core.bool hasShadowDy() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearShadowDy() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.int get shadowRadius => $_getIZ(11);\n  @$pb.TagNumber(12)\n  set shadowRadius($core.int value) => $_setUnsignedInt32(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasShadowRadius() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearShadowRadius() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $core.String get shadowColor => $_getSZ(12);\n  @$pb.TagNumber(13)\n  set shadowColor($core.String value) => $_setString(12, value);\n  @$pb.TagNumber(13)\n  $core.bool hasShadowColor() => $_has(12);\n  @$pb.TagNumber(13)\n  void clearShadowColor() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  $core.String get strokeColor => $_getSZ(13);\n  @$pb.TagNumber(14)\n  set strokeColor($core.String value) => $_setString(13, value);\n  @$pb.TagNumber(14)\n  $core.bool hasStrokeColor() => $_has(13);\n  @$pb.TagNumber(14)\n  void clearStrokeColor() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  $core.int get strokeWidth => $_getIZ(14);\n  @$pb.TagNumber(15)\n  set strokeWidth($core.int value) => $_setUnsignedInt32(14, value);\n  @$pb.TagNumber(15)\n  $core.bool hasStrokeWidth() => $_has(14);\n  @$pb.TagNumber(15)\n  void clearStrokeWidth() => $_clearField(15);\n}\n\n/// 成员消息\nclass MemberMessage extends $pb.GeneratedMessage {\n  factory MemberMessage({\n    Common? common,\n    User? user,\n    $fixnum.Int64? memberCount,\n    User? operator,\n    $core.bool? isSetToAdmin,\n    $core.bool? isTopUser,\n    $fixnum.Int64? rankScore,\n    $fixnum.Int64? topUserNo,\n    $fixnum.Int64? enterType,\n    $fixnum.Int64? action,\n    $core.String? actionDescription,\n    $fixnum.Int64? userId,\n    EffectConfig? effectConfig,\n    $core.String? popStr,\n    EffectConfig? enterEffectConfig,\n    Image? backgroundImage,\n    Image? backgroundImageV2,\n    Text? anchorDisplayText,\n    PublicAreaCommon? publicAreaCommon,\n    $fixnum.Int64? userEnterTipType,\n    $fixnum.Int64? anchorEnterTipType,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (user != null) result.user = user;\n    if (memberCount != null) result.memberCount = memberCount;\n    if (operator != null) result.operator = operator;\n    if (isSetToAdmin != null) result.isSetToAdmin = isSetToAdmin;\n    if (isTopUser != null) result.isTopUser = isTopUser;\n    if (rankScore != null) result.rankScore = rankScore;\n    if (topUserNo != null) result.topUserNo = topUserNo;\n    if (enterType != null) result.enterType = enterType;\n    if (action != null) result.action = action;\n    if (actionDescription != null) result.actionDescription = actionDescription;\n    if (userId != null) result.userId = userId;\n    if (effectConfig != null) result.effectConfig = effectConfig;\n    if (popStr != null) result.popStr = popStr;\n    if (enterEffectConfig != null) result.enterEffectConfig = enterEffectConfig;\n    if (backgroundImage != null) result.backgroundImage = backgroundImage;\n    if (backgroundImageV2 != null) result.backgroundImageV2 = backgroundImageV2;\n    if (anchorDisplayText != null) result.anchorDisplayText = anchorDisplayText;\n    if (publicAreaCommon != null) result.publicAreaCommon = publicAreaCommon;\n    if (userEnterTipType != null) result.userEnterTipType = userEnterTipType;\n    if (anchorEnterTipType != null)\n      result.anchorEnterTipType = anchorEnterTipType;\n    return result;\n  }\n\n  MemberMessage._();\n\n  factory MemberMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory MemberMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'MemberMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'memberCount', $pb.PbFieldType.OU6,\n        protoName: 'memberCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<User>(4, _omitFieldNames ? '' : 'operator', subBuilder: User.create)\n    ..aOB(5, _omitFieldNames ? '' : 'isSetToAdmin', protoName: 'isSetToAdmin')\n    ..aOB(6, _omitFieldNames ? '' : 'isTopUser', protoName: 'isTopUser')\n    ..a<$fixnum.Int64>(\n        7, _omitFieldNames ? '' : 'rankScore', $pb.PbFieldType.OU6,\n        protoName: 'rankScore', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        8, _omitFieldNames ? '' : 'topUserNo', $pb.PbFieldType.OU6,\n        protoName: 'topUserNo', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        9, _omitFieldNames ? '' : 'enterType', $pb.PbFieldType.OU6,\n        protoName: 'enterType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(10, _omitFieldNames ? '' : 'action', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(11, _omitFieldNames ? '' : 'actionDescription',\n        protoName: 'actionDescription')\n    ..a<$fixnum.Int64>(12, _omitFieldNames ? '' : 'userId', $pb.PbFieldType.OU6,\n        protoName: 'userId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<EffectConfig>(13, _omitFieldNames ? '' : 'effectConfig',\n        protoName: 'effectConfig', subBuilder: EffectConfig.create)\n    ..aOS(14, _omitFieldNames ? '' : 'popStr', protoName: 'popStr')\n    ..aOM<EffectConfig>(15, _omitFieldNames ? '' : 'enterEffectConfig',\n        protoName: 'enterEffectConfig', subBuilder: EffectConfig.create)\n    ..aOM<Image>(16, _omitFieldNames ? '' : 'backgroundImage',\n        protoName: 'backgroundImage', subBuilder: Image.create)\n    ..aOM<Image>(17, _omitFieldNames ? '' : 'backgroundImageV2',\n        protoName: 'backgroundImageV2', subBuilder: Image.create)\n    ..aOM<Text>(18, _omitFieldNames ? '' : 'anchorDisplayText',\n        protoName: 'anchorDisplayText', subBuilder: Text.create)\n    ..aOM<PublicAreaCommon>(19, _omitFieldNames ? '' : 'publicAreaCommon',\n        protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create)\n    ..a<$fixnum.Int64>(\n        20, _omitFieldNames ? '' : 'userEnterTipType', $pb.PbFieldType.OU6,\n        protoName: 'userEnterTipType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        21, _omitFieldNames ? '' : 'anchorEnterTipType', $pb.PbFieldType.OU6,\n        protoName: 'anchorEnterTipType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  MemberMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  MemberMessage copyWith(void Function(MemberMessage) updates) =>\n      super.copyWith((message) => updates(message as MemberMessage))\n          as MemberMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static MemberMessage create() => MemberMessage._();\n  @$core.override\n  MemberMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static MemberMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<MemberMessage>(create);\n  static MemberMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get memberCount => $_getI64(2);\n  @$pb.TagNumber(3)\n  set memberCount($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasMemberCount() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearMemberCount() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  User get operator => $_getN(3);\n  @$pb.TagNumber(4)\n  set operator(User value) => $_setField(4, value);\n  @$pb.TagNumber(4)\n  $core.bool hasOperator() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearOperator() => $_clearField(4);\n  @$pb.TagNumber(4)\n  User ensureOperator() => $_ensure(3);\n\n  @$pb.TagNumber(5)\n  $core.bool get isSetToAdmin => $_getBF(4);\n  @$pb.TagNumber(5)\n  set isSetToAdmin($core.bool value) => $_setBool(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasIsSetToAdmin() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearIsSetToAdmin() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.bool get isTopUser => $_getBF(5);\n  @$pb.TagNumber(6)\n  set isTopUser($core.bool value) => $_setBool(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasIsTopUser() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearIsTopUser() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $fixnum.Int64 get rankScore => $_getI64(6);\n  @$pb.TagNumber(7)\n  set rankScore($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasRankScore() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearRankScore() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $fixnum.Int64 get topUserNo => $_getI64(7);\n  @$pb.TagNumber(8)\n  set topUserNo($fixnum.Int64 value) => $_setInt64(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasTopUserNo() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearTopUserNo() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $fixnum.Int64 get enterType => $_getI64(8);\n  @$pb.TagNumber(9)\n  set enterType($fixnum.Int64 value) => $_setInt64(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasEnterType() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearEnterType() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $fixnum.Int64 get action => $_getI64(9);\n  @$pb.TagNumber(10)\n  set action($fixnum.Int64 value) => $_setInt64(9, value);\n  @$pb.TagNumber(10)\n  $core.bool hasAction() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearAction() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $core.String get actionDescription => $_getSZ(10);\n  @$pb.TagNumber(11)\n  set actionDescription($core.String value) => $_setString(10, value);\n  @$pb.TagNumber(11)\n  $core.bool hasActionDescription() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearActionDescription() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $fixnum.Int64 get userId => $_getI64(11);\n  @$pb.TagNumber(12)\n  set userId($fixnum.Int64 value) => $_setInt64(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasUserId() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearUserId() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  EffectConfig get effectConfig => $_getN(12);\n  @$pb.TagNumber(13)\n  set effectConfig(EffectConfig value) => $_setField(13, value);\n  @$pb.TagNumber(13)\n  $core.bool hasEffectConfig() => $_has(12);\n  @$pb.TagNumber(13)\n  void clearEffectConfig() => $_clearField(13);\n  @$pb.TagNumber(13)\n  EffectConfig ensureEffectConfig() => $_ensure(12);\n\n  @$pb.TagNumber(14)\n  $core.String get popStr => $_getSZ(13);\n  @$pb.TagNumber(14)\n  set popStr($core.String value) => $_setString(13, value);\n  @$pb.TagNumber(14)\n  $core.bool hasPopStr() => $_has(13);\n  @$pb.TagNumber(14)\n  void clearPopStr() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  EffectConfig get enterEffectConfig => $_getN(14);\n  @$pb.TagNumber(15)\n  set enterEffectConfig(EffectConfig value) => $_setField(15, value);\n  @$pb.TagNumber(15)\n  $core.bool hasEnterEffectConfig() => $_has(14);\n  @$pb.TagNumber(15)\n  void clearEnterEffectConfig() => $_clearField(15);\n  @$pb.TagNumber(15)\n  EffectConfig ensureEnterEffectConfig() => $_ensure(14);\n\n  @$pb.TagNumber(16)\n  Image get backgroundImage => $_getN(15);\n  @$pb.TagNumber(16)\n  set backgroundImage(Image value) => $_setField(16, value);\n  @$pb.TagNumber(16)\n  $core.bool hasBackgroundImage() => $_has(15);\n  @$pb.TagNumber(16)\n  void clearBackgroundImage() => $_clearField(16);\n  @$pb.TagNumber(16)\n  Image ensureBackgroundImage() => $_ensure(15);\n\n  @$pb.TagNumber(17)\n  Image get backgroundImageV2 => $_getN(16);\n  @$pb.TagNumber(17)\n  set backgroundImageV2(Image value) => $_setField(17, value);\n  @$pb.TagNumber(17)\n  $core.bool hasBackgroundImageV2() => $_has(16);\n  @$pb.TagNumber(17)\n  void clearBackgroundImageV2() => $_clearField(17);\n  @$pb.TagNumber(17)\n  Image ensureBackgroundImageV2() => $_ensure(16);\n\n  @$pb.TagNumber(18)\n  Text get anchorDisplayText => $_getN(17);\n  @$pb.TagNumber(18)\n  set anchorDisplayText(Text value) => $_setField(18, value);\n  @$pb.TagNumber(18)\n  $core.bool hasAnchorDisplayText() => $_has(17);\n  @$pb.TagNumber(18)\n  void clearAnchorDisplayText() => $_clearField(18);\n  @$pb.TagNumber(18)\n  Text ensureAnchorDisplayText() => $_ensure(17);\n\n  @$pb.TagNumber(19)\n  PublicAreaCommon get publicAreaCommon => $_getN(18);\n  @$pb.TagNumber(19)\n  set publicAreaCommon(PublicAreaCommon value) => $_setField(19, value);\n  @$pb.TagNumber(19)\n  $core.bool hasPublicAreaCommon() => $_has(18);\n  @$pb.TagNumber(19)\n  void clearPublicAreaCommon() => $_clearField(19);\n  @$pb.TagNumber(19)\n  PublicAreaCommon ensurePublicAreaCommon() => $_ensure(18);\n\n  @$pb.TagNumber(20)\n  $fixnum.Int64 get userEnterTipType => $_getI64(19);\n  @$pb.TagNumber(20)\n  set userEnterTipType($fixnum.Int64 value) => $_setInt64(19, value);\n  @$pb.TagNumber(20)\n  $core.bool hasUserEnterTipType() => $_has(19);\n  @$pb.TagNumber(20)\n  void clearUserEnterTipType() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $fixnum.Int64 get anchorEnterTipType => $_getI64(20);\n  @$pb.TagNumber(21)\n  set anchorEnterTipType($fixnum.Int64 value) => $_setInt64(20, value);\n  @$pb.TagNumber(21)\n  $core.bool hasAnchorEnterTipType() => $_has(20);\n  @$pb.TagNumber(21)\n  void clearAnchorEnterTipType() => $_clearField(21);\n}\n\nclass PublicAreaCommon extends $pb.GeneratedMessage {\n  factory PublicAreaCommon({\n    Image? userLabel,\n    $fixnum.Int64? userConsumeInRoom,\n    $fixnum.Int64? userSendGiftCntInRoom,\n  }) {\n    final result = create();\n    if (userLabel != null) result.userLabel = userLabel;\n    if (userConsumeInRoom != null) result.userConsumeInRoom = userConsumeInRoom;\n    if (userSendGiftCntInRoom != null)\n      result.userSendGiftCntInRoom = userSendGiftCntInRoom;\n    return result;\n  }\n\n  PublicAreaCommon._();\n\n  factory PublicAreaCommon.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory PublicAreaCommon.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'PublicAreaCommon',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Image>(1, _omitFieldNames ? '' : 'userLabel',\n        protoName: 'userLabel', subBuilder: Image.create)\n    ..a<$fixnum.Int64>(\n        2, _omitFieldNames ? '' : 'userConsumeInRoom', $pb.PbFieldType.OU6,\n        protoName: 'userConsumeInRoom', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'userSendGiftCntInRoom', $pb.PbFieldType.OU6,\n        protoName: 'userSendGiftCntInRoom', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PublicAreaCommon clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PublicAreaCommon copyWith(void Function(PublicAreaCommon) updates) =>\n      super.copyWith((message) => updates(message as PublicAreaCommon))\n          as PublicAreaCommon;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static PublicAreaCommon create() => PublicAreaCommon._();\n  @$core.override\n  PublicAreaCommon createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static PublicAreaCommon getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<PublicAreaCommon>(create);\n  static PublicAreaCommon? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Image get userLabel => $_getN(0);\n  @$pb.TagNumber(1)\n  set userLabel(Image value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasUserLabel() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearUserLabel() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Image ensureUserLabel() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get userConsumeInRoom => $_getI64(1);\n  @$pb.TagNumber(2)\n  set userConsumeInRoom($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUserConsumeInRoom() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUserConsumeInRoom() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get userSendGiftCntInRoom => $_getI64(2);\n  @$pb.TagNumber(3)\n  set userSendGiftCntInRoom($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasUserSendGiftCntInRoom() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearUserSendGiftCntInRoom() => $_clearField(3);\n}\n\nclass EffectConfig extends $pb.GeneratedMessage {\n  factory EffectConfig({\n    $fixnum.Int64? type,\n    Image? icon,\n    $fixnum.Int64? avatarPos,\n    Text? text,\n    Image? textIcon,\n    $core.int? stayTime,\n    $fixnum.Int64? animAssetId,\n    Image? badge,\n    $core.Iterable<$fixnum.Int64>? flexSettingArrayList,\n    Image? textIconOverlay,\n    Image? animatedBadge,\n    $core.bool? hasSweepLight,\n    $core.Iterable<$fixnum.Int64>? textFlexSettingArrayList,\n    $fixnum.Int64? centerAnimAssetId,\n    Image? dynamicImage,\n    $core.Iterable<$core.MapEntry<$core.String, $core.String>>? extraMap,\n    $fixnum.Int64? mp4AnimAssetId,\n    $fixnum.Int64? priority,\n    $fixnum.Int64? maxWaitTime,\n    $core.String? dressId,\n    $fixnum.Int64? alignment,\n    $fixnum.Int64? alignmentOffset,\n  }) {\n    final result = create();\n    if (type != null) result.type = type;\n    if (icon != null) result.icon = icon;\n    if (avatarPos != null) result.avatarPos = avatarPos;\n    if (text != null) result.text = text;\n    if (textIcon != null) result.textIcon = textIcon;\n    if (stayTime != null) result.stayTime = stayTime;\n    if (animAssetId != null) result.animAssetId = animAssetId;\n    if (badge != null) result.badge = badge;\n    if (flexSettingArrayList != null)\n      result.flexSettingArrayList.addAll(flexSettingArrayList);\n    if (textIconOverlay != null) result.textIconOverlay = textIconOverlay;\n    if (animatedBadge != null) result.animatedBadge = animatedBadge;\n    if (hasSweepLight != null) result.hasSweepLight = hasSweepLight;\n    if (textFlexSettingArrayList != null)\n      result.textFlexSettingArrayList.addAll(textFlexSettingArrayList);\n    if (centerAnimAssetId != null) result.centerAnimAssetId = centerAnimAssetId;\n    if (dynamicImage != null) result.dynamicImage = dynamicImage;\n    if (extraMap != null) result.extraMap.addEntries(extraMap);\n    if (mp4AnimAssetId != null) result.mp4AnimAssetId = mp4AnimAssetId;\n    if (priority != null) result.priority = priority;\n    if (maxWaitTime != null) result.maxWaitTime = maxWaitTime;\n    if (dressId != null) result.dressId = dressId;\n    if (alignment != null) result.alignment = alignment;\n    if (alignmentOffset != null) result.alignmentOffset = alignmentOffset;\n    return result;\n  }\n\n  EffectConfig._();\n\n  factory EffectConfig.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory EffectConfig.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'EffectConfig',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<Image>(2, _omitFieldNames ? '' : 'icon', subBuilder: Image.create)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'avatarPos', $pb.PbFieldType.OU6,\n        protoName: 'avatarPos', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<Text>(4, _omitFieldNames ? '' : 'text', subBuilder: Text.create)\n    ..aOM<Image>(5, _omitFieldNames ? '' : 'textIcon',\n        protoName: 'textIcon', subBuilder: Image.create)\n    ..aI(6, _omitFieldNames ? '' : 'stayTime',\n        protoName: 'stayTime', fieldType: $pb.PbFieldType.OU3)\n    ..a<$fixnum.Int64>(\n        7, _omitFieldNames ? '' : 'animAssetId', $pb.PbFieldType.OU6,\n        protoName: 'animAssetId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<Image>(8, _omitFieldNames ? '' : 'badge', subBuilder: Image.create)\n    ..p<$fixnum.Int64>(\n        9, _omitFieldNames ? '' : 'flexSettingArrayList', $pb.PbFieldType.KU6,\n        protoName: 'flexSettingArrayList')\n    ..aOM<Image>(10, _omitFieldNames ? '' : 'textIconOverlay',\n        protoName: 'textIconOverlay', subBuilder: Image.create)\n    ..aOM<Image>(11, _omitFieldNames ? '' : 'animatedBadge',\n        protoName: 'animatedBadge', subBuilder: Image.create)\n    ..aOB(12, _omitFieldNames ? '' : 'hasSweepLight',\n        protoName: 'hasSweepLight')\n    ..p<$fixnum.Int64>(13, _omitFieldNames ? '' : 'textFlexSettingArrayList',\n        $pb.PbFieldType.KU6,\n        protoName: 'textFlexSettingArrayList')\n    ..a<$fixnum.Int64>(\n        14, _omitFieldNames ? '' : 'centerAnimAssetId', $pb.PbFieldType.OU6,\n        protoName: 'centerAnimAssetId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<Image>(15, _omitFieldNames ? '' : 'dynamicImage',\n        protoName: 'dynamicImage', subBuilder: Image.create)\n    ..m<$core.String, $core.String>(16, _omitFieldNames ? '' : 'extraMap',\n        protoName: 'extraMap',\n        entryClassName: 'EffectConfig.ExtraMapEntry',\n        keyFieldType: $pb.PbFieldType.OS,\n        valueFieldType: $pb.PbFieldType.OS,\n        packageName: const $pb.PackageName('douyin'))\n    ..a<$fixnum.Int64>(\n        17, _omitFieldNames ? '' : 'mp4AnimAssetId', $pb.PbFieldType.OU6,\n        protoName: 'mp4AnimAssetId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        18, _omitFieldNames ? '' : 'priority', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        19, _omitFieldNames ? '' : 'maxWaitTime', $pb.PbFieldType.OU6,\n        protoName: 'maxWaitTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(20, _omitFieldNames ? '' : 'dressId', protoName: 'dressId')\n    ..a<$fixnum.Int64>(\n        21, _omitFieldNames ? '' : 'alignment', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        22, _omitFieldNames ? '' : 'alignmentOffset', $pb.PbFieldType.OU6,\n        protoName: 'alignmentOffset', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  EffectConfig clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  EffectConfig copyWith(void Function(EffectConfig) updates) =>\n      super.copyWith((message) => updates(message as EffectConfig))\n          as EffectConfig;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static EffectConfig create() => EffectConfig._();\n  @$core.override\n  EffectConfig createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static EffectConfig getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<EffectConfig>(create);\n  static EffectConfig? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get type => $_getI64(0);\n  @$pb.TagNumber(1)\n  set type($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasType() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearType() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  Image get icon => $_getN(1);\n  @$pb.TagNumber(2)\n  set icon(Image value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasIcon() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearIcon() => $_clearField(2);\n  @$pb.TagNumber(2)\n  Image ensureIcon() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get avatarPos => $_getI64(2);\n  @$pb.TagNumber(3)\n  set avatarPos($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasAvatarPos() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearAvatarPos() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  Text get text => $_getN(3);\n  @$pb.TagNumber(4)\n  set text(Text value) => $_setField(4, value);\n  @$pb.TagNumber(4)\n  $core.bool hasText() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearText() => $_clearField(4);\n  @$pb.TagNumber(4)\n  Text ensureText() => $_ensure(3);\n\n  @$pb.TagNumber(5)\n  Image get textIcon => $_getN(4);\n  @$pb.TagNumber(5)\n  set textIcon(Image value) => $_setField(5, value);\n  @$pb.TagNumber(5)\n  $core.bool hasTextIcon() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearTextIcon() => $_clearField(5);\n  @$pb.TagNumber(5)\n  Image ensureTextIcon() => $_ensure(4);\n\n  @$pb.TagNumber(6)\n  $core.int get stayTime => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set stayTime($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasStayTime() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearStayTime() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $fixnum.Int64 get animAssetId => $_getI64(6);\n  @$pb.TagNumber(7)\n  set animAssetId($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasAnimAssetId() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearAnimAssetId() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  Image get badge => $_getN(7);\n  @$pb.TagNumber(8)\n  set badge(Image value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasBadge() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearBadge() => $_clearField(8);\n  @$pb.TagNumber(8)\n  Image ensureBadge() => $_ensure(7);\n\n  @$pb.TagNumber(9)\n  $pb.PbList<$fixnum.Int64> get flexSettingArrayList => $_getList(8);\n\n  @$pb.TagNumber(10)\n  Image get textIconOverlay => $_getN(9);\n  @$pb.TagNumber(10)\n  set textIconOverlay(Image value) => $_setField(10, value);\n  @$pb.TagNumber(10)\n  $core.bool hasTextIconOverlay() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearTextIconOverlay() => $_clearField(10);\n  @$pb.TagNumber(10)\n  Image ensureTextIconOverlay() => $_ensure(9);\n\n  @$pb.TagNumber(11)\n  Image get animatedBadge => $_getN(10);\n  @$pb.TagNumber(11)\n  set animatedBadge(Image value) => $_setField(11, value);\n  @$pb.TagNumber(11)\n  $core.bool hasAnimatedBadge() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearAnimatedBadge() => $_clearField(11);\n  @$pb.TagNumber(11)\n  Image ensureAnimatedBadge() => $_ensure(10);\n\n  @$pb.TagNumber(12)\n  $core.bool get hasSweepLight => $_getBF(11);\n  @$pb.TagNumber(12)\n  set hasSweepLight($core.bool value) => $_setBool(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasHasSweepLight() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearHasSweepLight() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $pb.PbList<$fixnum.Int64> get textFlexSettingArrayList => $_getList(12);\n\n  @$pb.TagNumber(14)\n  $fixnum.Int64 get centerAnimAssetId => $_getI64(13);\n  @$pb.TagNumber(14)\n  set centerAnimAssetId($fixnum.Int64 value) => $_setInt64(13, value);\n  @$pb.TagNumber(14)\n  $core.bool hasCenterAnimAssetId() => $_has(13);\n  @$pb.TagNumber(14)\n  void clearCenterAnimAssetId() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  Image get dynamicImage => $_getN(14);\n  @$pb.TagNumber(15)\n  set dynamicImage(Image value) => $_setField(15, value);\n  @$pb.TagNumber(15)\n  $core.bool hasDynamicImage() => $_has(14);\n  @$pb.TagNumber(15)\n  void clearDynamicImage() => $_clearField(15);\n  @$pb.TagNumber(15)\n  Image ensureDynamicImage() => $_ensure(14);\n\n  @$pb.TagNumber(16)\n  $pb.PbMap<$core.String, $core.String> get extraMap => $_getMap(15);\n\n  @$pb.TagNumber(17)\n  $fixnum.Int64 get mp4AnimAssetId => $_getI64(16);\n  @$pb.TagNumber(17)\n  set mp4AnimAssetId($fixnum.Int64 value) => $_setInt64(16, value);\n  @$pb.TagNumber(17)\n  $core.bool hasMp4AnimAssetId() => $_has(16);\n  @$pb.TagNumber(17)\n  void clearMp4AnimAssetId() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $fixnum.Int64 get priority => $_getI64(17);\n  @$pb.TagNumber(18)\n  set priority($fixnum.Int64 value) => $_setInt64(17, value);\n  @$pb.TagNumber(18)\n  $core.bool hasPriority() => $_has(17);\n  @$pb.TagNumber(18)\n  void clearPriority() => $_clearField(18);\n\n  @$pb.TagNumber(19)\n  $fixnum.Int64 get maxWaitTime => $_getI64(18);\n  @$pb.TagNumber(19)\n  set maxWaitTime($fixnum.Int64 value) => $_setInt64(18, value);\n  @$pb.TagNumber(19)\n  $core.bool hasMaxWaitTime() => $_has(18);\n  @$pb.TagNumber(19)\n  void clearMaxWaitTime() => $_clearField(19);\n\n  @$pb.TagNumber(20)\n  $core.String get dressId => $_getSZ(19);\n  @$pb.TagNumber(20)\n  set dressId($core.String value) => $_setString(19, value);\n  @$pb.TagNumber(20)\n  $core.bool hasDressId() => $_has(19);\n  @$pb.TagNumber(20)\n  void clearDressId() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $fixnum.Int64 get alignment => $_getI64(20);\n  @$pb.TagNumber(21)\n  set alignment($fixnum.Int64 value) => $_setInt64(20, value);\n  @$pb.TagNumber(21)\n  $core.bool hasAlignment() => $_has(20);\n  @$pb.TagNumber(21)\n  void clearAlignment() => $_clearField(21);\n\n  @$pb.TagNumber(22)\n  $fixnum.Int64 get alignmentOffset => $_getI64(21);\n  @$pb.TagNumber(22)\n  set alignmentOffset($fixnum.Int64 value) => $_setInt64(21, value);\n  @$pb.TagNumber(22)\n  $core.bool hasAlignmentOffset() => $_has(21);\n  @$pb.TagNumber(22)\n  void clearAlignmentOffset() => $_clearField(22);\n}\n\nclass Text extends $pb.GeneratedMessage {\n  factory Text({\n    $core.String? key,\n    $core.String? defaultPatter,\n    TextFormat? defaultFormat,\n    $core.Iterable<TextPiece>? piecesList,\n  }) {\n    final result = create();\n    if (key != null) result.key = key;\n    if (defaultPatter != null) result.defaultPatter = defaultPatter;\n    if (defaultFormat != null) result.defaultFormat = defaultFormat;\n    if (piecesList != null) result.piecesList.addAll(piecesList);\n    return result;\n  }\n\n  Text._();\n\n  factory Text.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Text.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Text',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'key')\n    ..aOS(2, _omitFieldNames ? '' : 'defaultPatter', protoName: 'defaultPatter')\n    ..aOM<TextFormat>(3, _omitFieldNames ? '' : 'defaultFormat',\n        protoName: 'defaultFormat', subBuilder: TextFormat.create)\n    ..pPM<TextPiece>(4, _omitFieldNames ? '' : 'piecesList',\n        protoName: 'piecesList', subBuilder: TextPiece.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Text clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Text copyWith(void Function(Text) updates) =>\n      super.copyWith((message) => updates(message as Text)) as Text;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Text create() => Text._();\n  @$core.override\n  Text createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Text getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Text>(create);\n  static Text? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get key => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set key($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasKey() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearKey() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get defaultPatter => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set defaultPatter($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasDefaultPatter() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearDefaultPatter() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  TextFormat get defaultFormat => $_getN(2);\n  @$pb.TagNumber(3)\n  set defaultFormat(TextFormat value) => $_setField(3, value);\n  @$pb.TagNumber(3)\n  $core.bool hasDefaultFormat() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearDefaultFormat() => $_clearField(3);\n  @$pb.TagNumber(3)\n  TextFormat ensureDefaultFormat() => $_ensure(2);\n\n  @$pb.TagNumber(4)\n  $pb.PbList<TextPiece> get piecesList => $_getList(3);\n}\n\nclass TextPiece extends $pb.GeneratedMessage {\n  factory TextPiece({\n    $core.bool? type,\n    TextFormat? format,\n    $core.String? stringValue,\n    TextPieceUser? userValue,\n    TextPieceGift? giftValue,\n    TextPieceHeart? heartValue,\n    TextPiecePatternRef? patternRefValue,\n    TextPieceImage? imageValue,\n  }) {\n    final result = create();\n    if (type != null) result.type = type;\n    if (format != null) result.format = format;\n    if (stringValue != null) result.stringValue = stringValue;\n    if (userValue != null) result.userValue = userValue;\n    if (giftValue != null) result.giftValue = giftValue;\n    if (heartValue != null) result.heartValue = heartValue;\n    if (patternRefValue != null) result.patternRefValue = patternRefValue;\n    if (imageValue != null) result.imageValue = imageValue;\n    return result;\n  }\n\n  TextPiece._();\n\n  factory TextPiece.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPiece.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPiece',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOB(1, _omitFieldNames ? '' : 'type')\n    ..aOM<TextFormat>(2, _omitFieldNames ? '' : 'format',\n        subBuilder: TextFormat.create)\n    ..aOS(3, _omitFieldNames ? '' : 'stringValue', protoName: 'stringValue')\n    ..aOM<TextPieceUser>(4, _omitFieldNames ? '' : 'userValue',\n        protoName: 'userValue', subBuilder: TextPieceUser.create)\n    ..aOM<TextPieceGift>(5, _omitFieldNames ? '' : 'giftValue',\n        protoName: 'giftValue', subBuilder: TextPieceGift.create)\n    ..aOM<TextPieceHeart>(6, _omitFieldNames ? '' : 'heartValue',\n        protoName: 'heartValue', subBuilder: TextPieceHeart.create)\n    ..aOM<TextPiecePatternRef>(7, _omitFieldNames ? '' : 'patternRefValue',\n        protoName: 'patternRefValue', subBuilder: TextPiecePatternRef.create)\n    ..aOM<TextPieceImage>(8, _omitFieldNames ? '' : 'imageValue',\n        protoName: 'imageValue', subBuilder: TextPieceImage.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPiece clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPiece copyWith(void Function(TextPiece) updates) =>\n      super.copyWith((message) => updates(message as TextPiece)) as TextPiece;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPiece create() => TextPiece._();\n  @$core.override\n  TextPiece createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPiece getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<TextPiece>(create);\n  static TextPiece? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.bool get type => $_getBF(0);\n  @$pb.TagNumber(1)\n  set type($core.bool value) => $_setBool(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasType() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearType() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  TextFormat get format => $_getN(1);\n  @$pb.TagNumber(2)\n  set format(TextFormat value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasFormat() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearFormat() => $_clearField(2);\n  @$pb.TagNumber(2)\n  TextFormat ensureFormat() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.String get stringValue => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set stringValue($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasStringValue() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearStringValue() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  TextPieceUser get userValue => $_getN(3);\n  @$pb.TagNumber(4)\n  set userValue(TextPieceUser value) => $_setField(4, value);\n  @$pb.TagNumber(4)\n  $core.bool hasUserValue() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearUserValue() => $_clearField(4);\n  @$pb.TagNumber(4)\n  TextPieceUser ensureUserValue() => $_ensure(3);\n\n  @$pb.TagNumber(5)\n  TextPieceGift get giftValue => $_getN(4);\n  @$pb.TagNumber(5)\n  set giftValue(TextPieceGift value) => $_setField(5, value);\n  @$pb.TagNumber(5)\n  $core.bool hasGiftValue() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearGiftValue() => $_clearField(5);\n  @$pb.TagNumber(5)\n  TextPieceGift ensureGiftValue() => $_ensure(4);\n\n  @$pb.TagNumber(6)\n  TextPieceHeart get heartValue => $_getN(5);\n  @$pb.TagNumber(6)\n  set heartValue(TextPieceHeart value) => $_setField(6, value);\n  @$pb.TagNumber(6)\n  $core.bool hasHeartValue() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearHeartValue() => $_clearField(6);\n  @$pb.TagNumber(6)\n  TextPieceHeart ensureHeartValue() => $_ensure(5);\n\n  @$pb.TagNumber(7)\n  TextPiecePatternRef get patternRefValue => $_getN(6);\n  @$pb.TagNumber(7)\n  set patternRefValue(TextPiecePatternRef value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasPatternRefValue() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearPatternRefValue() => $_clearField(7);\n  @$pb.TagNumber(7)\n  TextPiecePatternRef ensurePatternRefValue() => $_ensure(6);\n\n  @$pb.TagNumber(8)\n  TextPieceImage get imageValue => $_getN(7);\n  @$pb.TagNumber(8)\n  set imageValue(TextPieceImage value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasImageValue() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearImageValue() => $_clearField(8);\n  @$pb.TagNumber(8)\n  TextPieceImage ensureImageValue() => $_ensure(7);\n}\n\nclass TextPieceImage extends $pb.GeneratedMessage {\n  factory TextPieceImage({\n    Image? image,\n    $core.double? scalingRate,\n  }) {\n    final result = create();\n    if (image != null) result.image = image;\n    if (scalingRate != null) result.scalingRate = scalingRate;\n    return result;\n  }\n\n  TextPieceImage._();\n\n  factory TextPieceImage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPieceImage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPieceImage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Image>(1, _omitFieldNames ? '' : 'image', subBuilder: Image.create)\n    ..aD(2, _omitFieldNames ? '' : 'scalingRate',\n        protoName: 'scalingRate', fieldType: $pb.PbFieldType.OF)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceImage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceImage copyWith(void Function(TextPieceImage) updates) =>\n      super.copyWith((message) => updates(message as TextPieceImage))\n          as TextPieceImage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPieceImage create() => TextPieceImage._();\n  @$core.override\n  TextPieceImage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPieceImage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextPieceImage>(create);\n  static TextPieceImage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Image get image => $_getN(0);\n  @$pb.TagNumber(1)\n  set image(Image value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasImage() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearImage() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Image ensureImage() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $core.double get scalingRate => $_getN(1);\n  @$pb.TagNumber(2)\n  set scalingRate($core.double value) => $_setFloat(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasScalingRate() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearScalingRate() => $_clearField(2);\n}\n\nclass TextPiecePatternRef extends $pb.GeneratedMessage {\n  factory TextPiecePatternRef({\n    $core.String? key,\n    $core.String? defaultPattern,\n  }) {\n    final result = create();\n    if (key != null) result.key = key;\n    if (defaultPattern != null) result.defaultPattern = defaultPattern;\n    return result;\n  }\n\n  TextPiecePatternRef._();\n\n  factory TextPiecePatternRef.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPiecePatternRef.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPiecePatternRef',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'key')\n    ..aOS(2, _omitFieldNames ? '' : 'defaultPattern',\n        protoName: 'defaultPattern')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPiecePatternRef clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPiecePatternRef copyWith(void Function(TextPiecePatternRef) updates) =>\n      super.copyWith((message) => updates(message as TextPiecePatternRef))\n          as TextPiecePatternRef;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPiecePatternRef create() => TextPiecePatternRef._();\n  @$core.override\n  TextPiecePatternRef createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPiecePatternRef getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextPiecePatternRef>(create);\n  static TextPiecePatternRef? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get key => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set key($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasKey() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearKey() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get defaultPattern => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set defaultPattern($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasDefaultPattern() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearDefaultPattern() => $_clearField(2);\n}\n\nclass TextPieceHeart extends $pb.GeneratedMessage {\n  factory TextPieceHeart({\n    $core.String? color,\n  }) {\n    final result = create();\n    if (color != null) result.color = color;\n    return result;\n  }\n\n  TextPieceHeart._();\n\n  factory TextPieceHeart.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPieceHeart.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPieceHeart',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'color')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceHeart clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceHeart copyWith(void Function(TextPieceHeart) updates) =>\n      super.copyWith((message) => updates(message as TextPieceHeart))\n          as TextPieceHeart;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPieceHeart create() => TextPieceHeart._();\n  @$core.override\n  TextPieceHeart createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPieceHeart getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextPieceHeart>(create);\n  static TextPieceHeart? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get color => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set color($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasColor() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearColor() => $_clearField(1);\n}\n\nclass TextPieceGift extends $pb.GeneratedMessage {\n  factory TextPieceGift({\n    $fixnum.Int64? giftId,\n    PatternRef? nameRef,\n  }) {\n    final result = create();\n    if (giftId != null) result.giftId = giftId;\n    if (nameRef != null) result.nameRef = nameRef;\n    return result;\n  }\n\n  TextPieceGift._();\n\n  factory TextPieceGift.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPieceGift.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPieceGift',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'giftId', $pb.PbFieldType.OU6,\n        protoName: 'giftId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<PatternRef>(2, _omitFieldNames ? '' : 'nameRef',\n        protoName: 'nameRef', subBuilder: PatternRef.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceGift clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceGift copyWith(void Function(TextPieceGift) updates) =>\n      super.copyWith((message) => updates(message as TextPieceGift))\n          as TextPieceGift;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPieceGift create() => TextPieceGift._();\n  @$core.override\n  TextPieceGift createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPieceGift getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextPieceGift>(create);\n  static TextPieceGift? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get giftId => $_getI64(0);\n  @$pb.TagNumber(1)\n  set giftId($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasGiftId() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearGiftId() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  PatternRef get nameRef => $_getN(1);\n  @$pb.TagNumber(2)\n  set nameRef(PatternRef value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasNameRef() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearNameRef() => $_clearField(2);\n  @$pb.TagNumber(2)\n  PatternRef ensureNameRef() => $_ensure(1);\n}\n\nclass PatternRef extends $pb.GeneratedMessage {\n  factory PatternRef({\n    $core.String? key,\n    $core.String? defaultPattern,\n  }) {\n    final result = create();\n    if (key != null) result.key = key;\n    if (defaultPattern != null) result.defaultPattern = defaultPattern;\n    return result;\n  }\n\n  PatternRef._();\n\n  factory PatternRef.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory PatternRef.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'PatternRef',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'key')\n    ..aOS(2, _omitFieldNames ? '' : 'defaultPattern',\n        protoName: 'defaultPattern')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PatternRef clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PatternRef copyWith(void Function(PatternRef) updates) =>\n      super.copyWith((message) => updates(message as PatternRef)) as PatternRef;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static PatternRef create() => PatternRef._();\n  @$core.override\n  PatternRef createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static PatternRef getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<PatternRef>(create);\n  static PatternRef? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get key => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set key($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasKey() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearKey() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get defaultPattern => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set defaultPattern($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasDefaultPattern() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearDefaultPattern() => $_clearField(2);\n}\n\nclass TextPieceUser extends $pb.GeneratedMessage {\n  factory TextPieceUser({\n    User? user,\n    $core.bool? withColon,\n  }) {\n    final result = create();\n    if (user != null) result.user = user;\n    if (withColon != null) result.withColon = withColon;\n    return result;\n  }\n\n  TextPieceUser._();\n\n  factory TextPieceUser.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextPieceUser.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextPieceUser',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<User>(1, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOB(2, _omitFieldNames ? '' : 'withColon', protoName: 'withColon')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceUser clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextPieceUser copyWith(void Function(TextPieceUser) updates) =>\n      super.copyWith((message) => updates(message as TextPieceUser))\n          as TextPieceUser;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextPieceUser create() => TextPieceUser._();\n  @$core.override\n  TextPieceUser createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextPieceUser getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextPieceUser>(create);\n  static TextPieceUser? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  User get user => $_getN(0);\n  @$pb.TagNumber(1)\n  set user(User value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasUser() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearUser() => $_clearField(1);\n  @$pb.TagNumber(1)\n  User ensureUser() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $core.bool get withColon => $_getBF(1);\n  @$pb.TagNumber(2)\n  set withColon($core.bool value) => $_setBool(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasWithColon() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearWithColon() => $_clearField(2);\n}\n\nclass TextFormat extends $pb.GeneratedMessage {\n  factory TextFormat({\n    $core.String? color,\n    $core.bool? bold,\n    $core.bool? italic,\n    $core.int? weight,\n    $core.int? italicAngle,\n    $core.int? fontSize,\n    $core.bool? useHeighLightColor,\n    $core.bool? useRemoteClor,\n  }) {\n    final result = create();\n    if (color != null) result.color = color;\n    if (bold != null) result.bold = bold;\n    if (italic != null) result.italic = italic;\n    if (weight != null) result.weight = weight;\n    if (italicAngle != null) result.italicAngle = italicAngle;\n    if (fontSize != null) result.fontSize = fontSize;\n    if (useHeighLightColor != null)\n      result.useHeighLightColor = useHeighLightColor;\n    if (useRemoteClor != null) result.useRemoteClor = useRemoteClor;\n    return result;\n  }\n\n  TextFormat._();\n\n  factory TextFormat.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory TextFormat.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'TextFormat',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'color')\n    ..aOB(2, _omitFieldNames ? '' : 'bold')\n    ..aOB(3, _omitFieldNames ? '' : 'italic')\n    ..aI(4, _omitFieldNames ? '' : 'weight', fieldType: $pb.PbFieldType.OU3)\n    ..aI(5, _omitFieldNames ? '' : 'italicAngle',\n        protoName: 'italicAngle', fieldType: $pb.PbFieldType.OU3)\n    ..aI(6, _omitFieldNames ? '' : 'fontSize',\n        protoName: 'fontSize', fieldType: $pb.PbFieldType.OU3)\n    ..aOB(7, _omitFieldNames ? '' : 'useHeighLightColor',\n        protoName: 'useHeighLightColor')\n    ..aOB(8, _omitFieldNames ? '' : 'useRemoteClor', protoName: 'useRemoteClor')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextFormat clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  TextFormat copyWith(void Function(TextFormat) updates) =>\n      super.copyWith((message) => updates(message as TextFormat)) as TextFormat;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static TextFormat create() => TextFormat._();\n  @$core.override\n  TextFormat createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static TextFormat getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<TextFormat>(create);\n  static TextFormat? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get color => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set color($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasColor() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearColor() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.bool get bold => $_getBF(1);\n  @$pb.TagNumber(2)\n  set bold($core.bool value) => $_setBool(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasBold() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearBold() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.bool get italic => $_getBF(2);\n  @$pb.TagNumber(3)\n  set italic($core.bool value) => $_setBool(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasItalic() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearItalic() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.int get weight => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set weight($core.int value) => $_setUnsignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasWeight() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearWeight() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.int get italicAngle => $_getIZ(4);\n  @$pb.TagNumber(5)\n  set italicAngle($core.int value) => $_setUnsignedInt32(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasItalicAngle() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearItalicAngle() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get fontSize => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set fontSize($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasFontSize() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearFontSize() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.bool get useHeighLightColor => $_getBF(6);\n  @$pb.TagNumber(7)\n  set useHeighLightColor($core.bool value) => $_setBool(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasUseHeighLightColor() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearUseHeighLightColor() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.bool get useRemoteClor => $_getBF(7);\n  @$pb.TagNumber(8)\n  set useRemoteClor($core.bool value) => $_setBool(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasUseRemoteClor() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearUseRemoteClor() => $_clearField(8);\n}\n\n/// 点赞\nclass LikeMessage extends $pb.GeneratedMessage {\n  factory LikeMessage({\n    Common? common,\n    $fixnum.Int64? count,\n    $fixnum.Int64? total,\n    $fixnum.Int64? color,\n    User? user,\n    $core.String? icon,\n    DoubleLikeDetail? doubleLikeDetail,\n    DisplayControlInfo? displayControlInfo,\n    $fixnum.Int64? linkmicGuestUid,\n    $core.String? scene,\n    PicoDisplayInfo? picoDisplayInfo,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (count != null) result.count = count;\n    if (total != null) result.total = total;\n    if (color != null) result.color = color;\n    if (user != null) result.user = user;\n    if (icon != null) result.icon = icon;\n    if (doubleLikeDetail != null) result.doubleLikeDetail = doubleLikeDetail;\n    if (displayControlInfo != null)\n      result.displayControlInfo = displayControlInfo;\n    if (linkmicGuestUid != null) result.linkmicGuestUid = linkmicGuestUid;\n    if (scene != null) result.scene = scene;\n    if (picoDisplayInfo != null) result.picoDisplayInfo = picoDisplayInfo;\n    return result;\n  }\n\n  LikeMessage._();\n\n  factory LikeMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory LikeMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'LikeMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'count', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'total', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'color', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<User>(5, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOS(6, _omitFieldNames ? '' : 'icon')\n    ..aOM<DoubleLikeDetail>(7, _omitFieldNames ? '' : 'doubleLikeDetail',\n        protoName: 'doubleLikeDetail', subBuilder: DoubleLikeDetail.create)\n    ..aOM<DisplayControlInfo>(8, _omitFieldNames ? '' : 'displayControlInfo',\n        protoName: 'displayControlInfo', subBuilder: DisplayControlInfo.create)\n    ..a<$fixnum.Int64>(\n        9, _omitFieldNames ? '' : 'linkmicGuestUid', $pb.PbFieldType.OU6,\n        protoName: 'linkmicGuestUid', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(10, _omitFieldNames ? '' : 'scene')\n    ..aOM<PicoDisplayInfo>(11, _omitFieldNames ? '' : 'picoDisplayInfo',\n        protoName: 'picoDisplayInfo', subBuilder: PicoDisplayInfo.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  LikeMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  LikeMessage copyWith(void Function(LikeMessage) updates) =>\n      super.copyWith((message) => updates(message as LikeMessage))\n          as LikeMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static LikeMessage create() => LikeMessage._();\n  @$core.override\n  LikeMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static LikeMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<LikeMessage>(create);\n  static LikeMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get count => $_getI64(1);\n  @$pb.TagNumber(2)\n  set count($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasCount() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearCount() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get total => $_getI64(2);\n  @$pb.TagNumber(3)\n  set total($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasTotal() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearTotal() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get color => $_getI64(3);\n  @$pb.TagNumber(4)\n  set color($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasColor() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearColor() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  User get user => $_getN(4);\n  @$pb.TagNumber(5)\n  set user(User value) => $_setField(5, value);\n  @$pb.TagNumber(5)\n  $core.bool hasUser() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearUser() => $_clearField(5);\n  @$pb.TagNumber(5)\n  User ensureUser() => $_ensure(4);\n\n  @$pb.TagNumber(6)\n  $core.String get icon => $_getSZ(5);\n  @$pb.TagNumber(6)\n  set icon($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasIcon() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearIcon() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  DoubleLikeDetail get doubleLikeDetail => $_getN(6);\n  @$pb.TagNumber(7)\n  set doubleLikeDetail(DoubleLikeDetail value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasDoubleLikeDetail() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearDoubleLikeDetail() => $_clearField(7);\n  @$pb.TagNumber(7)\n  DoubleLikeDetail ensureDoubleLikeDetail() => $_ensure(6);\n\n  @$pb.TagNumber(8)\n  DisplayControlInfo get displayControlInfo => $_getN(7);\n  @$pb.TagNumber(8)\n  set displayControlInfo(DisplayControlInfo value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasDisplayControlInfo() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearDisplayControlInfo() => $_clearField(8);\n  @$pb.TagNumber(8)\n  DisplayControlInfo ensureDisplayControlInfo() => $_ensure(7);\n\n  @$pb.TagNumber(9)\n  $fixnum.Int64 get linkmicGuestUid => $_getI64(8);\n  @$pb.TagNumber(9)\n  set linkmicGuestUid($fixnum.Int64 value) => $_setInt64(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasLinkmicGuestUid() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearLinkmicGuestUid() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $core.String get scene => $_getSZ(9);\n  @$pb.TagNumber(10)\n  set scene($core.String value) => $_setString(9, value);\n  @$pb.TagNumber(10)\n  $core.bool hasScene() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearScene() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  PicoDisplayInfo get picoDisplayInfo => $_getN(10);\n  @$pb.TagNumber(11)\n  set picoDisplayInfo(PicoDisplayInfo value) => $_setField(11, value);\n  @$pb.TagNumber(11)\n  $core.bool hasPicoDisplayInfo() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearPicoDisplayInfo() => $_clearField(11);\n  @$pb.TagNumber(11)\n  PicoDisplayInfo ensurePicoDisplayInfo() => $_ensure(10);\n}\n\nclass SocialMessage extends $pb.GeneratedMessage {\n  factory SocialMessage({\n    Common? common,\n    User? user,\n    $fixnum.Int64? shareType,\n    $fixnum.Int64? action,\n    $core.String? shareTarget,\n    $fixnum.Int64? followCount,\n    PublicAreaCommon? publicAreaCommon,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (user != null) result.user = user;\n    if (shareType != null) result.shareType = shareType;\n    if (action != null) result.action = action;\n    if (shareTarget != null) result.shareTarget = shareTarget;\n    if (followCount != null) result.followCount = followCount;\n    if (publicAreaCommon != null) result.publicAreaCommon = publicAreaCommon;\n    return result;\n  }\n\n  SocialMessage._();\n\n  factory SocialMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory SocialMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'SocialMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'shareType', $pb.PbFieldType.OU6,\n        protoName: 'shareType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'action', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(5, _omitFieldNames ? '' : 'shareTarget', protoName: 'shareTarget')\n    ..a<$fixnum.Int64>(\n        6, _omitFieldNames ? '' : 'followCount', $pb.PbFieldType.OU6,\n        protoName: 'followCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOM<PublicAreaCommon>(7, _omitFieldNames ? '' : 'publicAreaCommon',\n        protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  SocialMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  SocialMessage copyWith(void Function(SocialMessage) updates) =>\n      super.copyWith((message) => updates(message as SocialMessage))\n          as SocialMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static SocialMessage create() => SocialMessage._();\n  @$core.override\n  SocialMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static SocialMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<SocialMessage>(create);\n  static SocialMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get shareType => $_getI64(2);\n  @$pb.TagNumber(3)\n  set shareType($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasShareType() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearShareType() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get action => $_getI64(3);\n  @$pb.TagNumber(4)\n  set action($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasAction() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearAction() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.String get shareTarget => $_getSZ(4);\n  @$pb.TagNumber(5)\n  set shareTarget($core.String value) => $_setString(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasShareTarget() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearShareTarget() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $fixnum.Int64 get followCount => $_getI64(5);\n  @$pb.TagNumber(6)\n  set followCount($fixnum.Int64 value) => $_setInt64(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasFollowCount() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearFollowCount() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  PublicAreaCommon get publicAreaCommon => $_getN(6);\n  @$pb.TagNumber(7)\n  set publicAreaCommon(PublicAreaCommon value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasPublicAreaCommon() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearPublicAreaCommon() => $_clearField(7);\n  @$pb.TagNumber(7)\n  PublicAreaCommon ensurePublicAreaCommon() => $_ensure(6);\n}\n\nclass PicoDisplayInfo extends $pb.GeneratedMessage {\n  factory PicoDisplayInfo({\n    $fixnum.Int64? comboSumCount,\n    $core.String? emoji,\n    Image? emojiIcon,\n    $core.String? emojiText,\n  }) {\n    final result = create();\n    if (comboSumCount != null) result.comboSumCount = comboSumCount;\n    if (emoji != null) result.emoji = emoji;\n    if (emojiIcon != null) result.emojiIcon = emojiIcon;\n    if (emojiText != null) result.emojiText = emojiText;\n    return result;\n  }\n\n  PicoDisplayInfo._();\n\n  factory PicoDisplayInfo.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory PicoDisplayInfo.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'PicoDisplayInfo',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(\n        1, _omitFieldNames ? '' : 'comboSumCount', $pb.PbFieldType.OU6,\n        protoName: 'comboSumCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(2, _omitFieldNames ? '' : 'emoji')\n    ..aOM<Image>(3, _omitFieldNames ? '' : 'emojiIcon',\n        protoName: 'emojiIcon', subBuilder: Image.create)\n    ..aOS(4, _omitFieldNames ? '' : 'emojiText', protoName: 'emojiText')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PicoDisplayInfo clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PicoDisplayInfo copyWith(void Function(PicoDisplayInfo) updates) =>\n      super.copyWith((message) => updates(message as PicoDisplayInfo))\n          as PicoDisplayInfo;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static PicoDisplayInfo create() => PicoDisplayInfo._();\n  @$core.override\n  PicoDisplayInfo createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static PicoDisplayInfo getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<PicoDisplayInfo>(create);\n  static PicoDisplayInfo? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get comboSumCount => $_getI64(0);\n  @$pb.TagNumber(1)\n  set comboSumCount($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasComboSumCount() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearComboSumCount() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get emoji => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set emoji($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasEmoji() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearEmoji() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  Image get emojiIcon => $_getN(2);\n  @$pb.TagNumber(3)\n  set emojiIcon(Image value) => $_setField(3, value);\n  @$pb.TagNumber(3)\n  $core.bool hasEmojiIcon() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearEmojiIcon() => $_clearField(3);\n  @$pb.TagNumber(3)\n  Image ensureEmojiIcon() => $_ensure(2);\n\n  @$pb.TagNumber(4)\n  $core.String get emojiText => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set emojiText($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasEmojiText() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearEmojiText() => $_clearField(4);\n}\n\nclass DoubleLikeDetail extends $pb.GeneratedMessage {\n  factory DoubleLikeDetail({\n    $core.bool? doubleFlag,\n    $core.int? seqId,\n    $core.int? renewalsNum,\n    $core.int? triggersNum,\n  }) {\n    final result = create();\n    if (doubleFlag != null) result.doubleFlag = doubleFlag;\n    if (seqId != null) result.seqId = seqId;\n    if (renewalsNum != null) result.renewalsNum = renewalsNum;\n    if (triggersNum != null) result.triggersNum = triggersNum;\n    return result;\n  }\n\n  DoubleLikeDetail._();\n\n  factory DoubleLikeDetail.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory DoubleLikeDetail.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'DoubleLikeDetail',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOB(1, _omitFieldNames ? '' : 'doubleFlag', protoName: 'doubleFlag')\n    ..aI(2, _omitFieldNames ? '' : 'seqId',\n        protoName: 'seqId', fieldType: $pb.PbFieldType.OU3)\n    ..aI(3, _omitFieldNames ? '' : 'renewalsNum',\n        protoName: 'renewalsNum', fieldType: $pb.PbFieldType.OU3)\n    ..aI(4, _omitFieldNames ? '' : 'triggersNum',\n        protoName: 'triggersNum', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  DoubleLikeDetail clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  DoubleLikeDetail copyWith(void Function(DoubleLikeDetail) updates) =>\n      super.copyWith((message) => updates(message as DoubleLikeDetail))\n          as DoubleLikeDetail;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static DoubleLikeDetail create() => DoubleLikeDetail._();\n  @$core.override\n  DoubleLikeDetail createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static DoubleLikeDetail getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<DoubleLikeDetail>(create);\n  static DoubleLikeDetail? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.bool get doubleFlag => $_getBF(0);\n  @$pb.TagNumber(1)\n  set doubleFlag($core.bool value) => $_setBool(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasDoubleFlag() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearDoubleFlag() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.int get seqId => $_getIZ(1);\n  @$pb.TagNumber(2)\n  set seqId($core.int value) => $_setUnsignedInt32(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasSeqId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearSeqId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.int get renewalsNum => $_getIZ(2);\n  @$pb.TagNumber(3)\n  set renewalsNum($core.int value) => $_setUnsignedInt32(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasRenewalsNum() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearRenewalsNum() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.int get triggersNum => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set triggersNum($core.int value) => $_setUnsignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasTriggersNum() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearTriggersNum() => $_clearField(4);\n}\n\nclass DisplayControlInfo extends $pb.GeneratedMessage {\n  factory DisplayControlInfo({\n    $core.bool? showText,\n    $core.bool? showIcons,\n  }) {\n    final result = create();\n    if (showText != null) result.showText = showText;\n    if (showIcons != null) result.showIcons = showIcons;\n    return result;\n  }\n\n  DisplayControlInfo._();\n\n  factory DisplayControlInfo.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory DisplayControlInfo.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'DisplayControlInfo',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOB(1, _omitFieldNames ? '' : 'showText', protoName: 'showText')\n    ..aOB(2, _omitFieldNames ? '' : 'showIcons', protoName: 'showIcons')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  DisplayControlInfo clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  DisplayControlInfo copyWith(void Function(DisplayControlInfo) updates) =>\n      super.copyWith((message) => updates(message as DisplayControlInfo))\n          as DisplayControlInfo;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static DisplayControlInfo create() => DisplayControlInfo._();\n  @$core.override\n  DisplayControlInfo createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static DisplayControlInfo getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<DisplayControlInfo>(create);\n  static DisplayControlInfo? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.bool get showText => $_getBF(0);\n  @$pb.TagNumber(1)\n  set showText($core.bool value) => $_setBool(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasShowText() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearShowText() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.bool get showIcons => $_getBF(1);\n  @$pb.TagNumber(2)\n  set showIcons($core.bool value) => $_setBool(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasShowIcons() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearShowIcons() => $_clearField(2);\n}\n\nclass EpisodeChatMessage extends $pb.GeneratedMessage {\n  factory EpisodeChatMessage({\n    Message? common,\n    User? user,\n    $core.String? content,\n    $core.bool? visibleToSende,\n    Image? giftImage,\n    $fixnum.Int64? agreeMsgId,\n    $core.Iterable<$core.String>? colorValueList,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (user != null) result.user = user;\n    if (content != null) result.content = content;\n    if (visibleToSende != null) result.visibleToSende = visibleToSende;\n    if (giftImage != null) result.giftImage = giftImage;\n    if (agreeMsgId != null) result.agreeMsgId = agreeMsgId;\n    if (colorValueList != null) result.colorValueList.addAll(colorValueList);\n    return result;\n  }\n\n  EpisodeChatMessage._();\n\n  factory EpisodeChatMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory EpisodeChatMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'EpisodeChatMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Message>(1, _omitFieldNames ? '' : 'common',\n        subBuilder: Message.create)\n    ..aOM<User>(2, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..aOS(3, _omitFieldNames ? '' : 'content')\n    ..aOB(4, _omitFieldNames ? '' : 'visibleToSende',\n        protoName: 'visibleToSende')\n    ..aOM<Image>(7, _omitFieldNames ? '' : 'giftImage',\n        protoName: 'giftImage', subBuilder: Image.create)\n    ..a<$fixnum.Int64>(\n        8, _omitFieldNames ? '' : 'agreeMsgId', $pb.PbFieldType.OU6,\n        protoName: 'agreeMsgId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..pPS(9, _omitFieldNames ? '' : 'colorValueList',\n        protoName: 'colorValueList')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  EpisodeChatMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  EpisodeChatMessage copyWith(void Function(EpisodeChatMessage) updates) =>\n      super.copyWith((message) => updates(message as EpisodeChatMessage))\n          as EpisodeChatMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static EpisodeChatMessage create() => EpisodeChatMessage._();\n  @$core.override\n  EpisodeChatMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static EpisodeChatMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<EpisodeChatMessage>(create);\n  static EpisodeChatMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Message get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Message value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Message ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  User get user => $_getN(1);\n  @$pb.TagNumber(2)\n  set user(User value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUser() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUser() => $_clearField(2);\n  @$pb.TagNumber(2)\n  User ensureUser() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.String get content => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set content($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasContent() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearContent() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.bool get visibleToSende => $_getBF(3);\n  @$pb.TagNumber(4)\n  set visibleToSende($core.bool value) => $_setBool(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasVisibleToSende() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearVisibleToSende() => $_clearField(4);\n\n  /// BackgroundImage backgroundImage = 5;\n  /// PublicAreaCommon publicAreaCommon = 6;\n  @$pb.TagNumber(7)\n  Image get giftImage => $_getN(4);\n  @$pb.TagNumber(7)\n  set giftImage(Image value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasGiftImage() => $_has(4);\n  @$pb.TagNumber(7)\n  void clearGiftImage() => $_clearField(7);\n  @$pb.TagNumber(7)\n  Image ensureGiftImage() => $_ensure(4);\n\n  @$pb.TagNumber(8)\n  $fixnum.Int64 get agreeMsgId => $_getI64(5);\n  @$pb.TagNumber(8)\n  set agreeMsgId($fixnum.Int64 value) => $_setInt64(5, value);\n  @$pb.TagNumber(8)\n  $core.bool hasAgreeMsgId() => $_has(5);\n  @$pb.TagNumber(8)\n  void clearAgreeMsgId() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  $pb.PbList<$core.String> get colorValueList => $_getList(6);\n}\n\nclass MatchAgainstScoreMessage extends $pb.GeneratedMessage {\n  factory MatchAgainstScoreMessage({\n    Common? common,\n    Against? against,\n    $core.int? matchStatus,\n    $core.int? displayStatus,\n  }) {\n    final result = create();\n    if (common != null) result.common = common;\n    if (against != null) result.against = against;\n    if (matchStatus != null) result.matchStatus = matchStatus;\n    if (displayStatus != null) result.displayStatus = displayStatus;\n    return result;\n  }\n\n  MatchAgainstScoreMessage._();\n\n  factory MatchAgainstScoreMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory MatchAgainstScoreMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'MatchAgainstScoreMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOM<Common>(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create)\n    ..aOM<Against>(2, _omitFieldNames ? '' : 'against',\n        subBuilder: Against.create)\n    ..aI(3, _omitFieldNames ? '' : 'matchStatus',\n        protoName: 'matchStatus', fieldType: $pb.PbFieldType.OU3)\n    ..aI(4, _omitFieldNames ? '' : 'displayStatus',\n        protoName: 'displayStatus', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  MatchAgainstScoreMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  MatchAgainstScoreMessage copyWith(\n          void Function(MatchAgainstScoreMessage) updates) =>\n      super.copyWith((message) => updates(message as MatchAgainstScoreMessage))\n          as MatchAgainstScoreMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static MatchAgainstScoreMessage create() => MatchAgainstScoreMessage._();\n  @$core.override\n  MatchAgainstScoreMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static MatchAgainstScoreMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<MatchAgainstScoreMessage>(create);\n  static MatchAgainstScoreMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  Common get common => $_getN(0);\n  @$pb.TagNumber(1)\n  set common(Common value) => $_setField(1, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCommon() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCommon() => $_clearField(1);\n  @$pb.TagNumber(1)\n  Common ensureCommon() => $_ensure(0);\n\n  @$pb.TagNumber(2)\n  Against get against => $_getN(1);\n  @$pb.TagNumber(2)\n  set against(Against value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasAgainst() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearAgainst() => $_clearField(2);\n  @$pb.TagNumber(2)\n  Against ensureAgainst() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.int get matchStatus => $_getIZ(2);\n  @$pb.TagNumber(3)\n  set matchStatus($core.int value) => $_setUnsignedInt32(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasMatchStatus() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearMatchStatus() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.int get displayStatus => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set displayStatus($core.int value) => $_setUnsignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasDisplayStatus() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearDisplayStatus() => $_clearField(4);\n}\n\nclass Against extends $pb.GeneratedMessage {\n  factory Against({\n    $core.String? leftName,\n    Image? leftLogo,\n    $core.String? leftGoal,\n    $core.String? rightName,\n    Image? rightLogo,\n    $core.String? rightGoal,\n    $fixnum.Int64? timestamp,\n    $fixnum.Int64? version,\n    $fixnum.Int64? leftTeamId,\n    $fixnum.Int64? rightTeamId,\n    $fixnum.Int64? diffSei2absSecond,\n    $core.int? finalGoalStage,\n    $core.int? currentGoalStage,\n    $core.int? leftScoreAddition,\n    $core.int? rightScoreAddition,\n    $fixnum.Int64? leftGoalInt,\n    $fixnum.Int64? rightGoalInt,\n  }) {\n    final result = create();\n    if (leftName != null) result.leftName = leftName;\n    if (leftLogo != null) result.leftLogo = leftLogo;\n    if (leftGoal != null) result.leftGoal = leftGoal;\n    if (rightName != null) result.rightName = rightName;\n    if (rightLogo != null) result.rightLogo = rightLogo;\n    if (rightGoal != null) result.rightGoal = rightGoal;\n    if (timestamp != null) result.timestamp = timestamp;\n    if (version != null) result.version = version;\n    if (leftTeamId != null) result.leftTeamId = leftTeamId;\n    if (rightTeamId != null) result.rightTeamId = rightTeamId;\n    if (diffSei2absSecond != null) result.diffSei2absSecond = diffSei2absSecond;\n    if (finalGoalStage != null) result.finalGoalStage = finalGoalStage;\n    if (currentGoalStage != null) result.currentGoalStage = currentGoalStage;\n    if (leftScoreAddition != null) result.leftScoreAddition = leftScoreAddition;\n    if (rightScoreAddition != null)\n      result.rightScoreAddition = rightScoreAddition;\n    if (leftGoalInt != null) result.leftGoalInt = leftGoalInt;\n    if (rightGoalInt != null) result.rightGoalInt = rightGoalInt;\n    return result;\n  }\n\n  Against._();\n\n  factory Against.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Against.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Against',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'leftName', protoName: 'leftName')\n    ..aOM<Image>(2, _omitFieldNames ? '' : 'leftLogo',\n        protoName: 'leftLogo', subBuilder: Image.create)\n    ..aOS(3, _omitFieldNames ? '' : 'leftGoal', protoName: 'leftGoal')\n    ..aOS(6, _omitFieldNames ? '' : 'rightName', protoName: 'rightName')\n    ..aOM<Image>(7, _omitFieldNames ? '' : 'rightLogo',\n        protoName: 'rightLogo', subBuilder: Image.create)\n    ..aOS(8, _omitFieldNames ? '' : 'rightGoal', protoName: 'rightGoal')\n    ..a<$fixnum.Int64>(\n        11, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        12, _omitFieldNames ? '' : 'version', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        13, _omitFieldNames ? '' : 'leftTeamId', $pb.PbFieldType.OU6,\n        protoName: 'leftTeamId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        14, _omitFieldNames ? '' : 'rightTeamId', $pb.PbFieldType.OU6,\n        protoName: 'rightTeamId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        15, _omitFieldNames ? '' : 'diffSei2absSecond', $pb.PbFieldType.OU6,\n        protoName: 'diffSei2absSecond', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aI(16, _omitFieldNames ? '' : 'finalGoalStage',\n        protoName: 'finalGoalStage', fieldType: $pb.PbFieldType.OU3)\n    ..aI(17, _omitFieldNames ? '' : 'currentGoalStage',\n        protoName: 'currentGoalStage', fieldType: $pb.PbFieldType.OU3)\n    ..aI(18, _omitFieldNames ? '' : 'leftScoreAddition',\n        protoName: 'leftScoreAddition', fieldType: $pb.PbFieldType.OU3)\n    ..aI(19, _omitFieldNames ? '' : 'rightScoreAddition',\n        protoName: 'rightScoreAddition', fieldType: $pb.PbFieldType.OU3)\n    ..a<$fixnum.Int64>(\n        20, _omitFieldNames ? '' : 'leftGoalInt', $pb.PbFieldType.OU6,\n        protoName: 'leftGoalInt', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        21, _omitFieldNames ? '' : 'rightGoalInt', $pb.PbFieldType.OU6,\n        protoName: 'rightGoalInt', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Against clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Against copyWith(void Function(Against) updates) =>\n      super.copyWith((message) => updates(message as Against)) as Against;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Against create() => Against._();\n  @$core.override\n  Against createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Against getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Against>(create);\n  static Against? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get leftName => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set leftName($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasLeftName() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearLeftName() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  Image get leftLogo => $_getN(1);\n  @$pb.TagNumber(2)\n  set leftLogo(Image value) => $_setField(2, value);\n  @$pb.TagNumber(2)\n  $core.bool hasLeftLogo() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearLeftLogo() => $_clearField(2);\n  @$pb.TagNumber(2)\n  Image ensureLeftLogo() => $_ensure(1);\n\n  @$pb.TagNumber(3)\n  $core.String get leftGoal => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set leftGoal($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasLeftGoal() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearLeftGoal() => $_clearField(3);\n\n  /// LeftPlayersList leftPlayersList = 4;\n  /// LeftGoalStageDetail leftGoalStageDetail = 5;\n  @$pb.TagNumber(6)\n  $core.String get rightName => $_getSZ(3);\n  @$pb.TagNumber(6)\n  set rightName($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(6)\n  $core.bool hasRightName() => $_has(3);\n  @$pb.TagNumber(6)\n  void clearRightName() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  Image get rightLogo => $_getN(4);\n  @$pb.TagNumber(7)\n  set rightLogo(Image value) => $_setField(7, value);\n  @$pb.TagNumber(7)\n  $core.bool hasRightLogo() => $_has(4);\n  @$pb.TagNumber(7)\n  void clearRightLogo() => $_clearField(7);\n  @$pb.TagNumber(7)\n  Image ensureRightLogo() => $_ensure(4);\n\n  @$pb.TagNumber(8)\n  $core.String get rightGoal => $_getSZ(5);\n  @$pb.TagNumber(8)\n  set rightGoal($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(8)\n  $core.bool hasRightGoal() => $_has(5);\n  @$pb.TagNumber(8)\n  void clearRightGoal() => $_clearField(8);\n\n  /// RightPlayersList rightPlayersList  = 9;\n  /// RightGoalStageDetail rightGoalStageDetail = 10;\n  @$pb.TagNumber(11)\n  $fixnum.Int64 get timestamp => $_getI64(6);\n  @$pb.TagNumber(11)\n  set timestamp($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(11)\n  $core.bool hasTimestamp() => $_has(6);\n  @$pb.TagNumber(11)\n  void clearTimestamp() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $fixnum.Int64 get version => $_getI64(7);\n  @$pb.TagNumber(12)\n  set version($fixnum.Int64 value) => $_setInt64(7, value);\n  @$pb.TagNumber(12)\n  $core.bool hasVersion() => $_has(7);\n  @$pb.TagNumber(12)\n  void clearVersion() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $fixnum.Int64 get leftTeamId => $_getI64(8);\n  @$pb.TagNumber(13)\n  set leftTeamId($fixnum.Int64 value) => $_setInt64(8, value);\n  @$pb.TagNumber(13)\n  $core.bool hasLeftTeamId() => $_has(8);\n  @$pb.TagNumber(13)\n  void clearLeftTeamId() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  $fixnum.Int64 get rightTeamId => $_getI64(9);\n  @$pb.TagNumber(14)\n  set rightTeamId($fixnum.Int64 value) => $_setInt64(9, value);\n  @$pb.TagNumber(14)\n  $core.bool hasRightTeamId() => $_has(9);\n  @$pb.TagNumber(14)\n  void clearRightTeamId() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  $fixnum.Int64 get diffSei2absSecond => $_getI64(10);\n  @$pb.TagNumber(15)\n  set diffSei2absSecond($fixnum.Int64 value) => $_setInt64(10, value);\n  @$pb.TagNumber(15)\n  $core.bool hasDiffSei2absSecond() => $_has(10);\n  @$pb.TagNumber(15)\n  void clearDiffSei2absSecond() => $_clearField(15);\n\n  @$pb.TagNumber(16)\n  $core.int get finalGoalStage => $_getIZ(11);\n  @$pb.TagNumber(16)\n  set finalGoalStage($core.int value) => $_setUnsignedInt32(11, value);\n  @$pb.TagNumber(16)\n  $core.bool hasFinalGoalStage() => $_has(11);\n  @$pb.TagNumber(16)\n  void clearFinalGoalStage() => $_clearField(16);\n\n  @$pb.TagNumber(17)\n  $core.int get currentGoalStage => $_getIZ(12);\n  @$pb.TagNumber(17)\n  set currentGoalStage($core.int value) => $_setUnsignedInt32(12, value);\n  @$pb.TagNumber(17)\n  $core.bool hasCurrentGoalStage() => $_has(12);\n  @$pb.TagNumber(17)\n  void clearCurrentGoalStage() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $core.int get leftScoreAddition => $_getIZ(13);\n  @$pb.TagNumber(18)\n  set leftScoreAddition($core.int value) => $_setUnsignedInt32(13, value);\n  @$pb.TagNumber(18)\n  $core.bool hasLeftScoreAddition() => $_has(13);\n  @$pb.TagNumber(18)\n  void clearLeftScoreAddition() => $_clearField(18);\n\n  @$pb.TagNumber(19)\n  $core.int get rightScoreAddition => $_getIZ(14);\n  @$pb.TagNumber(19)\n  set rightScoreAddition($core.int value) => $_setUnsignedInt32(14, value);\n  @$pb.TagNumber(19)\n  $core.bool hasRightScoreAddition() => $_has(14);\n  @$pb.TagNumber(19)\n  void clearRightScoreAddition() => $_clearField(19);\n\n  @$pb.TagNumber(20)\n  $fixnum.Int64 get leftGoalInt => $_getI64(15);\n  @$pb.TagNumber(20)\n  set leftGoalInt($fixnum.Int64 value) => $_setInt64(15, value);\n  @$pb.TagNumber(20)\n  $core.bool hasLeftGoalInt() => $_has(15);\n  @$pb.TagNumber(20)\n  void clearLeftGoalInt() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $fixnum.Int64 get rightGoalInt => $_getI64(16);\n  @$pb.TagNumber(21)\n  set rightGoalInt($fixnum.Int64 value) => $_setInt64(16, value);\n  @$pb.TagNumber(21)\n  $core.bool hasRightGoalInt() => $_has(16);\n  @$pb.TagNumber(21)\n  void clearRightGoalInt() => $_clearField(21);\n}\n\nclass Common extends $pb.GeneratedMessage {\n  factory Common({\n    $core.String? method,\n    $fixnum.Int64? msgId,\n    $fixnum.Int64? roomId,\n    $fixnum.Int64? createTime,\n    $core.int? monitor,\n    $core.bool? isShowMsg,\n    $core.String? describe,\n    $fixnum.Int64? foldType,\n    $fixnum.Int64? anchorFoldType,\n    $fixnum.Int64? priorityScore,\n    $core.String? logId,\n    $core.String? msgProcessFilterK,\n    $core.String? msgProcessFilterV,\n    User? user,\n    $fixnum.Int64? anchorFoldTypeV2,\n    $fixnum.Int64? processAtSeiTimeMs,\n    $fixnum.Int64? randomDispatchMs,\n    $core.bool? isDispatch,\n    $fixnum.Int64? channelId,\n    $fixnum.Int64? diffSei2absSecond,\n    $fixnum.Int64? anchorFoldDuration,\n  }) {\n    final result = create();\n    if (method != null) result.method = method;\n    if (msgId != null) result.msgId = msgId;\n    if (roomId != null) result.roomId = roomId;\n    if (createTime != null) result.createTime = createTime;\n    if (monitor != null) result.monitor = monitor;\n    if (isShowMsg != null) result.isShowMsg = isShowMsg;\n    if (describe != null) result.describe = describe;\n    if (foldType != null) result.foldType = foldType;\n    if (anchorFoldType != null) result.anchorFoldType = anchorFoldType;\n    if (priorityScore != null) result.priorityScore = priorityScore;\n    if (logId != null) result.logId = logId;\n    if (msgProcessFilterK != null) result.msgProcessFilterK = msgProcessFilterK;\n    if (msgProcessFilterV != null) result.msgProcessFilterV = msgProcessFilterV;\n    if (user != null) result.user = user;\n    if (anchorFoldTypeV2 != null) result.anchorFoldTypeV2 = anchorFoldTypeV2;\n    if (processAtSeiTimeMs != null)\n      result.processAtSeiTimeMs = processAtSeiTimeMs;\n    if (randomDispatchMs != null) result.randomDispatchMs = randomDispatchMs;\n    if (isDispatch != null) result.isDispatch = isDispatch;\n    if (channelId != null) result.channelId = channelId;\n    if (diffSei2absSecond != null) result.diffSei2absSecond = diffSei2absSecond;\n    if (anchorFoldDuration != null)\n      result.anchorFoldDuration = anchorFoldDuration;\n    return result;\n  }\n\n  Common._();\n\n  factory Common.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Common.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Common',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'method')\n    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'msgId', $pb.PbFieldType.OU6,\n        protoName: 'msgId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'roomId', $pb.PbFieldType.OU6,\n        protoName: 'roomId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        4, _omitFieldNames ? '' : 'createTime', $pb.PbFieldType.OU6,\n        protoName: 'createTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aI(5, _omitFieldNames ? '' : 'monitor', fieldType: $pb.PbFieldType.OU3)\n    ..aOB(6, _omitFieldNames ? '' : 'isShowMsg', protoName: 'isShowMsg')\n    ..aOS(7, _omitFieldNames ? '' : 'describe')\n    ..a<$fixnum.Int64>(\n        9, _omitFieldNames ? '' : 'foldType', $pb.PbFieldType.OU6,\n        protoName: 'foldType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        10, _omitFieldNames ? '' : 'anchorFoldType', $pb.PbFieldType.OU6,\n        protoName: 'anchorFoldType', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        11, _omitFieldNames ? '' : 'priorityScore', $pb.PbFieldType.OU6,\n        protoName: 'priorityScore', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(12, _omitFieldNames ? '' : 'logId', protoName: 'logId')\n    ..aOS(13, _omitFieldNames ? '' : 'msgProcessFilterK',\n        protoName: 'msgProcessFilterK')\n    ..aOS(14, _omitFieldNames ? '' : 'msgProcessFilterV',\n        protoName: 'msgProcessFilterV')\n    ..aOM<User>(15, _omitFieldNames ? '' : 'user', subBuilder: User.create)\n    ..a<$fixnum.Int64>(\n        17, _omitFieldNames ? '' : 'anchorFoldTypeV2', $pb.PbFieldType.OU6,\n        protoName: 'anchorFoldTypeV2', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        18, _omitFieldNames ? '' : 'processAtSeiTimeMs', $pb.PbFieldType.OU6,\n        protoName: 'processAtSeiTimeMs', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        19, _omitFieldNames ? '' : 'randomDispatchMs', $pb.PbFieldType.OU6,\n        protoName: 'randomDispatchMs', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOB(20, _omitFieldNames ? '' : 'isDispatch', protoName: 'isDispatch')\n    ..a<$fixnum.Int64>(\n        21, _omitFieldNames ? '' : 'channelId', $pb.PbFieldType.OU6,\n        protoName: 'channelId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        22, _omitFieldNames ? '' : 'diffSei2absSecond', $pb.PbFieldType.OU6,\n        protoName: 'diffSei2absSecond', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        23, _omitFieldNames ? '' : 'anchorFoldDuration', $pb.PbFieldType.OU6,\n        protoName: 'anchorFoldDuration', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Common clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Common copyWith(void Function(Common) updates) =>\n      super.copyWith((message) => updates(message as Common)) as Common;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Common create() => Common._();\n  @$core.override\n  Common createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Common getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Common>(create);\n  static Common? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get method => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set method($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasMethod() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearMethod() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get msgId => $_getI64(1);\n  @$pb.TagNumber(2)\n  set msgId($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasMsgId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearMsgId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get roomId => $_getI64(2);\n  @$pb.TagNumber(3)\n  set roomId($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasRoomId() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearRoomId() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get createTime => $_getI64(3);\n  @$pb.TagNumber(4)\n  set createTime($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasCreateTime() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearCreateTime() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.int get monitor => $_getIZ(4);\n  @$pb.TagNumber(5)\n  set monitor($core.int value) => $_setUnsignedInt32(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasMonitor() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearMonitor() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.bool get isShowMsg => $_getBF(5);\n  @$pb.TagNumber(6)\n  set isShowMsg($core.bool value) => $_setBool(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasIsShowMsg() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearIsShowMsg() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get describe => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set describe($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasDescribe() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearDescribe() => $_clearField(7);\n\n  /// DisplayText displayText = 8;\n  @$pb.TagNumber(9)\n  $fixnum.Int64 get foldType => $_getI64(7);\n  @$pb.TagNumber(9)\n  set foldType($fixnum.Int64 value) => $_setInt64(7, value);\n  @$pb.TagNumber(9)\n  $core.bool hasFoldType() => $_has(7);\n  @$pb.TagNumber(9)\n  void clearFoldType() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  $fixnum.Int64 get anchorFoldType => $_getI64(8);\n  @$pb.TagNumber(10)\n  set anchorFoldType($fixnum.Int64 value) => $_setInt64(8, value);\n  @$pb.TagNumber(10)\n  $core.bool hasAnchorFoldType() => $_has(8);\n  @$pb.TagNumber(10)\n  void clearAnchorFoldType() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $fixnum.Int64 get priorityScore => $_getI64(9);\n  @$pb.TagNumber(11)\n  set priorityScore($fixnum.Int64 value) => $_setInt64(9, value);\n  @$pb.TagNumber(11)\n  $core.bool hasPriorityScore() => $_has(9);\n  @$pb.TagNumber(11)\n  void clearPriorityScore() => $_clearField(11);\n\n  @$pb.TagNumber(12)\n  $core.String get logId => $_getSZ(10);\n  @$pb.TagNumber(12)\n  set logId($core.String value) => $_setString(10, value);\n  @$pb.TagNumber(12)\n  $core.bool hasLogId() => $_has(10);\n  @$pb.TagNumber(12)\n  void clearLogId() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $core.String get msgProcessFilterK => $_getSZ(11);\n  @$pb.TagNumber(13)\n  set msgProcessFilterK($core.String value) => $_setString(11, value);\n  @$pb.TagNumber(13)\n  $core.bool hasMsgProcessFilterK() => $_has(11);\n  @$pb.TagNumber(13)\n  void clearMsgProcessFilterK() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  $core.String get msgProcessFilterV => $_getSZ(12);\n  @$pb.TagNumber(14)\n  set msgProcessFilterV($core.String value) => $_setString(12, value);\n  @$pb.TagNumber(14)\n  $core.bool hasMsgProcessFilterV() => $_has(12);\n  @$pb.TagNumber(14)\n  void clearMsgProcessFilterV() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  User get user => $_getN(13);\n  @$pb.TagNumber(15)\n  set user(User value) => $_setField(15, value);\n  @$pb.TagNumber(15)\n  $core.bool hasUser() => $_has(13);\n  @$pb.TagNumber(15)\n  void clearUser() => $_clearField(15);\n  @$pb.TagNumber(15)\n  User ensureUser() => $_ensure(13);\n\n  /// Room room = 16;\n  @$pb.TagNumber(17)\n  $fixnum.Int64 get anchorFoldTypeV2 => $_getI64(14);\n  @$pb.TagNumber(17)\n  set anchorFoldTypeV2($fixnum.Int64 value) => $_setInt64(14, value);\n  @$pb.TagNumber(17)\n  $core.bool hasAnchorFoldTypeV2() => $_has(14);\n  @$pb.TagNumber(17)\n  void clearAnchorFoldTypeV2() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $fixnum.Int64 get processAtSeiTimeMs => $_getI64(15);\n  @$pb.TagNumber(18)\n  set processAtSeiTimeMs($fixnum.Int64 value) => $_setInt64(15, value);\n  @$pb.TagNumber(18)\n  $core.bool hasProcessAtSeiTimeMs() => $_has(15);\n  @$pb.TagNumber(18)\n  void clearProcessAtSeiTimeMs() => $_clearField(18);\n\n  @$pb.TagNumber(19)\n  $fixnum.Int64 get randomDispatchMs => $_getI64(16);\n  @$pb.TagNumber(19)\n  set randomDispatchMs($fixnum.Int64 value) => $_setInt64(16, value);\n  @$pb.TagNumber(19)\n  $core.bool hasRandomDispatchMs() => $_has(16);\n  @$pb.TagNumber(19)\n  void clearRandomDispatchMs() => $_clearField(19);\n\n  @$pb.TagNumber(20)\n  $core.bool get isDispatch => $_getBF(17);\n  @$pb.TagNumber(20)\n  set isDispatch($core.bool value) => $_setBool(17, value);\n  @$pb.TagNumber(20)\n  $core.bool hasIsDispatch() => $_has(17);\n  @$pb.TagNumber(20)\n  void clearIsDispatch() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $fixnum.Int64 get channelId => $_getI64(18);\n  @$pb.TagNumber(21)\n  set channelId($fixnum.Int64 value) => $_setInt64(18, value);\n  @$pb.TagNumber(21)\n  $core.bool hasChannelId() => $_has(18);\n  @$pb.TagNumber(21)\n  void clearChannelId() => $_clearField(21);\n\n  @$pb.TagNumber(22)\n  $fixnum.Int64 get diffSei2absSecond => $_getI64(19);\n  @$pb.TagNumber(22)\n  set diffSei2absSecond($fixnum.Int64 value) => $_setInt64(19, value);\n  @$pb.TagNumber(22)\n  $core.bool hasDiffSei2absSecond() => $_has(19);\n  @$pb.TagNumber(22)\n  void clearDiffSei2absSecond() => $_clearField(22);\n\n  @$pb.TagNumber(23)\n  $fixnum.Int64 get anchorFoldDuration => $_getI64(20);\n  @$pb.TagNumber(23)\n  set anchorFoldDuration($fixnum.Int64 value) => $_setInt64(20, value);\n  @$pb.TagNumber(23)\n  $core.bool hasAnchorFoldDuration() => $_has(20);\n  @$pb.TagNumber(23)\n  void clearAnchorFoldDuration() => $_clearField(23);\n}\n\nclass User extends $pb.GeneratedMessage {\n  factory User({\n    $fixnum.Int64? id,\n    $fixnum.Int64? shortId,\n    $core.String? nickName,\n    $core.int? gender,\n    $core.String? signature,\n    $core.int? level,\n    $fixnum.Int64? birthday,\n    $core.String? telephone,\n    Image? avatarThumb,\n    Image? avatarMedium,\n    Image? avatarLarge,\n    $core.bool? verified,\n    $core.int? experience,\n    $core.String? city,\n    $core.int? status,\n    $fixnum.Int64? createTime,\n    $fixnum.Int64? modifyTime,\n    $core.int? secret,\n    $core.String? shareQrcodeUri,\n    $core.int? incomeSharePercent,\n    $core.Iterable<Image>? badgeImageList,\n    FollowInfo? followInfo,\n    $core.String? specialId,\n    Image? avatarBorder,\n    Image? medal,\n    $core.Iterable<Image>? realTimeIconsList,\n    $core.String? displayId,\n    $core.String? secUid,\n    $fixnum.Int64? fanTicketCount,\n    $core.String? idStr,\n    $core.int? ageRange,\n  }) {\n    final result = create();\n    if (id != null) result.id = id;\n    if (shortId != null) result.shortId = shortId;\n    if (nickName != null) result.nickName = nickName;\n    if (gender != null) result.gender = gender;\n    if (signature != null) result.signature = signature;\n    if (level != null) result.level = level;\n    if (birthday != null) result.birthday = birthday;\n    if (telephone != null) result.telephone = telephone;\n    if (avatarThumb != null) result.avatarThumb = avatarThumb;\n    if (avatarMedium != null) result.avatarMedium = avatarMedium;\n    if (avatarLarge != null) result.avatarLarge = avatarLarge;\n    if (verified != null) result.verified = verified;\n    if (experience != null) result.experience = experience;\n    if (city != null) result.city = city;\n    if (status != null) result.status = status;\n    if (createTime != null) result.createTime = createTime;\n    if (modifyTime != null) result.modifyTime = modifyTime;\n    if (secret != null) result.secret = secret;\n    if (shareQrcodeUri != null) result.shareQrcodeUri = shareQrcodeUri;\n    if (incomeSharePercent != null)\n      result.incomeSharePercent = incomeSharePercent;\n    if (badgeImageList != null) result.badgeImageList.addAll(badgeImageList);\n    if (followInfo != null) result.followInfo = followInfo;\n    if (specialId != null) result.specialId = specialId;\n    if (avatarBorder != null) result.avatarBorder = avatarBorder;\n    if (medal != null) result.medal = medal;\n    if (realTimeIconsList != null)\n      result.realTimeIconsList.addAll(realTimeIconsList);\n    if (displayId != null) result.displayId = displayId;\n    if (secUid != null) result.secUid = secUid;\n    if (fanTicketCount != null) result.fanTicketCount = fanTicketCount;\n    if (idStr != null) result.idStr = idStr;\n    if (ageRange != null) result.ageRange = ageRange;\n    return result;\n  }\n\n  User._();\n\n  factory User.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory User.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'User',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'shortId', $pb.PbFieldType.OU6,\n        protoName: 'shortId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(3, _omitFieldNames ? '' : 'nickName', protoName: 'nickName')\n    ..aI(4, _omitFieldNames ? '' : 'gender', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(5, _omitFieldNames ? '' : 'Signature', protoName: 'Signature')\n    ..aI(6, _omitFieldNames ? '' : 'Level',\n        protoName: 'Level', fieldType: $pb.PbFieldType.OU3)\n    ..a<$fixnum.Int64>(\n        7, _omitFieldNames ? '' : 'Birthday', $pb.PbFieldType.OU6,\n        protoName: 'Birthday', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(8, _omitFieldNames ? '' : 'Telephone', protoName: 'Telephone')\n    ..aOM<Image>(9, _omitFieldNames ? '' : 'AvatarThumb',\n        protoName: 'AvatarThumb', subBuilder: Image.create)\n    ..aOM<Image>(10, _omitFieldNames ? '' : 'AvatarMedium',\n        protoName: 'AvatarMedium', subBuilder: Image.create)\n    ..aOM<Image>(11, _omitFieldNames ? '' : 'AvatarLarge',\n        protoName: 'AvatarLarge', subBuilder: Image.create)\n    ..aOB(12, _omitFieldNames ? '' : 'Verified', protoName: 'Verified')\n    ..aI(13, _omitFieldNames ? '' : 'Experience',\n        protoName: 'Experience', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(14, _omitFieldNames ? '' : 'city')\n    ..aI(15, _omitFieldNames ? '' : 'Status', protoName: 'Status')\n    ..a<$fixnum.Int64>(\n        16, _omitFieldNames ? '' : 'CreateTime', $pb.PbFieldType.OU6,\n        protoName: 'CreateTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        17, _omitFieldNames ? '' : 'ModifyTime', $pb.PbFieldType.OU6,\n        protoName: 'ModifyTime', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aI(18, _omitFieldNames ? '' : 'Secret',\n        protoName: 'Secret', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(19, _omitFieldNames ? '' : 'ShareQrcodeUri',\n        protoName: 'ShareQrcodeUri')\n    ..aI(20, _omitFieldNames ? '' : 'IncomeSharePercent',\n        protoName: 'IncomeSharePercent', fieldType: $pb.PbFieldType.OU3)\n    ..pPM<Image>(21, _omitFieldNames ? '' : 'BadgeImageList',\n        protoName: 'BadgeImageList', subBuilder: Image.create)\n    ..aOM<FollowInfo>(22, _omitFieldNames ? '' : 'FollowInfo',\n        protoName: 'FollowInfo', subBuilder: FollowInfo.create)\n    ..aOS(26, _omitFieldNames ? '' : 'SpecialId', protoName: 'SpecialId')\n    ..aOM<Image>(27, _omitFieldNames ? '' : 'AvatarBorder',\n        protoName: 'AvatarBorder', subBuilder: Image.create)\n    ..aOM<Image>(28, _omitFieldNames ? '' : 'Medal',\n        protoName: 'Medal', subBuilder: Image.create)\n    ..pPM<Image>(29, _omitFieldNames ? '' : 'RealTimeIconsList',\n        protoName: 'RealTimeIconsList', subBuilder: Image.create)\n    ..aOS(38, _omitFieldNames ? '' : 'displayId', protoName: 'displayId')\n    ..aOS(46, _omitFieldNames ? '' : 'secUid', protoName: 'secUid')\n    ..a<$fixnum.Int64>(\n        1022, _omitFieldNames ? '' : 'fanTicketCount', $pb.PbFieldType.OU6,\n        protoName: 'fanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(1028, _omitFieldNames ? '' : 'idStr', protoName: 'idStr')\n    ..aI(1045, _omitFieldNames ? '' : 'ageRange',\n        protoName: 'ageRange', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  User clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  User copyWith(void Function(User) updates) =>\n      super.copyWith((message) => updates(message as User)) as User;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static User create() => User._();\n  @$core.override\n  User createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static User getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<User>(create);\n  static User? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get id => $_getI64(0);\n  @$pb.TagNumber(1)\n  set id($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasId() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearId() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get shortId => $_getI64(1);\n  @$pb.TagNumber(2)\n  set shortId($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasShortId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearShortId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.String get nickName => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set nickName($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasNickName() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearNickName() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.int get gender => $_getIZ(3);\n  @$pb.TagNumber(4)\n  set gender($core.int value) => $_setUnsignedInt32(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasGender() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearGender() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.String get signature => $_getSZ(4);\n  @$pb.TagNumber(5)\n  set signature($core.String value) => $_setString(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasSignature() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearSignature() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get level => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set level($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasLevel() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearLevel() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $fixnum.Int64 get birthday => $_getI64(6);\n  @$pb.TagNumber(7)\n  set birthday($fixnum.Int64 value) => $_setInt64(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasBirthday() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearBirthday() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.String get telephone => $_getSZ(7);\n  @$pb.TagNumber(8)\n  set telephone($core.String value) => $_setString(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasTelephone() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearTelephone() => $_clearField(8);\n\n  @$pb.TagNumber(9)\n  Image get avatarThumb => $_getN(8);\n  @$pb.TagNumber(9)\n  set avatarThumb(Image value) => $_setField(9, value);\n  @$pb.TagNumber(9)\n  $core.bool hasAvatarThumb() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearAvatarThumb() => $_clearField(9);\n  @$pb.TagNumber(9)\n  Image ensureAvatarThumb() => $_ensure(8);\n\n  @$pb.TagNumber(10)\n  Image get avatarMedium => $_getN(9);\n  @$pb.TagNumber(10)\n  set avatarMedium(Image value) => $_setField(10, value);\n  @$pb.TagNumber(10)\n  $core.bool hasAvatarMedium() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearAvatarMedium() => $_clearField(10);\n  @$pb.TagNumber(10)\n  Image ensureAvatarMedium() => $_ensure(9);\n\n  @$pb.TagNumber(11)\n  Image get avatarLarge => $_getN(10);\n  @$pb.TagNumber(11)\n  set avatarLarge(Image value) => $_setField(11, value);\n  @$pb.TagNumber(11)\n  $core.bool hasAvatarLarge() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearAvatarLarge() => $_clearField(11);\n  @$pb.TagNumber(11)\n  Image ensureAvatarLarge() => $_ensure(10);\n\n  @$pb.TagNumber(12)\n  $core.bool get verified => $_getBF(11);\n  @$pb.TagNumber(12)\n  set verified($core.bool value) => $_setBool(11, value);\n  @$pb.TagNumber(12)\n  $core.bool hasVerified() => $_has(11);\n  @$pb.TagNumber(12)\n  void clearVerified() => $_clearField(12);\n\n  @$pb.TagNumber(13)\n  $core.int get experience => $_getIZ(12);\n  @$pb.TagNumber(13)\n  set experience($core.int value) => $_setUnsignedInt32(12, value);\n  @$pb.TagNumber(13)\n  $core.bool hasExperience() => $_has(12);\n  @$pb.TagNumber(13)\n  void clearExperience() => $_clearField(13);\n\n  @$pb.TagNumber(14)\n  $core.String get city => $_getSZ(13);\n  @$pb.TagNumber(14)\n  set city($core.String value) => $_setString(13, value);\n  @$pb.TagNumber(14)\n  $core.bool hasCity() => $_has(13);\n  @$pb.TagNumber(14)\n  void clearCity() => $_clearField(14);\n\n  @$pb.TagNumber(15)\n  $core.int get status => $_getIZ(14);\n  @$pb.TagNumber(15)\n  set status($core.int value) => $_setSignedInt32(14, value);\n  @$pb.TagNumber(15)\n  $core.bool hasStatus() => $_has(14);\n  @$pb.TagNumber(15)\n  void clearStatus() => $_clearField(15);\n\n  @$pb.TagNumber(16)\n  $fixnum.Int64 get createTime => $_getI64(15);\n  @$pb.TagNumber(16)\n  set createTime($fixnum.Int64 value) => $_setInt64(15, value);\n  @$pb.TagNumber(16)\n  $core.bool hasCreateTime() => $_has(15);\n  @$pb.TagNumber(16)\n  void clearCreateTime() => $_clearField(16);\n\n  @$pb.TagNumber(17)\n  $fixnum.Int64 get modifyTime => $_getI64(16);\n  @$pb.TagNumber(17)\n  set modifyTime($fixnum.Int64 value) => $_setInt64(16, value);\n  @$pb.TagNumber(17)\n  $core.bool hasModifyTime() => $_has(16);\n  @$pb.TagNumber(17)\n  void clearModifyTime() => $_clearField(17);\n\n  @$pb.TagNumber(18)\n  $core.int get secret => $_getIZ(17);\n  @$pb.TagNumber(18)\n  set secret($core.int value) => $_setUnsignedInt32(17, value);\n  @$pb.TagNumber(18)\n  $core.bool hasSecret() => $_has(17);\n  @$pb.TagNumber(18)\n  void clearSecret() => $_clearField(18);\n\n  @$pb.TagNumber(19)\n  $core.String get shareQrcodeUri => $_getSZ(18);\n  @$pb.TagNumber(19)\n  set shareQrcodeUri($core.String value) => $_setString(18, value);\n  @$pb.TagNumber(19)\n  $core.bool hasShareQrcodeUri() => $_has(18);\n  @$pb.TagNumber(19)\n  void clearShareQrcodeUri() => $_clearField(19);\n\n  @$pb.TagNumber(20)\n  $core.int get incomeSharePercent => $_getIZ(19);\n  @$pb.TagNumber(20)\n  set incomeSharePercent($core.int value) => $_setUnsignedInt32(19, value);\n  @$pb.TagNumber(20)\n  $core.bool hasIncomeSharePercent() => $_has(19);\n  @$pb.TagNumber(20)\n  void clearIncomeSharePercent() => $_clearField(20);\n\n  @$pb.TagNumber(21)\n  $pb.PbList<Image> get badgeImageList => $_getList(20);\n\n  @$pb.TagNumber(22)\n  FollowInfo get followInfo => $_getN(21);\n  @$pb.TagNumber(22)\n  set followInfo(FollowInfo value) => $_setField(22, value);\n  @$pb.TagNumber(22)\n  $core.bool hasFollowInfo() => $_has(21);\n  @$pb.TagNumber(22)\n  void clearFollowInfo() => $_clearField(22);\n  @$pb.TagNumber(22)\n  FollowInfo ensureFollowInfo() => $_ensure(21);\n\n  /// PayGrade PayGrade = 23;\n  /// FansClub FansClub = 24;\n  /// Border Border = 25;\n  @$pb.TagNumber(26)\n  $core.String get specialId => $_getSZ(22);\n  @$pb.TagNumber(26)\n  set specialId($core.String value) => $_setString(22, value);\n  @$pb.TagNumber(26)\n  $core.bool hasSpecialId() => $_has(22);\n  @$pb.TagNumber(26)\n  void clearSpecialId() => $_clearField(26);\n\n  @$pb.TagNumber(27)\n  Image get avatarBorder => $_getN(23);\n  @$pb.TagNumber(27)\n  set avatarBorder(Image value) => $_setField(27, value);\n  @$pb.TagNumber(27)\n  $core.bool hasAvatarBorder() => $_has(23);\n  @$pb.TagNumber(27)\n  void clearAvatarBorder() => $_clearField(27);\n  @$pb.TagNumber(27)\n  Image ensureAvatarBorder() => $_ensure(23);\n\n  @$pb.TagNumber(28)\n  Image get medal => $_getN(24);\n  @$pb.TagNumber(28)\n  set medal(Image value) => $_setField(28, value);\n  @$pb.TagNumber(28)\n  $core.bool hasMedal() => $_has(24);\n  @$pb.TagNumber(28)\n  void clearMedal() => $_clearField(28);\n  @$pb.TagNumber(28)\n  Image ensureMedal() => $_ensure(24);\n\n  @$pb.TagNumber(29)\n  $pb.PbList<Image> get realTimeIconsList => $_getList(25);\n\n  @$pb.TagNumber(38)\n  $core.String get displayId => $_getSZ(26);\n  @$pb.TagNumber(38)\n  set displayId($core.String value) => $_setString(26, value);\n  @$pb.TagNumber(38)\n  $core.bool hasDisplayId() => $_has(26);\n  @$pb.TagNumber(38)\n  void clearDisplayId() => $_clearField(38);\n\n  @$pb.TagNumber(46)\n  $core.String get secUid => $_getSZ(27);\n  @$pb.TagNumber(46)\n  set secUid($core.String value) => $_setString(27, value);\n  @$pb.TagNumber(46)\n  $core.bool hasSecUid() => $_has(27);\n  @$pb.TagNumber(46)\n  void clearSecUid() => $_clearField(46);\n\n  @$pb.TagNumber(1022)\n  $fixnum.Int64 get fanTicketCount => $_getI64(28);\n  @$pb.TagNumber(1022)\n  set fanTicketCount($fixnum.Int64 value) => $_setInt64(28, value);\n  @$pb.TagNumber(1022)\n  $core.bool hasFanTicketCount() => $_has(28);\n  @$pb.TagNumber(1022)\n  void clearFanTicketCount() => $_clearField(1022);\n\n  @$pb.TagNumber(1028)\n  $core.String get idStr => $_getSZ(29);\n  @$pb.TagNumber(1028)\n  set idStr($core.String value) => $_setString(29, value);\n  @$pb.TagNumber(1028)\n  $core.bool hasIdStr() => $_has(29);\n  @$pb.TagNumber(1028)\n  void clearIdStr() => $_clearField(1028);\n\n  @$pb.TagNumber(1045)\n  $core.int get ageRange => $_getIZ(30);\n  @$pb.TagNumber(1045)\n  set ageRange($core.int value) => $_setUnsignedInt32(30, value);\n  @$pb.TagNumber(1045)\n  $core.bool hasAgeRange() => $_has(30);\n  @$pb.TagNumber(1045)\n  void clearAgeRange() => $_clearField(1045);\n}\n\nclass FollowInfo extends $pb.GeneratedMessage {\n  factory FollowInfo({\n    $fixnum.Int64? followingCount,\n    $fixnum.Int64? followerCount,\n    $fixnum.Int64? followStatus,\n    $fixnum.Int64? pushStatus,\n    $core.String? remarkName,\n    $core.String? followerCountStr,\n    $core.String? followingCountStr,\n  }) {\n    final result = create();\n    if (followingCount != null) result.followingCount = followingCount;\n    if (followerCount != null) result.followerCount = followerCount;\n    if (followStatus != null) result.followStatus = followStatus;\n    if (pushStatus != null) result.pushStatus = pushStatus;\n    if (remarkName != null) result.remarkName = remarkName;\n    if (followerCountStr != null) result.followerCountStr = followerCountStr;\n    if (followingCountStr != null) result.followingCountStr = followingCountStr;\n    return result;\n  }\n\n  FollowInfo._();\n\n  factory FollowInfo.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory FollowInfo.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'FollowInfo',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(\n        1, _omitFieldNames ? '' : 'followingCount', $pb.PbFieldType.OU6,\n        protoName: 'followingCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        2, _omitFieldNames ? '' : 'followerCount', $pb.PbFieldType.OU6,\n        protoName: 'followerCount', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'followStatus', $pb.PbFieldType.OU6,\n        protoName: 'followStatus', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(\n        4, _omitFieldNames ? '' : 'pushStatus', $pb.PbFieldType.OU6,\n        protoName: 'pushStatus', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(5, _omitFieldNames ? '' : 'remarkName', protoName: 'remarkName')\n    ..aOS(6, _omitFieldNames ? '' : 'followerCountStr',\n        protoName: 'followerCountStr')\n    ..aOS(7, _omitFieldNames ? '' : 'followingCountStr',\n        protoName: 'followingCountStr')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  FollowInfo clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  FollowInfo copyWith(void Function(FollowInfo) updates) =>\n      super.copyWith((message) => updates(message as FollowInfo)) as FollowInfo;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static FollowInfo create() => FollowInfo._();\n  @$core.override\n  FollowInfo createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static FollowInfo getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<FollowInfo>(create);\n  static FollowInfo? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get followingCount => $_getI64(0);\n  @$pb.TagNumber(1)\n  set followingCount($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasFollowingCount() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearFollowingCount() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get followerCount => $_getI64(1);\n  @$pb.TagNumber(2)\n  set followerCount($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasFollowerCount() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearFollowerCount() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get followStatus => $_getI64(2);\n  @$pb.TagNumber(3)\n  set followStatus($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasFollowStatus() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearFollowStatus() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get pushStatus => $_getI64(3);\n  @$pb.TagNumber(4)\n  set pushStatus($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasPushStatus() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearPushStatus() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.String get remarkName => $_getSZ(4);\n  @$pb.TagNumber(5)\n  set remarkName($core.String value) => $_setString(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasRemarkName() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearRemarkName() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.String get followerCountStr => $_getSZ(5);\n  @$pb.TagNumber(6)\n  set followerCountStr($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasFollowerCountStr() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearFollowerCountStr() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get followingCountStr => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set followingCountStr($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasFollowingCountStr() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearFollowingCountStr() => $_clearField(7);\n}\n\nclass Image extends $pb.GeneratedMessage {\n  factory Image({\n    $core.Iterable<$core.String>? urlListList,\n    $core.String? uri,\n    $fixnum.Int64? height,\n    $fixnum.Int64? width,\n    $core.String? avgColor,\n    $core.int? imageType,\n    $core.String? openWebUrl,\n    ImageContent? content,\n    $core.bool? isAnimated,\n    NinePatchSetting? flexSettingList,\n    NinePatchSetting? textSettingList,\n  }) {\n    final result = create();\n    if (urlListList != null) result.urlListList.addAll(urlListList);\n    if (uri != null) result.uri = uri;\n    if (height != null) result.height = height;\n    if (width != null) result.width = width;\n    if (avgColor != null) result.avgColor = avgColor;\n    if (imageType != null) result.imageType = imageType;\n    if (openWebUrl != null) result.openWebUrl = openWebUrl;\n    if (content != null) result.content = content;\n    if (isAnimated != null) result.isAnimated = isAnimated;\n    if (flexSettingList != null) result.flexSettingList = flexSettingList;\n    if (textSettingList != null) result.textSettingList = textSettingList;\n    return result;\n  }\n\n  Image._();\n\n  factory Image.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Image.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Image',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..pPS(1, _omitFieldNames ? '' : 'urlListList', protoName: 'urlListList')\n    ..aOS(2, _omitFieldNames ? '' : 'uri')\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'height', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'width', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(5, _omitFieldNames ? '' : 'avgColor', protoName: 'avgColor')\n    ..aI(6, _omitFieldNames ? '' : 'imageType',\n        protoName: 'imageType', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(7, _omitFieldNames ? '' : 'openWebUrl', protoName: 'openWebUrl')\n    ..aOM<ImageContent>(8, _omitFieldNames ? '' : 'content',\n        subBuilder: ImageContent.create)\n    ..aOB(9, _omitFieldNames ? '' : 'isAnimated', protoName: 'isAnimated')\n    ..aOM<NinePatchSetting>(10, _omitFieldNames ? '' : 'FlexSettingList',\n        protoName: 'FlexSettingList', subBuilder: NinePatchSetting.create)\n    ..aOM<NinePatchSetting>(11, _omitFieldNames ? '' : 'TextSettingList',\n        protoName: 'TextSettingList', subBuilder: NinePatchSetting.create)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Image clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Image copyWith(void Function(Image) updates) =>\n      super.copyWith((message) => updates(message as Image)) as Image;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Image create() => Image._();\n  @$core.override\n  Image createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Image getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Image>(create);\n  static Image? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $pb.PbList<$core.String> get urlListList => $_getList(0);\n\n  @$pb.TagNumber(2)\n  $core.String get uri => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set uri($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasUri() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearUri() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get height => $_getI64(2);\n  @$pb.TagNumber(3)\n  set height($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasHeight() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearHeight() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get width => $_getI64(3);\n  @$pb.TagNumber(4)\n  set width($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasWidth() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearWidth() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.String get avgColor => $_getSZ(4);\n  @$pb.TagNumber(5)\n  set avgColor($core.String value) => $_setString(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasAvgColor() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearAvgColor() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get imageType => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set imageType($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasImageType() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearImageType() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get openWebUrl => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set openWebUrl($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasOpenWebUrl() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearOpenWebUrl() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  ImageContent get content => $_getN(7);\n  @$pb.TagNumber(8)\n  set content(ImageContent value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasContent() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearContent() => $_clearField(8);\n  @$pb.TagNumber(8)\n  ImageContent ensureContent() => $_ensure(7);\n\n  @$pb.TagNumber(9)\n  $core.bool get isAnimated => $_getBF(8);\n  @$pb.TagNumber(9)\n  set isAnimated($core.bool value) => $_setBool(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasIsAnimated() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearIsAnimated() => $_clearField(9);\n\n  @$pb.TagNumber(10)\n  NinePatchSetting get flexSettingList => $_getN(9);\n  @$pb.TagNumber(10)\n  set flexSettingList(NinePatchSetting value) => $_setField(10, value);\n  @$pb.TagNumber(10)\n  $core.bool hasFlexSettingList() => $_has(9);\n  @$pb.TagNumber(10)\n  void clearFlexSettingList() => $_clearField(10);\n  @$pb.TagNumber(10)\n  NinePatchSetting ensureFlexSettingList() => $_ensure(9);\n\n  @$pb.TagNumber(11)\n  NinePatchSetting get textSettingList => $_getN(10);\n  @$pb.TagNumber(11)\n  set textSettingList(NinePatchSetting value) => $_setField(11, value);\n  @$pb.TagNumber(11)\n  $core.bool hasTextSettingList() => $_has(10);\n  @$pb.TagNumber(11)\n  void clearTextSettingList() => $_clearField(11);\n  @$pb.TagNumber(11)\n  NinePatchSetting ensureTextSettingList() => $_ensure(10);\n}\n\nclass NinePatchSetting extends $pb.GeneratedMessage {\n  factory NinePatchSetting({\n    $core.Iterable<$core.String>? settingListList,\n  }) {\n    final result = create();\n    if (settingListList != null) result.settingListList.addAll(settingListList);\n    return result;\n  }\n\n  NinePatchSetting._();\n\n  factory NinePatchSetting.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory NinePatchSetting.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'NinePatchSetting',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..pPS(1, _omitFieldNames ? '' : 'settingListList',\n        protoName: 'settingListList')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  NinePatchSetting clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  NinePatchSetting copyWith(void Function(NinePatchSetting) updates) =>\n      super.copyWith((message) => updates(message as NinePatchSetting))\n          as NinePatchSetting;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static NinePatchSetting create() => NinePatchSetting._();\n  @$core.override\n  NinePatchSetting createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static NinePatchSetting getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<NinePatchSetting>(create);\n  static NinePatchSetting? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $pb.PbList<$core.String> get settingListList => $_getList(0);\n}\n\nclass ImageContent extends $pb.GeneratedMessage {\n  factory ImageContent({\n    $core.String? name,\n    $core.String? fontColor,\n    $fixnum.Int64? level,\n    $core.String? alternativeText,\n  }) {\n    final result = create();\n    if (name != null) result.name = name;\n    if (fontColor != null) result.fontColor = fontColor;\n    if (level != null) result.level = level;\n    if (alternativeText != null) result.alternativeText = alternativeText;\n    return result;\n  }\n\n  ImageContent._();\n\n  factory ImageContent.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory ImageContent.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'ImageContent',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'name')\n    ..aOS(2, _omitFieldNames ? '' : 'fontColor', protoName: 'fontColor')\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'level', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(4, _omitFieldNames ? '' : 'alternativeText',\n        protoName: 'alternativeText')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ImageContent clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ImageContent copyWith(void Function(ImageContent) updates) =>\n      super.copyWith((message) => updates(message as ImageContent))\n          as ImageContent;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static ImageContent create() => ImageContent._();\n  @$core.override\n  ImageContent createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static ImageContent getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<ImageContent>(create);\n  static ImageContent? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get name => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set name($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasName() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearName() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get fontColor => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set fontColor($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasFontColor() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearFontColor() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get level => $_getI64(2);\n  @$pb.TagNumber(3)\n  set level($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasLevel() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearLevel() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get alternativeText => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set alternativeText($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasAlternativeText() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearAlternativeText() => $_clearField(4);\n}\n\nclass PushFrame extends $pb.GeneratedMessage {\n  factory PushFrame({\n    $fixnum.Int64? seqId,\n    $fixnum.Int64? logId,\n    $fixnum.Int64? service,\n    $fixnum.Int64? method,\n    $core.Iterable<HeadersList>? headersList,\n    $core.String? payloadEncoding,\n    $core.String? payloadType,\n    $core.List<$core.int>? payload,\n  }) {\n    final result = create();\n    if (seqId != null) result.seqId = seqId;\n    if (logId != null) result.logId = logId;\n    if (service != null) result.service = service;\n    if (method != null) result.method = method;\n    if (headersList != null) result.headersList.addAll(headersList);\n    if (payloadEncoding != null) result.payloadEncoding = payloadEncoding;\n    if (payloadType != null) result.payloadType = payloadType;\n    if (payload != null) result.payload = payload;\n    return result;\n  }\n\n  PushFrame._();\n\n  factory PushFrame.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory PushFrame.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'PushFrame',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'seqId', $pb.PbFieldType.OU6,\n        protoName: 'seqId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'logId', $pb.PbFieldType.OU6,\n        protoName: 'logId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'service', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'method', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..pPM<HeadersList>(5, _omitFieldNames ? '' : 'headersList',\n        protoName: 'headersList', subBuilder: HeadersList.create)\n    ..aOS(6, _omitFieldNames ? '' : 'payloadEncoding',\n        protoName: 'payloadEncoding')\n    ..aOS(7, _omitFieldNames ? '' : 'payloadType', protoName: 'payloadType')\n    ..a<$core.List<$core.int>>(\n        8, _omitFieldNames ? '' : 'payload', $pb.PbFieldType.OY)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PushFrame clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PushFrame copyWith(void Function(PushFrame) updates) =>\n      super.copyWith((message) => updates(message as PushFrame)) as PushFrame;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static PushFrame create() => PushFrame._();\n  @$core.override\n  PushFrame createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static PushFrame getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<PushFrame>(create);\n  static PushFrame? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get seqId => $_getI64(0);\n  @$pb.TagNumber(1)\n  set seqId($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasSeqId() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearSeqId() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $fixnum.Int64 get logId => $_getI64(1);\n  @$pb.TagNumber(2)\n  set logId($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasLogId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearLogId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get service => $_getI64(2);\n  @$pb.TagNumber(3)\n  set service($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasService() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearService() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $fixnum.Int64 get method => $_getI64(3);\n  @$pb.TagNumber(4)\n  set method($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasMethod() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearMethod() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $pb.PbList<HeadersList> get headersList => $_getList(4);\n\n  @$pb.TagNumber(6)\n  $core.String get payloadEncoding => $_getSZ(5);\n  @$pb.TagNumber(6)\n  set payloadEncoding($core.String value) => $_setString(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasPayloadEncoding() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearPayloadEncoding() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get payloadType => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set payloadType($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasPayloadType() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearPayloadType() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.List<$core.int> get payload => $_getN(7);\n  @$pb.TagNumber(8)\n  set payload($core.List<$core.int> value) => $_setBytes(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasPayload() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearPayload() => $_clearField(8);\n}\n\nclass kk extends $pb.GeneratedMessage {\n  factory kk({\n    $core.int? k,\n  }) {\n    final result = create();\n    if (k != null) result.k = k;\n    return result;\n  }\n\n  kk._();\n\n  factory kk.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory kk.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'kk',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aI(14, _omitFieldNames ? '' : 'k', fieldType: $pb.PbFieldType.OU3)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  kk clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  kk copyWith(void Function(kk) updates) =>\n      super.copyWith((message) => updates(message as kk)) as kk;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static kk create() => kk._();\n  @$core.override\n  kk createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static kk getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<kk>(create);\n  static kk? _defaultInstance;\n\n  @$pb.TagNumber(14)\n  $core.int get k => $_getIZ(0);\n  @$pb.TagNumber(14)\n  set k($core.int value) => $_setUnsignedInt32(0, value);\n  @$pb.TagNumber(14)\n  $core.bool hasK() => $_has(0);\n  @$pb.TagNumber(14)\n  void clearK() => $_clearField(14);\n}\n\nclass SendMessageBody extends $pb.GeneratedMessage {\n  factory SendMessageBody({\n    $core.String? conversationId,\n    $core.int? conversationType,\n    $fixnum.Int64? conversationShortId,\n    $core.String? content,\n    $core.Iterable<ExtList>? ext,\n    $core.int? messageType,\n    $core.String? ticket,\n    $core.String? clientMessageId,\n  }) {\n    final result = create();\n    if (conversationId != null) result.conversationId = conversationId;\n    if (conversationType != null) result.conversationType = conversationType;\n    if (conversationShortId != null)\n      result.conversationShortId = conversationShortId;\n    if (content != null) result.content = content;\n    if (ext != null) result.ext.addAll(ext);\n    if (messageType != null) result.messageType = messageType;\n    if (ticket != null) result.ticket = ticket;\n    if (clientMessageId != null) result.clientMessageId = clientMessageId;\n    return result;\n  }\n\n  SendMessageBody._();\n\n  factory SendMessageBody.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory SendMessageBody.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'SendMessageBody',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'conversationId',\n        protoName: 'conversationId')\n    ..aI(2, _omitFieldNames ? '' : 'conversationType',\n        protoName: 'conversationType', fieldType: $pb.PbFieldType.OU3)\n    ..a<$fixnum.Int64>(\n        3, _omitFieldNames ? '' : 'conversationShortId', $pb.PbFieldType.OU6,\n        protoName: 'conversationShortId', defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(4, _omitFieldNames ? '' : 'content')\n    ..pPM<ExtList>(5, _omitFieldNames ? '' : 'ext', subBuilder: ExtList.create)\n    ..aI(6, _omitFieldNames ? '' : 'messageType',\n        protoName: 'messageType', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(7, _omitFieldNames ? '' : 'ticket')\n    ..aOS(8, _omitFieldNames ? '' : 'clientMessageId',\n        protoName: 'clientMessageId')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  SendMessageBody clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  SendMessageBody copyWith(void Function(SendMessageBody) updates) =>\n      super.copyWith((message) => updates(message as SendMessageBody))\n          as SendMessageBody;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static SendMessageBody create() => SendMessageBody._();\n  @$core.override\n  SendMessageBody createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static SendMessageBody getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<SendMessageBody>(create);\n  static SendMessageBody? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get conversationId => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set conversationId($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasConversationId() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearConversationId() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.int get conversationType => $_getIZ(1);\n  @$pb.TagNumber(2)\n  set conversationType($core.int value) => $_setUnsignedInt32(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasConversationType() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearConversationType() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get conversationShortId => $_getI64(2);\n  @$pb.TagNumber(3)\n  set conversationShortId($fixnum.Int64 value) => $_setInt64(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasConversationShortId() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearConversationShortId() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get content => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set content($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasContent() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearContent() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $pb.PbList<ExtList> get ext => $_getList(4);\n\n  @$pb.TagNumber(6)\n  $core.int get messageType => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set messageType($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasMessageType() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearMessageType() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get ticket => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set ticket($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasTicket() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearTicket() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  $core.String get clientMessageId => $_getSZ(7);\n  @$pb.TagNumber(8)\n  set clientMessageId($core.String value) => $_setString(7, value);\n  @$pb.TagNumber(8)\n  $core.bool hasClientMessageId() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearClientMessageId() => $_clearField(8);\n}\n\nclass ExtList extends $pb.GeneratedMessage {\n  factory ExtList({\n    $core.String? key,\n    $core.String? value,\n  }) {\n    final result = create();\n    if (key != null) result.key = key;\n    if (value != null) result.value = value;\n    return result;\n  }\n\n  ExtList._();\n\n  factory ExtList.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory ExtList.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'ExtList',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'key')\n    ..aOS(2, _omitFieldNames ? '' : 'value')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ExtList clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  ExtList copyWith(void Function(ExtList) updates) =>\n      super.copyWith((message) => updates(message as ExtList)) as ExtList;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static ExtList create() => ExtList._();\n  @$core.override\n  ExtList createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static ExtList getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ExtList>(create);\n  static ExtList? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get key => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set key($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasKey() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearKey() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get value => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set value($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasValue() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearValue() => $_clearField(2);\n}\n\nclass Rsp_F extends $pb.GeneratedMessage {\n  factory Rsp_F({\n    $fixnum.Int64? q1,\n    $fixnum.Int64? q3,\n    $core.String? q4,\n    $fixnum.Int64? q5,\n  }) {\n    final result = create();\n    if (q1 != null) result.q1 = q1;\n    if (q3 != null) result.q3 = q3;\n    if (q4 != null) result.q4 = q4;\n    if (q5 != null) result.q5 = q5;\n    return result;\n  }\n\n  Rsp_F._();\n\n  factory Rsp_F.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Rsp_F.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Rsp.F',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'q1', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'q3', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..aOS(4, _omitFieldNames ? '' : 'q4')\n    ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'q5', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Rsp_F clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Rsp_F copyWith(void Function(Rsp_F) updates) =>\n      super.copyWith((message) => updates(message as Rsp_F)) as Rsp_F;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Rsp_F create() => Rsp_F._();\n  @$core.override\n  Rsp_F createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Rsp_F getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Rsp_F>(create);\n  static Rsp_F? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $fixnum.Int64 get q1 => $_getI64(0);\n  @$pb.TagNumber(1)\n  set q1($fixnum.Int64 value) => $_setInt64(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasQ1() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearQ1() => $_clearField(1);\n\n  @$pb.TagNumber(3)\n  $fixnum.Int64 get q3 => $_getI64(1);\n  @$pb.TagNumber(3)\n  set q3($fixnum.Int64 value) => $_setInt64(1, value);\n  @$pb.TagNumber(3)\n  $core.bool hasQ3() => $_has(1);\n  @$pb.TagNumber(3)\n  void clearQ3() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get q4 => $_getSZ(2);\n  @$pb.TagNumber(4)\n  set q4($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(4)\n  $core.bool hasQ4() => $_has(2);\n  @$pb.TagNumber(4)\n  void clearQ4() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $fixnum.Int64 get q5 => $_getI64(3);\n  @$pb.TagNumber(5)\n  set q5($fixnum.Int64 value) => $_setInt64(3, value);\n  @$pb.TagNumber(5)\n  $core.bool hasQ5() => $_has(3);\n  @$pb.TagNumber(5)\n  void clearQ5() => $_clearField(5);\n}\n\nclass Rsp extends $pb.GeneratedMessage {\n  factory Rsp({\n    $core.int? a,\n    $core.int? b,\n    $core.int? c,\n    $core.String? d,\n    $core.int? e,\n    Rsp_F? f,\n    $core.String? g,\n    $fixnum.Int64? h,\n    $fixnum.Int64? i,\n    $fixnum.Int64? j,\n  }) {\n    final result = create();\n    if (a != null) result.a = a;\n    if (b != null) result.b = b;\n    if (c != null) result.c = c;\n    if (d != null) result.d = d;\n    if (e != null) result.e = e;\n    if (f != null) result.f = f;\n    if (g != null) result.g = g;\n    if (h != null) result.h = h;\n    if (i != null) result.i = i;\n    if (j != null) result.j = j;\n    return result;\n  }\n\n  Rsp._();\n\n  factory Rsp.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory Rsp.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'Rsp',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aI(1, _omitFieldNames ? '' : 'a')\n    ..aI(2, _omitFieldNames ? '' : 'b')\n    ..aI(3, _omitFieldNames ? '' : 'c')\n    ..aOS(4, _omitFieldNames ? '' : 'd')\n    ..aI(5, _omitFieldNames ? '' : 'e')\n    ..aOM<Rsp_F>(6, _omitFieldNames ? '' : 'f', subBuilder: Rsp_F.create)\n    ..aOS(7, _omitFieldNames ? '' : 'g')\n    ..a<$fixnum.Int64>(10, _omitFieldNames ? '' : 'h', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'i', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..a<$fixnum.Int64>(13, _omitFieldNames ? '' : 'j', $pb.PbFieldType.OU6,\n        defaultOrMaker: $fixnum.Int64.ZERO)\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Rsp clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  Rsp copyWith(void Function(Rsp) updates) =>\n      super.copyWith((message) => updates(message as Rsp)) as Rsp;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static Rsp create() => Rsp._();\n  @$core.override\n  Rsp createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static Rsp getDefault() =>\n      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Rsp>(create);\n  static Rsp? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.int get a => $_getIZ(0);\n  @$pb.TagNumber(1)\n  set a($core.int value) => $_setSignedInt32(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasA() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearA() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.int get b => $_getIZ(1);\n  @$pb.TagNumber(2)\n  set b($core.int value) => $_setSignedInt32(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasB() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearB() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.int get c => $_getIZ(2);\n  @$pb.TagNumber(3)\n  set c($core.int value) => $_setSignedInt32(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasC() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearC() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get d => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set d($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasD() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearD() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.int get e => $_getIZ(4);\n  @$pb.TagNumber(5)\n  set e($core.int value) => $_setSignedInt32(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasE() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearE() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  Rsp_F get f => $_getN(5);\n  @$pb.TagNumber(6)\n  set f(Rsp_F value) => $_setField(6, value);\n  @$pb.TagNumber(6)\n  $core.bool hasF() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearF() => $_clearField(6);\n  @$pb.TagNumber(6)\n  Rsp_F ensureF() => $_ensure(5);\n\n  @$pb.TagNumber(7)\n  $core.String get g => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set g($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasG() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearG() => $_clearField(7);\n\n  @$pb.TagNumber(10)\n  $fixnum.Int64 get h => $_getI64(7);\n  @$pb.TagNumber(10)\n  set h($fixnum.Int64 value) => $_setInt64(7, value);\n  @$pb.TagNumber(10)\n  $core.bool hasH() => $_has(7);\n  @$pb.TagNumber(10)\n  void clearH() => $_clearField(10);\n\n  @$pb.TagNumber(11)\n  $fixnum.Int64 get i => $_getI64(8);\n  @$pb.TagNumber(11)\n  set i($fixnum.Int64 value) => $_setInt64(8, value);\n  @$pb.TagNumber(11)\n  $core.bool hasI() => $_has(8);\n  @$pb.TagNumber(11)\n  void clearI() => $_clearField(11);\n\n  @$pb.TagNumber(13)\n  $fixnum.Int64 get j => $_getI64(9);\n  @$pb.TagNumber(13)\n  set j($fixnum.Int64 value) => $_setInt64(9, value);\n  @$pb.TagNumber(13)\n  $core.bool hasJ() => $_has(9);\n  @$pb.TagNumber(13)\n  void clearJ() => $_clearField(13);\n}\n\nclass PreMessage extends $pb.GeneratedMessage {\n  factory PreMessage({\n    $core.int? cmd,\n    $core.int? sequenceId,\n    $core.String? sdkVersion,\n    $core.String? token,\n    $core.int? refer,\n    $core.int? inboxType,\n    $core.String? buildNumber,\n    SendMessageBody? sendMessageBody,\n    $core.String? aa,\n    $core.String? devicePlatform,\n    $core.Iterable<HeadersList>? headers,\n    $core.int? authType,\n    $core.String? biz,\n    $core.String? access,\n  }) {\n    final result = create();\n    if (cmd != null) result.cmd = cmd;\n    if (sequenceId != null) result.sequenceId = sequenceId;\n    if (sdkVersion != null) result.sdkVersion = sdkVersion;\n    if (token != null) result.token = token;\n    if (refer != null) result.refer = refer;\n    if (inboxType != null) result.inboxType = inboxType;\n    if (buildNumber != null) result.buildNumber = buildNumber;\n    if (sendMessageBody != null) result.sendMessageBody = sendMessageBody;\n    if (aa != null) result.aa = aa;\n    if (devicePlatform != null) result.devicePlatform = devicePlatform;\n    if (headers != null) result.headers.addAll(headers);\n    if (authType != null) result.authType = authType;\n    if (biz != null) result.biz = biz;\n    if (access != null) result.access = access;\n    return result;\n  }\n\n  PreMessage._();\n\n  factory PreMessage.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory PreMessage.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'PreMessage',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aI(1, _omitFieldNames ? '' : 'cmd', fieldType: $pb.PbFieldType.OU3)\n    ..aI(2, _omitFieldNames ? '' : 'sequenceId',\n        protoName: 'sequenceId', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(3, _omitFieldNames ? '' : 'sdkVersion', protoName: 'sdkVersion')\n    ..aOS(4, _omitFieldNames ? '' : 'token')\n    ..aI(5, _omitFieldNames ? '' : 'refer', fieldType: $pb.PbFieldType.OU3)\n    ..aI(6, _omitFieldNames ? '' : 'inboxType',\n        protoName: 'inboxType', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(7, _omitFieldNames ? '' : 'buildNumber', protoName: 'buildNumber')\n    ..aOM<SendMessageBody>(8, _omitFieldNames ? '' : 'sendMessageBody',\n        protoName: 'sendMessageBody', subBuilder: SendMessageBody.create)\n    ..aOS(9, _omitFieldNames ? '' : 'aa')\n    ..aOS(11, _omitFieldNames ? '' : 'devicePlatform',\n        protoName: 'devicePlatform')\n    ..pPM<HeadersList>(15, _omitFieldNames ? '' : 'headers',\n        subBuilder: HeadersList.create)\n    ..aI(18, _omitFieldNames ? '' : 'authType',\n        protoName: 'authType', fieldType: $pb.PbFieldType.OU3)\n    ..aOS(21, _omitFieldNames ? '' : 'biz')\n    ..aOS(22, _omitFieldNames ? '' : 'access')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PreMessage clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  PreMessage copyWith(void Function(PreMessage) updates) =>\n      super.copyWith((message) => updates(message as PreMessage)) as PreMessage;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static PreMessage create() => PreMessage._();\n  @$core.override\n  PreMessage createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static PreMessage getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<PreMessage>(create);\n  static PreMessage? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.int get cmd => $_getIZ(0);\n  @$pb.TagNumber(1)\n  set cmd($core.int value) => $_setUnsignedInt32(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasCmd() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearCmd() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.int get sequenceId => $_getIZ(1);\n  @$pb.TagNumber(2)\n  set sequenceId($core.int value) => $_setUnsignedInt32(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasSequenceId() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearSequenceId() => $_clearField(2);\n\n  @$pb.TagNumber(3)\n  $core.String get sdkVersion => $_getSZ(2);\n  @$pb.TagNumber(3)\n  set sdkVersion($core.String value) => $_setString(2, value);\n  @$pb.TagNumber(3)\n  $core.bool hasSdkVersion() => $_has(2);\n  @$pb.TagNumber(3)\n  void clearSdkVersion() => $_clearField(3);\n\n  @$pb.TagNumber(4)\n  $core.String get token => $_getSZ(3);\n  @$pb.TagNumber(4)\n  set token($core.String value) => $_setString(3, value);\n  @$pb.TagNumber(4)\n  $core.bool hasToken() => $_has(3);\n  @$pb.TagNumber(4)\n  void clearToken() => $_clearField(4);\n\n  @$pb.TagNumber(5)\n  $core.int get refer => $_getIZ(4);\n  @$pb.TagNumber(5)\n  set refer($core.int value) => $_setUnsignedInt32(4, value);\n  @$pb.TagNumber(5)\n  $core.bool hasRefer() => $_has(4);\n  @$pb.TagNumber(5)\n  void clearRefer() => $_clearField(5);\n\n  @$pb.TagNumber(6)\n  $core.int get inboxType => $_getIZ(5);\n  @$pb.TagNumber(6)\n  set inboxType($core.int value) => $_setUnsignedInt32(5, value);\n  @$pb.TagNumber(6)\n  $core.bool hasInboxType() => $_has(5);\n  @$pb.TagNumber(6)\n  void clearInboxType() => $_clearField(6);\n\n  @$pb.TagNumber(7)\n  $core.String get buildNumber => $_getSZ(6);\n  @$pb.TagNumber(7)\n  set buildNumber($core.String value) => $_setString(6, value);\n  @$pb.TagNumber(7)\n  $core.bool hasBuildNumber() => $_has(6);\n  @$pb.TagNumber(7)\n  void clearBuildNumber() => $_clearField(7);\n\n  @$pb.TagNumber(8)\n  SendMessageBody get sendMessageBody => $_getN(7);\n  @$pb.TagNumber(8)\n  set sendMessageBody(SendMessageBody value) => $_setField(8, value);\n  @$pb.TagNumber(8)\n  $core.bool hasSendMessageBody() => $_has(7);\n  @$pb.TagNumber(8)\n  void clearSendMessageBody() => $_clearField(8);\n  @$pb.TagNumber(8)\n  SendMessageBody ensureSendMessageBody() => $_ensure(7);\n\n  /// 字段名待定\n  @$pb.TagNumber(9)\n  $core.String get aa => $_getSZ(8);\n  @$pb.TagNumber(9)\n  set aa($core.String value) => $_setString(8, value);\n  @$pb.TagNumber(9)\n  $core.bool hasAa() => $_has(8);\n  @$pb.TagNumber(9)\n  void clearAa() => $_clearField(9);\n\n  @$pb.TagNumber(11)\n  $core.String get devicePlatform => $_getSZ(9);\n  @$pb.TagNumber(11)\n  set devicePlatform($core.String value) => $_setString(9, value);\n  @$pb.TagNumber(11)\n  $core.bool hasDevicePlatform() => $_has(9);\n  @$pb.TagNumber(11)\n  void clearDevicePlatform() => $_clearField(11);\n\n  @$pb.TagNumber(15)\n  $pb.PbList<HeadersList> get headers => $_getList(10);\n\n  @$pb.TagNumber(18)\n  $core.int get authType => $_getIZ(11);\n  @$pb.TagNumber(18)\n  set authType($core.int value) => $_setUnsignedInt32(11, value);\n  @$pb.TagNumber(18)\n  $core.bool hasAuthType() => $_has(11);\n  @$pb.TagNumber(18)\n  void clearAuthType() => $_clearField(18);\n\n  @$pb.TagNumber(21)\n  $core.String get biz => $_getSZ(12);\n  @$pb.TagNumber(21)\n  set biz($core.String value) => $_setString(12, value);\n  @$pb.TagNumber(21)\n  $core.bool hasBiz() => $_has(12);\n  @$pb.TagNumber(21)\n  void clearBiz() => $_clearField(21);\n\n  @$pb.TagNumber(22)\n  $core.String get access => $_getSZ(13);\n  @$pb.TagNumber(22)\n  set access($core.String value) => $_setString(13, value);\n  @$pb.TagNumber(22)\n  $core.bool hasAccess() => $_has(13);\n  @$pb.TagNumber(22)\n  void clearAccess() => $_clearField(22);\n}\n\nclass HeadersList extends $pb.GeneratedMessage {\n  factory HeadersList({\n    $core.String? key,\n    $core.String? value,\n  }) {\n    final result = create();\n    if (key != null) result.key = key;\n    if (value != null) result.value = value;\n    return result;\n  }\n\n  HeadersList._();\n\n  factory HeadersList.fromBuffer($core.List<$core.int> data,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromBuffer(data, registry);\n  factory HeadersList.fromJson($core.String json,\n          [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>\n      create()..mergeFromJson(json, registry);\n\n  static final $pb.BuilderInfo _i = $pb.BuilderInfo(\n      _omitMessageNames ? '' : 'HeadersList',\n      package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'),\n      createEmptyInstance: create)\n    ..aOS(1, _omitFieldNames ? '' : 'key')\n    ..aOS(2, _omitFieldNames ? '' : 'value')\n    ..hasRequiredFields = false;\n\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  HeadersList clone() => deepCopy();\n  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')\n  HeadersList copyWith(void Function(HeadersList) updates) =>\n      super.copyWith((message) => updates(message as HeadersList))\n          as HeadersList;\n\n  @$core.override\n  $pb.BuilderInfo get info_ => _i;\n\n  @$core.pragma('dart2js:noInline')\n  static HeadersList create() => HeadersList._();\n  @$core.override\n  HeadersList createEmptyInstance() => create();\n  @$core.pragma('dart2js:noInline')\n  static HeadersList getDefault() => _defaultInstance ??=\n      $pb.GeneratedMessage.$_defaultFor<HeadersList>(create);\n  static HeadersList? _defaultInstance;\n\n  @$pb.TagNumber(1)\n  $core.String get key => $_getSZ(0);\n  @$pb.TagNumber(1)\n  set key($core.String value) => $_setString(0, value);\n  @$pb.TagNumber(1)\n  $core.bool hasKey() => $_has(0);\n  @$pb.TagNumber(1)\n  void clearKey() => $_clearField(1);\n\n  @$pb.TagNumber(2)\n  $core.String get value => $_getSZ(1);\n  @$pb.TagNumber(2)\n  set value($core.String value) => $_setString(1, value);\n  @$pb.TagNumber(2)\n  $core.bool hasValue() => $_has(1);\n  @$pb.TagNumber(2)\n  void clearValue() => $_clearField(2);\n}\n\nconst $core.bool _omitFieldNames =\n    $core.bool.fromEnvironment('protobuf.omit_field_names');\nconst $core.bool _omitMessageNames =\n    $core.bool.fromEnvironment('protobuf.omit_message_names');\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/proto/douyin.pbenum.dart",
    "content": "// This is a generated file - do not edit.\n//\n// Generated from douyin.proto.\n\n// @dart = 3.3\n\n// ignore_for_file: annotate_overrides, camel_case_types, comment_references\n// ignore_for_file: constant_identifier_names\n// ignore_for_file: curly_braces_in_flow_control_structures\n// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes\n// ignore_for_file: non_constant_identifier_names, prefer_relative_imports\n\nimport 'dart:core' as $core;\n\nimport 'package:protobuf/protobuf.dart' as $pb;\n\nclass CommentTypeTag extends $pb.ProtobufEnum {\n  static const CommentTypeTag COMMENTTYPETAGUNKNOWN =\n      CommentTypeTag._(0, _omitEnumNames ? '' : 'COMMENTTYPETAGUNKNOWN');\n  static const CommentTypeTag COMMENTTYPETAGSTAR =\n      CommentTypeTag._(1, _omitEnumNames ? '' : 'COMMENTTYPETAGSTAR');\n\n  static const $core.List<CommentTypeTag> values = <CommentTypeTag>[\n    COMMENTTYPETAGUNKNOWN,\n    COMMENTTYPETAGSTAR,\n  ];\n\n  static final $core.List<CommentTypeTag?> _byValue =\n      $pb.ProtobufEnum.$_initByValueList(values, 1);\n  static CommentTypeTag? valueOf($core.int value) =>\n      value < 0 || value >= _byValue.length ? null : _byValue[value];\n\n  const CommentTypeTag._(super.value, super.name);\n}\n\nconst $core.bool _omitEnumNames =\n    $core.bool.fromEnvironment('protobuf.omit_enum_names');\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/proto/douyin.pbjson.dart",
    "content": "// This is a generated file - do not edit.\n//\n// Generated from douyin.proto.\n\n// @dart = 3.3\n\n// ignore_for_file: annotate_overrides, camel_case_types, comment_references\n// ignore_for_file: constant_identifier_names\n// ignore_for_file: curly_braces_in_flow_control_structures\n// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes\n// ignore_for_file: non_constant_identifier_names, prefer_relative_imports\n// ignore_for_file: unused_import\n\nimport 'dart:convert' as $convert;\nimport 'dart:core' as $core;\nimport 'dart:typed_data' as $typed_data;\n\n@$core.Deprecated('Use commentTypeTagDescriptor instead')\nconst CommentTypeTag$json = {\n  '1': 'CommentTypeTag',\n  '2': [\n    {'1': 'COMMENTTYPETAGUNKNOWN', '2': 0},\n    {'1': 'COMMENTTYPETAGSTAR', '2': 1},\n  ],\n};\n\n/// Descriptor for `CommentTypeTag`. Decode as a `google.protobuf.EnumDescriptorProto`.\nfinal $typed_data.Uint8List commentTypeTagDescriptor = $convert.base64Decode(\n    'Cg5Db21tZW50VHlwZVRhZxIZChVDT01NRU5UVFlQRVRBR1VOS05PV04QABIWChJDT01NRU5UVF'\n    'lQRVRBR1NUQVIQAQ==');\n\n@$core.Deprecated('Use responseDescriptor instead')\nconst Response$json = {\n  '1': 'Response',\n  '2': [\n    {\n      '1': 'messagesList',\n      '3': 1,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.Message',\n      '10': 'messagesList'\n    },\n    {'1': 'cursor', '3': 2, '4': 1, '5': 9, '10': 'cursor'},\n    {'1': 'fetchInterval', '3': 3, '4': 1, '5': 4, '10': 'fetchInterval'},\n    {'1': 'now', '3': 4, '4': 1, '5': 4, '10': 'now'},\n    {'1': 'internalExt', '3': 5, '4': 1, '5': 9, '10': 'internalExt'},\n    {'1': 'fetchType', '3': 6, '4': 1, '5': 13, '10': 'fetchType'},\n    {\n      '1': 'routeParams',\n      '3': 7,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.Response.RouteParamsEntry',\n      '10': 'routeParams'\n    },\n    {\n      '1': 'heartbeatDuration',\n      '3': 8,\n      '4': 1,\n      '5': 4,\n      '10': 'heartbeatDuration'\n    },\n    {'1': 'needAck', '3': 9, '4': 1, '5': 8, '10': 'needAck'},\n    {'1': 'pushServer', '3': 10, '4': 1, '5': 9, '10': 'pushServer'},\n    {'1': 'liveCursor', '3': 11, '4': 1, '5': 9, '10': 'liveCursor'},\n    {'1': 'historyNoMore', '3': 12, '4': 1, '5': 8, '10': 'historyNoMore'},\n  ],\n  '3': [Response_RouteParamsEntry$json],\n};\n\n@$core.Deprecated('Use responseDescriptor instead')\nconst Response_RouteParamsEntry$json = {\n  '1': 'RouteParamsEntry',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},\n  ],\n  '7': {'7': true},\n};\n\n/// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List responseDescriptor = $convert.base64Decode(\n    'CghSZXNwb25zZRIzCgxtZXNzYWdlc0xpc3QYASADKAsyDy5kb3V5aW4uTWVzc2FnZVIMbWVzc2'\n    'FnZXNMaXN0EhYKBmN1cnNvchgCIAEoCVIGY3Vyc29yEiQKDWZldGNoSW50ZXJ2YWwYAyABKARS'\n    'DWZldGNoSW50ZXJ2YWwSEAoDbm93GAQgASgEUgNub3cSIAoLaW50ZXJuYWxFeHQYBSABKAlSC2'\n    'ludGVybmFsRXh0EhwKCWZldGNoVHlwZRgGIAEoDVIJZmV0Y2hUeXBlEkMKC3JvdXRlUGFyYW1z'\n    'GAcgAygLMiEuZG91eWluLlJlc3BvbnNlLlJvdXRlUGFyYW1zRW50cnlSC3JvdXRlUGFyYW1zEi'\n    'wKEWhlYXJ0YmVhdER1cmF0aW9uGAggASgEUhFoZWFydGJlYXREdXJhdGlvbhIYCgduZWVkQWNr'\n    'GAkgASgIUgduZWVkQWNrEh4KCnB1c2hTZXJ2ZXIYCiABKAlSCnB1c2hTZXJ2ZXISHgoKbGl2ZU'\n    'N1cnNvchgLIAEoCVIKbGl2ZUN1cnNvchIkCg1oaXN0b3J5Tm9Nb3JlGAwgASgIUg1oaXN0b3J5'\n    'Tm9Nb3JlGj4KEFJvdXRlUGFyYW1zRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAi'\n    'ABKAlSBXZhbHVlOgI4AQ==');\n\n@$core.Deprecated('Use messageDescriptor instead')\nconst Message$json = {\n  '1': 'Message',\n  '2': [\n    {'1': 'method', '3': 1, '4': 1, '5': 9, '10': 'method'},\n    {'1': 'payload', '3': 2, '4': 1, '5': 12, '10': 'payload'},\n    {'1': 'msgId', '3': 3, '4': 1, '5': 3, '10': 'msgId'},\n    {'1': 'msgType', '3': 4, '4': 1, '5': 5, '10': 'msgType'},\n    {'1': 'offset', '3': 5, '4': 1, '5': 3, '10': 'offset'},\n    {'1': 'needWrdsStore', '3': 6, '4': 1, '5': 8, '10': 'needWrdsStore'},\n    {'1': 'wrdsVersion', '3': 7, '4': 1, '5': 3, '10': 'wrdsVersion'},\n    {'1': 'wrdsSubKey', '3': 8, '4': 1, '5': 9, '10': 'wrdsSubKey'},\n  ],\n};\n\n/// Descriptor for `Message`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List messageDescriptor = $convert.base64Decode(\n    'CgdNZXNzYWdlEhYKBm1ldGhvZBgBIAEoCVIGbWV0aG9kEhgKB3BheWxvYWQYAiABKAxSB3BheW'\n    'xvYWQSFAoFbXNnSWQYAyABKANSBW1zZ0lkEhgKB21zZ1R5cGUYBCABKAVSB21zZ1R5cGUSFgoG'\n    'b2Zmc2V0GAUgASgDUgZvZmZzZXQSJAoNbmVlZFdyZHNTdG9yZRgGIAEoCFINbmVlZFdyZHNTdG'\n    '9yZRIgCgt3cmRzVmVyc2lvbhgHIAEoA1ILd3Jkc1ZlcnNpb24SHgoKd3Jkc1N1YktleRgIIAEo'\n    'CVIKd3Jkc1N1YktleQ==');\n\n@$core.Deprecated('Use chatMessageDescriptor instead')\nconst ChatMessage$json = {\n  '1': 'ChatMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'},\n    {'1': 'visibleToSender', '3': 4, '4': 1, '5': 8, '10': 'visibleToSender'},\n    {\n      '1': 'backgroundImage',\n      '3': 5,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'backgroundImage'\n    },\n    {\n      '1': 'fullScreenTextColor',\n      '3': 6,\n      '4': 1,\n      '5': 9,\n      '10': 'fullScreenTextColor'\n    },\n    {\n      '1': 'backgroundImageV2',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'backgroundImageV2'\n    },\n    {\n      '1': 'publicAreaCommon',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PublicAreaCommon',\n      '10': 'publicAreaCommon'\n    },\n    {\n      '1': 'giftImage',\n      '3': 9,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'giftImage'\n    },\n    {'1': 'agreeMsgId', '3': 11, '4': 1, '5': 4, '10': 'agreeMsgId'},\n    {'1': 'priorityLevel', '3': 12, '4': 1, '5': 13, '10': 'priorityLevel'},\n    {\n      '1': 'landscapeAreaCommon',\n      '3': 13,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.LandscapeAreaCommon',\n      '10': 'landscapeAreaCommon'\n    },\n    {'1': 'eventTime', '3': 15, '4': 1, '5': 4, '10': 'eventTime'},\n    {'1': 'sendReview', '3': 16, '4': 1, '5': 8, '10': 'sendReview'},\n    {'1': 'fromIntercom', '3': 17, '4': 1, '5': 8, '10': 'fromIntercom'},\n    {\n      '1': 'intercomHideUserCard',\n      '3': 18,\n      '4': 1,\n      '5': 8,\n      '10': 'intercomHideUserCard'\n    },\n    {'1': 'chatBy', '3': 20, '4': 1, '5': 9, '10': 'chatBy'},\n    {\n      '1': 'individualChatPriority',\n      '3': 21,\n      '4': 1,\n      '5': 13,\n      '10': 'individualChatPriority'\n    },\n    {\n      '1': 'rtfContent',\n      '3': 22,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Text',\n      '10': 'rtfContent'\n    },\n  ],\n};\n\n/// Descriptor for `ChatMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List chatMessageDescriptor = $convert.base64Decode(\n    'CgtDaGF0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SIA'\n    'oEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhgKB2NvbnRlbnQYAyABKAlSB2NvbnRl'\n    'bnQSKAoPdmlzaWJsZVRvU2VuZGVyGAQgASgIUg92aXNpYmxlVG9TZW5kZXISNwoPYmFja2dyb3'\n    'VuZEltYWdlGAUgASgLMg0uZG91eWluLkltYWdlUg9iYWNrZ3JvdW5kSW1hZ2USMAoTZnVsbFNj'\n    'cmVlblRleHRDb2xvchgGIAEoCVITZnVsbFNjcmVlblRleHRDb2xvchI7ChFiYWNrZ3JvdW5kSW'\n    '1hZ2VWMhgHIAEoCzINLmRvdXlpbi5JbWFnZVIRYmFja2dyb3VuZEltYWdlVjISRAoQcHVibGlj'\n    'QXJlYUNvbW1vbhgIIAEoCzIYLmRvdXlpbi5QdWJsaWNBcmVhQ29tbW9uUhBwdWJsaWNBcmVhQ2'\n    '9tbW9uEisKCWdpZnRJbWFnZRgJIAEoCzINLmRvdXlpbi5JbWFnZVIJZ2lmdEltYWdlEh4KCmFn'\n    'cmVlTXNnSWQYCyABKARSCmFncmVlTXNnSWQSJAoNcHJpb3JpdHlMZXZlbBgMIAEoDVINcHJpb3'\n    'JpdHlMZXZlbBJNChNsYW5kc2NhcGVBcmVhQ29tbW9uGA0gASgLMhsuZG91eWluLkxhbmRzY2Fw'\n    'ZUFyZWFDb21tb25SE2xhbmRzY2FwZUFyZWFDb21tb24SHAoJZXZlbnRUaW1lGA8gASgEUglldm'\n    'VudFRpbWUSHgoKc2VuZFJldmlldxgQIAEoCFIKc2VuZFJldmlldxIiCgxmcm9tSW50ZXJjb20Y'\n    'ESABKAhSDGZyb21JbnRlcmNvbRIyChRpbnRlcmNvbUhpZGVVc2VyQ2FyZBgSIAEoCFIUaW50ZX'\n    'Jjb21IaWRlVXNlckNhcmQSFgoGY2hhdEJ5GBQgASgJUgZjaGF0QnkSNgoWaW5kaXZpZHVhbENo'\n    'YXRQcmlvcml0eRgVIAEoDVIWaW5kaXZpZHVhbENoYXRQcmlvcml0eRIsCgpydGZDb250ZW50GB'\n    'YgASgLMgwuZG91eWluLlRleHRSCnJ0ZkNvbnRlbnQ=');\n\n@$core.Deprecated('Use landscapeAreaCommonDescriptor instead')\nconst LandscapeAreaCommon$json = {\n  '1': 'LandscapeAreaCommon',\n  '2': [\n    {'1': 'showHead', '3': 1, '4': 1, '5': 8, '10': 'showHead'},\n    {'1': 'showNickname', '3': 2, '4': 1, '5': 8, '10': 'showNickname'},\n    {'1': 'showFontColor', '3': 3, '4': 1, '5': 8, '10': 'showFontColor'},\n    {'1': 'colorValueList', '3': 4, '4': 3, '5': 9, '10': 'colorValueList'},\n    {\n      '1': 'commentTypeTagsList',\n      '3': 5,\n      '4': 3,\n      '5': 14,\n      '6': '.douyin.CommentTypeTag',\n      '10': 'commentTypeTagsList'\n    },\n  ],\n};\n\n/// Descriptor for `LandscapeAreaCommon`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List landscapeAreaCommonDescriptor = $convert.base64Decode(\n    'ChNMYW5kc2NhcGVBcmVhQ29tbW9uEhoKCHNob3dIZWFkGAEgASgIUghzaG93SGVhZBIiCgxzaG'\n    '93Tmlja25hbWUYAiABKAhSDHNob3dOaWNrbmFtZRIkCg1zaG93Rm9udENvbG9yGAMgASgIUg1z'\n    'aG93Rm9udENvbG9yEiYKDmNvbG9yVmFsdWVMaXN0GAQgAygJUg5jb2xvclZhbHVlTGlzdBJICh'\n    'Njb21tZW50VHlwZVRhZ3NMaXN0GAUgAygOMhYuZG91eWluLkNvbW1lbnRUeXBlVGFnUhNjb21t'\n    'ZW50VHlwZVRhZ3NMaXN0');\n\n@$core.Deprecated('Use roomUserSeqMessageDescriptor instead')\nconst RoomUserSeqMessage$json = {\n  '1': 'RoomUserSeqMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {\n      '1': 'ranksList',\n      '3': 2,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.RoomUserSeqMessageContributor',\n      '10': 'ranksList'\n    },\n    {'1': 'total', '3': 3, '4': 1, '5': 3, '10': 'total'},\n    {'1': 'popStr', '3': 4, '4': 1, '5': 9, '10': 'popStr'},\n    {\n      '1': 'seatsList',\n      '3': 5,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.RoomUserSeqMessageContributor',\n      '10': 'seatsList'\n    },\n    {'1': 'popularity', '3': 6, '4': 1, '5': 3, '10': 'popularity'},\n    {'1': 'totalUser', '3': 7, '4': 1, '5': 3, '10': 'totalUser'},\n    {'1': 'totalUserStr', '3': 8, '4': 1, '5': 9, '10': 'totalUserStr'},\n    {'1': 'totalStr', '3': 9, '4': 1, '5': 9, '10': 'totalStr'},\n    {\n      '1': 'onlineUserForAnchor',\n      '3': 10,\n      '4': 1,\n      '5': 9,\n      '10': 'onlineUserForAnchor'\n    },\n    {\n      '1': 'totalPvForAnchor',\n      '3': 11,\n      '4': 1,\n      '5': 9,\n      '10': 'totalPvForAnchor'\n    },\n    {'1': 'upRightStatsStr', '3': 12, '4': 1, '5': 9, '10': 'upRightStatsStr'},\n    {\n      '1': 'upRightStatsStrComplete',\n      '3': 13,\n      '4': 1,\n      '5': 9,\n      '10': 'upRightStatsStrComplete'\n    },\n  ],\n};\n\n/// Descriptor for `RoomUserSeqMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List roomUserSeqMessageDescriptor = $convert.base64Decode(\n    'ChJSb29tVXNlclNlcU1lc3NhZ2USJgoGY29tbW9uGAEgASgLMg4uZG91eWluLkNvbW1vblIGY2'\n    '9tbW9uEkMKCXJhbmtzTGlzdBgCIAMoCzIlLmRvdXlpbi5Sb29tVXNlclNlcU1lc3NhZ2VDb250'\n    'cmlidXRvclIJcmFua3NMaXN0EhQKBXRvdGFsGAMgASgDUgV0b3RhbBIWCgZwb3BTdHIYBCABKA'\n    'lSBnBvcFN0chJDCglzZWF0c0xpc3QYBSADKAsyJS5kb3V5aW4uUm9vbVVzZXJTZXFNZXNzYWdl'\n    'Q29udHJpYnV0b3JSCXNlYXRzTGlzdBIeCgpwb3B1bGFyaXR5GAYgASgDUgpwb3B1bGFyaXR5Eh'\n    'wKCXRvdGFsVXNlchgHIAEoA1IJdG90YWxVc2VyEiIKDHRvdGFsVXNlclN0chgIIAEoCVIMdG90'\n    'YWxVc2VyU3RyEhoKCHRvdGFsU3RyGAkgASgJUgh0b3RhbFN0chIwChNvbmxpbmVVc2VyRm9yQW'\n    '5jaG9yGAogASgJUhNvbmxpbmVVc2VyRm9yQW5jaG9yEioKEHRvdGFsUHZGb3JBbmNob3IYCyAB'\n    'KAlSEHRvdGFsUHZGb3JBbmNob3ISKAoPdXBSaWdodFN0YXRzU3RyGAwgASgJUg91cFJpZ2h0U3'\n    'RhdHNTdHISOAoXdXBSaWdodFN0YXRzU3RyQ29tcGxldGUYDSABKAlSF3VwUmlnaHRTdGF0c1N0'\n    'ckNvbXBsZXRl');\n\n@$core.Deprecated('Use commonTextMessageDescriptor instead')\nconst CommonTextMessage$json = {\n  '1': 'CommonTextMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'scene', '3': 3, '4': 1, '5': 9, '10': 'scene'},\n  ],\n};\n\n/// Descriptor for `CommonTextMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List commonTextMessageDescriptor = $convert.base64Decode(\n    'ChFDb21tb25UZXh0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb2'\n    '1tb24SIAoEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhQKBXNjZW5lGAMgASgJUgVz'\n    'Y2VuZQ==');\n\n@$core.Deprecated('Use updateFanTicketMessageDescriptor instead')\nconst UpdateFanTicketMessage$json = {\n  '1': 'UpdateFanTicketMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {\n      '1': 'roomFanTicketCountText',\n      '3': 2,\n      '4': 1,\n      '5': 9,\n      '10': 'roomFanTicketCountText'\n    },\n    {\n      '1': 'roomFanTicketCount',\n      '3': 3,\n      '4': 1,\n      '5': 4,\n      '10': 'roomFanTicketCount'\n    },\n    {'1': 'forceUpdate', '3': 4, '4': 1, '5': 8, '10': 'forceUpdate'},\n  ],\n};\n\n/// Descriptor for `UpdateFanTicketMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List updateFanTicketMessageDescriptor = $convert.base64Decode(\n    'ChZVcGRhdGVGYW5UaWNrZXRNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb2'\n    '5SBmNvbW1vbhI2ChZyb29tRmFuVGlja2V0Q291bnRUZXh0GAIgASgJUhZyb29tRmFuVGlja2V0'\n    'Q291bnRUZXh0Ei4KEnJvb21GYW5UaWNrZXRDb3VudBgDIAEoBFIScm9vbUZhblRpY2tldENvdW'\n    '50EiAKC2ZvcmNlVXBkYXRlGAQgASgIUgtmb3JjZVVwZGF0ZQ==');\n\n@$core.Deprecated('Use roomUserSeqMessageContributorDescriptor instead')\nconst RoomUserSeqMessageContributor$json = {\n  '1': 'RoomUserSeqMessageContributor',\n  '2': [\n    {'1': 'score', '3': 1, '4': 1, '5': 4, '10': 'score'},\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'rank', '3': 3, '4': 1, '5': 4, '10': 'rank'},\n    {'1': 'delta', '3': 4, '4': 1, '5': 4, '10': 'delta'},\n    {'1': 'isHidden', '3': 5, '4': 1, '5': 8, '10': 'isHidden'},\n    {'1': 'scoreDescription', '3': 6, '4': 1, '5': 9, '10': 'scoreDescription'},\n    {'1': 'exactlyScore', '3': 7, '4': 1, '5': 9, '10': 'exactlyScore'},\n  ],\n};\n\n/// Descriptor for `RoomUserSeqMessageContributor`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List roomUserSeqMessageContributorDescriptor = $convert.base64Decode(\n    'Ch1Sb29tVXNlclNlcU1lc3NhZ2VDb250cmlidXRvchIUCgVzY29yZRgBIAEoBFIFc2NvcmUSIA'\n    'oEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhIKBHJhbmsYAyABKARSBHJhbmsSFAoF'\n    'ZGVsdGEYBCABKARSBWRlbHRhEhoKCGlzSGlkZGVuGAUgASgIUghpc0hpZGRlbhIqChBzY29yZU'\n    'Rlc2NyaXB0aW9uGAYgASgJUhBzY29yZURlc2NyaXB0aW9uEiIKDGV4YWN0bHlTY29yZRgHIAEo'\n    'CVIMZXhhY3RseVNjb3Jl');\n\n@$core.Deprecated('Use giftMessageDescriptor instead')\nconst GiftMessage$json = {\n  '1': 'GiftMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'giftId', '3': 2, '4': 1, '5': 4, '10': 'giftId'},\n    {'1': 'fanTicketCount', '3': 3, '4': 1, '5': 4, '10': 'fanTicketCount'},\n    {'1': 'groupCount', '3': 4, '4': 1, '5': 4, '10': 'groupCount'},\n    {'1': 'repeatCount', '3': 5, '4': 1, '5': 4, '10': 'repeatCount'},\n    {'1': 'comboCount', '3': 6, '4': 1, '5': 4, '10': 'comboCount'},\n    {'1': 'user', '3': 7, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {\n      '1': 'toUser',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.User',\n      '10': 'toUser'\n    },\n    {'1': 'repeatEnd', '3': 9, '4': 1, '5': 13, '10': 'repeatEnd'},\n    {\n      '1': 'textEffect',\n      '3': 10,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextEffect',\n      '10': 'textEffect'\n    },\n    {'1': 'groupId', '3': 11, '4': 1, '5': 4, '10': 'groupId'},\n    {'1': 'incomeTaskgifts', '3': 12, '4': 1, '5': 4, '10': 'incomeTaskgifts'},\n    {\n      '1': 'roomFanTicketCount',\n      '3': 13,\n      '4': 1,\n      '5': 4,\n      '10': 'roomFanTicketCount'\n    },\n    {\n      '1': 'priority',\n      '3': 14,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.GiftIMPriority',\n      '10': 'priority'\n    },\n    {\n      '1': 'gift',\n      '3': 15,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.GiftStruct',\n      '10': 'gift'\n    },\n    {'1': 'logId', '3': 16, '4': 1, '5': 9, '10': 'logId'},\n    {'1': 'sendType', '3': 17, '4': 1, '5': 4, '10': 'sendType'},\n    {\n      '1': 'publicAreaCommon',\n      '3': 18,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PublicAreaCommon',\n      '10': 'publicAreaCommon'\n    },\n    {\n      '1': 'trayDisplayText',\n      '3': 19,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Text',\n      '10': 'trayDisplayText'\n    },\n    {\n      '1': 'bannedDisplayEffects',\n      '3': 20,\n      '4': 1,\n      '5': 4,\n      '10': 'bannedDisplayEffects'\n    },\n    {'1': 'displayForSelf', '3': 25, '4': 1, '5': 8, '10': 'displayForSelf'},\n    {\n      '1': 'interactGiftInfo',\n      '3': 26,\n      '4': 1,\n      '5': 9,\n      '10': 'interactGiftInfo'\n    },\n    {'1': 'diyItemInfo', '3': 27, '4': 1, '5': 9, '10': 'diyItemInfo'},\n    {'1': 'minAssetSetList', '3': 28, '4': 3, '5': 4, '10': 'minAssetSetList'},\n    {'1': 'totalCount', '3': 29, '4': 1, '5': 4, '10': 'totalCount'},\n    {\n      '1': 'clientGiftSource',\n      '3': 30,\n      '4': 1,\n      '5': 13,\n      '10': 'clientGiftSource'\n    },\n    {'1': 'toUserIdsList', '3': 32, '4': 3, '5': 4, '10': 'toUserIdsList'},\n    {'1': 'sendTime', '3': 33, '4': 1, '5': 4, '10': 'sendTime'},\n    {\n      '1': 'forceDisplayEffects',\n      '3': 34,\n      '4': 1,\n      '5': 4,\n      '10': 'forceDisplayEffects'\n    },\n    {'1': 'traceId', '3': 35, '4': 1, '5': 9, '10': 'traceId'},\n    {'1': 'effectDisplayTs', '3': 36, '4': 1, '5': 4, '10': 'effectDisplayTs'},\n  ],\n};\n\n/// Descriptor for `GiftMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List giftMessageDescriptor = $convert.base64Decode(\n    'CgtHaWZ0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SFg'\n    'oGZ2lmdElkGAIgASgEUgZnaWZ0SWQSJgoOZmFuVGlja2V0Q291bnQYAyABKARSDmZhblRpY2tl'\n    'dENvdW50Eh4KCmdyb3VwQ291bnQYBCABKARSCmdyb3VwQ291bnQSIAoLcmVwZWF0Q291bnQYBS'\n    'ABKARSC3JlcGVhdENvdW50Eh4KCmNvbWJvQ291bnQYBiABKARSCmNvbWJvQ291bnQSIAoEdXNl'\n    'chgHIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEiQKBnRvVXNlchgIIAEoCzIMLmRvdXlpbi5Vc2'\n    'VyUgZ0b1VzZXISHAoJcmVwZWF0RW5kGAkgASgNUglyZXBlYXRFbmQSMgoKdGV4dEVmZmVjdBgK'\n    'IAEoCzISLmRvdXlpbi5UZXh0RWZmZWN0Ugp0ZXh0RWZmZWN0EhgKB2dyb3VwSWQYCyABKARSB2'\n    'dyb3VwSWQSKAoPaW5jb21lVGFza2dpZnRzGAwgASgEUg9pbmNvbWVUYXNrZ2lmdHMSLgoScm9v'\n    'bUZhblRpY2tldENvdW50GA0gASgEUhJyb29tRmFuVGlja2V0Q291bnQSMgoIcHJpb3JpdHkYDi'\n    'ABKAsyFi5kb3V5aW4uR2lmdElNUHJpb3JpdHlSCHByaW9yaXR5EiYKBGdpZnQYDyABKAsyEi5k'\n    'b3V5aW4uR2lmdFN0cnVjdFIEZ2lmdBIUCgVsb2dJZBgQIAEoCVIFbG9nSWQSGgoIc2VuZFR5cG'\n    'UYESABKARSCHNlbmRUeXBlEkQKEHB1YmxpY0FyZWFDb21tb24YEiABKAsyGC5kb3V5aW4uUHVi'\n    'bGljQXJlYUNvbW1vblIQcHVibGljQXJlYUNvbW1vbhI2Cg90cmF5RGlzcGxheVRleHQYEyABKA'\n    'syDC5kb3V5aW4uVGV4dFIPdHJheURpc3BsYXlUZXh0EjIKFGJhbm5lZERpc3BsYXlFZmZlY3Rz'\n    'GBQgASgEUhRiYW5uZWREaXNwbGF5RWZmZWN0cxImCg5kaXNwbGF5Rm9yU2VsZhgZIAEoCFIOZG'\n    'lzcGxheUZvclNlbGYSKgoQaW50ZXJhY3RHaWZ0SW5mbxgaIAEoCVIQaW50ZXJhY3RHaWZ0SW5m'\n    'bxIgCgtkaXlJdGVtSW5mbxgbIAEoCVILZGl5SXRlbUluZm8SKAoPbWluQXNzZXRTZXRMaXN0GB'\n    'wgAygEUg9taW5Bc3NldFNldExpc3QSHgoKdG90YWxDb3VudBgdIAEoBFIKdG90YWxDb3VudBIq'\n    'ChBjbGllbnRHaWZ0U291cmNlGB4gASgNUhBjbGllbnRHaWZ0U291cmNlEiQKDXRvVXNlcklkc0'\n    'xpc3QYICADKARSDXRvVXNlcklkc0xpc3QSGgoIc2VuZFRpbWUYISABKARSCHNlbmRUaW1lEjAK'\n    'E2ZvcmNlRGlzcGxheUVmZmVjdHMYIiABKARSE2ZvcmNlRGlzcGxheUVmZmVjdHMSGAoHdHJhY2'\n    'VJZBgjIAEoCVIHdHJhY2VJZBIoCg9lZmZlY3REaXNwbGF5VHMYJCABKARSD2VmZmVjdERpc3Bs'\n    'YXlUcw==');\n\n@$core.Deprecated('Use giftStructDescriptor instead')\nconst GiftStruct$json = {\n  '1': 'GiftStruct',\n  '2': [\n    {\n      '1': 'image',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'image'\n    },\n    {'1': 'describe', '3': 2, '4': 1, '5': 9, '10': 'describe'},\n    {'1': 'notify', '3': 3, '4': 1, '5': 8, '10': 'notify'},\n    {'1': 'duration', '3': 4, '4': 1, '5': 4, '10': 'duration'},\n    {'1': 'id', '3': 5, '4': 1, '5': 4, '10': 'id'},\n    {'1': 'forLinkmic', '3': 7, '4': 1, '5': 8, '10': 'forLinkmic'},\n    {'1': 'doodle', '3': 8, '4': 1, '5': 8, '10': 'doodle'},\n    {'1': 'forFansclub', '3': 9, '4': 1, '5': 8, '10': 'forFansclub'},\n    {'1': 'combo', '3': 10, '4': 1, '5': 8, '10': 'combo'},\n    {'1': 'type', '3': 11, '4': 1, '5': 13, '10': 'type'},\n    {'1': 'diamondCount', '3': 12, '4': 1, '5': 13, '10': 'diamondCount'},\n    {\n      '1': 'isDisplayedOnPanel',\n      '3': 13,\n      '4': 1,\n      '5': 8,\n      '10': 'isDisplayedOnPanel'\n    },\n    {'1': 'primaryEffectId', '3': 14, '4': 1, '5': 4, '10': 'primaryEffectId'},\n    {\n      '1': 'giftLabelIcon',\n      '3': 15,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'giftLabelIcon'\n    },\n    {'1': 'name', '3': 16, '4': 1, '5': 9, '10': 'name'},\n    {'1': 'region', '3': 17, '4': 1, '5': 9, '10': 'region'},\n    {'1': 'manual', '3': 18, '4': 1, '5': 9, '10': 'manual'},\n    {'1': 'forCustom', '3': 19, '4': 1, '5': 8, '10': 'forCustom'},\n    {'1': 'icon', '3': 21, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'icon'},\n    {'1': 'actionType', '3': 22, '4': 1, '5': 13, '10': 'actionType'},\n  ],\n};\n\n/// Descriptor for `GiftStruct`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List giftStructDescriptor = $convert.base64Decode(\n    'CgpHaWZ0U3RydWN0EiMKBWltYWdlGAEgASgLMg0uZG91eWluLkltYWdlUgVpbWFnZRIaCghkZX'\n    'NjcmliZRgCIAEoCVIIZGVzY3JpYmUSFgoGbm90aWZ5GAMgASgIUgZub3RpZnkSGgoIZHVyYXRp'\n    'b24YBCABKARSCGR1cmF0aW9uEg4KAmlkGAUgASgEUgJpZBIeCgpmb3JMaW5rbWljGAcgASgIUg'\n    'pmb3JMaW5rbWljEhYKBmRvb2RsZRgIIAEoCFIGZG9vZGxlEiAKC2ZvckZhbnNjbHViGAkgASgI'\n    'Ugtmb3JGYW5zY2x1YhIUCgVjb21ibxgKIAEoCFIFY29tYm8SEgoEdHlwZRgLIAEoDVIEdHlwZR'\n    'IiCgxkaWFtb25kQ291bnQYDCABKA1SDGRpYW1vbmRDb3VudBIuChJpc0Rpc3BsYXllZE9uUGFu'\n    'ZWwYDSABKAhSEmlzRGlzcGxheWVkT25QYW5lbBIoCg9wcmltYXJ5RWZmZWN0SWQYDiABKARSD3'\n    'ByaW1hcnlFZmZlY3RJZBIzCg1naWZ0TGFiZWxJY29uGA8gASgLMg0uZG91eWluLkltYWdlUg1n'\n    'aWZ0TGFiZWxJY29uEhIKBG5hbWUYECABKAlSBG5hbWUSFgoGcmVnaW9uGBEgASgJUgZyZWdpb2'\n    '4SFgoGbWFudWFsGBIgASgJUgZtYW51YWwSHAoJZm9yQ3VzdG9tGBMgASgIUglmb3JDdXN0b20S'\n    'IQoEaWNvbhgVIAEoCzINLmRvdXlpbi5JbWFnZVIEaWNvbhIeCgphY3Rpb25UeXBlGBYgASgNUg'\n    'phY3Rpb25UeXBl');\n\n@$core.Deprecated('Use giftIMPriorityDescriptor instead')\nconst GiftIMPriority$json = {\n  '1': 'GiftIMPriority',\n  '2': [\n    {'1': 'queueSizesList', '3': 1, '4': 3, '5': 4, '10': 'queueSizesList'},\n    {\n      '1': 'selfQueuePriority',\n      '3': 2,\n      '4': 1,\n      '5': 4,\n      '10': 'selfQueuePriority'\n    },\n    {'1': 'priority', '3': 3, '4': 1, '5': 4, '10': 'priority'},\n  ],\n};\n\n/// Descriptor for `GiftIMPriority`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List giftIMPriorityDescriptor = $convert.base64Decode(\n    'Cg5HaWZ0SU1Qcmlvcml0eRImCg5xdWV1ZVNpemVzTGlzdBgBIAMoBFIOcXVldWVTaXplc0xpc3'\n    'QSLAoRc2VsZlF1ZXVlUHJpb3JpdHkYAiABKARSEXNlbGZRdWV1ZVByaW9yaXR5EhoKCHByaW9y'\n    'aXR5GAMgASgEUghwcmlvcml0eQ==');\n\n@$core.Deprecated('Use textEffectDescriptor instead')\nconst TextEffect$json = {\n  '1': 'TextEffect',\n  '2': [\n    {\n      '1': 'portrait',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextEffectDetail',\n      '10': 'portrait'\n    },\n    {\n      '1': 'landscape',\n      '3': 2,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextEffectDetail',\n      '10': 'landscape'\n    },\n  ],\n};\n\n/// Descriptor for `TextEffect`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textEffectDescriptor = $convert.base64Decode(\n    'CgpUZXh0RWZmZWN0EjQKCHBvcnRyYWl0GAEgASgLMhguZG91eWluLlRleHRFZmZlY3REZXRhaW'\n    'xSCHBvcnRyYWl0EjYKCWxhbmRzY2FwZRgCIAEoCzIYLmRvdXlpbi5UZXh0RWZmZWN0RGV0YWls'\n    'UglsYW5kc2NhcGU=');\n\n@$core.Deprecated('Use textEffectDetailDescriptor instead')\nconst TextEffectDetail$json = {\n  '1': 'TextEffectDetail',\n  '2': [\n    {'1': 'text', '3': 1, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'text'},\n    {'1': 'textFontSize', '3': 2, '4': 1, '5': 13, '10': 'textFontSize'},\n    {\n      '1': 'background',\n      '3': 3,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'background'\n    },\n    {'1': 'start', '3': 4, '4': 1, '5': 13, '10': 'start'},\n    {'1': 'duration', '3': 5, '4': 1, '5': 13, '10': 'duration'},\n    {'1': 'x', '3': 6, '4': 1, '5': 13, '10': 'x'},\n    {'1': 'y', '3': 7, '4': 1, '5': 13, '10': 'y'},\n    {'1': 'width', '3': 8, '4': 1, '5': 13, '10': 'width'},\n    {'1': 'height', '3': 9, '4': 1, '5': 13, '10': 'height'},\n    {'1': 'shadowDx', '3': 10, '4': 1, '5': 13, '10': 'shadowDx'},\n    {'1': 'shadowDy', '3': 11, '4': 1, '5': 13, '10': 'shadowDy'},\n    {'1': 'shadowRadius', '3': 12, '4': 1, '5': 13, '10': 'shadowRadius'},\n    {'1': 'shadowColor', '3': 13, '4': 1, '5': 9, '10': 'shadowColor'},\n    {'1': 'strokeColor', '3': 14, '4': 1, '5': 9, '10': 'strokeColor'},\n    {'1': 'strokeWidth', '3': 15, '4': 1, '5': 13, '10': 'strokeWidth'},\n  ],\n};\n\n/// Descriptor for `TextEffectDetail`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textEffectDetailDescriptor = $convert.base64Decode(\n    'ChBUZXh0RWZmZWN0RGV0YWlsEiAKBHRleHQYASABKAsyDC5kb3V5aW4uVGV4dFIEdGV4dBIiCg'\n    'x0ZXh0Rm9udFNpemUYAiABKA1SDHRleHRGb250U2l6ZRItCgpiYWNrZ3JvdW5kGAMgASgLMg0u'\n    'ZG91eWluLkltYWdlUgpiYWNrZ3JvdW5kEhQKBXN0YXJ0GAQgASgNUgVzdGFydBIaCghkdXJhdG'\n    'lvbhgFIAEoDVIIZHVyYXRpb24SDAoBeBgGIAEoDVIBeBIMCgF5GAcgASgNUgF5EhQKBXdpZHRo'\n    'GAggASgNUgV3aWR0aBIWCgZoZWlnaHQYCSABKA1SBmhlaWdodBIaCghzaGFkb3dEeBgKIAEoDV'\n    'IIc2hhZG93RHgSGgoIc2hhZG93RHkYCyABKA1SCHNoYWRvd0R5EiIKDHNoYWRvd1JhZGl1cxgM'\n    'IAEoDVIMc2hhZG93UmFkaXVzEiAKC3NoYWRvd0NvbG9yGA0gASgJUgtzaGFkb3dDb2xvchIgCg'\n    'tzdHJva2VDb2xvchgOIAEoCVILc3Ryb2tlQ29sb3ISIAoLc3Ryb2tlV2lkdGgYDyABKA1SC3N0'\n    'cm9rZVdpZHRo');\n\n@$core.Deprecated('Use memberMessageDescriptor instead')\nconst MemberMessage$json = {\n  '1': 'MemberMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'memberCount', '3': 3, '4': 1, '5': 4, '10': 'memberCount'},\n    {\n      '1': 'operator',\n      '3': 4,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.User',\n      '10': 'operator'\n    },\n    {'1': 'isSetToAdmin', '3': 5, '4': 1, '5': 8, '10': 'isSetToAdmin'},\n    {'1': 'isTopUser', '3': 6, '4': 1, '5': 8, '10': 'isTopUser'},\n    {'1': 'rankScore', '3': 7, '4': 1, '5': 4, '10': 'rankScore'},\n    {'1': 'topUserNo', '3': 8, '4': 1, '5': 4, '10': 'topUserNo'},\n    {'1': 'enterType', '3': 9, '4': 1, '5': 4, '10': 'enterType'},\n    {'1': 'action', '3': 10, '4': 1, '5': 4, '10': 'action'},\n    {\n      '1': 'actionDescription',\n      '3': 11,\n      '4': 1,\n      '5': 9,\n      '10': 'actionDescription'\n    },\n    {'1': 'userId', '3': 12, '4': 1, '5': 4, '10': 'userId'},\n    {\n      '1': 'effectConfig',\n      '3': 13,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.EffectConfig',\n      '10': 'effectConfig'\n    },\n    {'1': 'popStr', '3': 14, '4': 1, '5': 9, '10': 'popStr'},\n    {\n      '1': 'enterEffectConfig',\n      '3': 15,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.EffectConfig',\n      '10': 'enterEffectConfig'\n    },\n    {\n      '1': 'backgroundImage',\n      '3': 16,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'backgroundImage'\n    },\n    {\n      '1': 'backgroundImageV2',\n      '3': 17,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'backgroundImageV2'\n    },\n    {\n      '1': 'anchorDisplayText',\n      '3': 18,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Text',\n      '10': 'anchorDisplayText'\n    },\n    {\n      '1': 'publicAreaCommon',\n      '3': 19,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PublicAreaCommon',\n      '10': 'publicAreaCommon'\n    },\n    {\n      '1': 'userEnterTipType',\n      '3': 20,\n      '4': 1,\n      '5': 4,\n      '10': 'userEnterTipType'\n    },\n    {\n      '1': 'anchorEnterTipType',\n      '3': 21,\n      '4': 1,\n      '5': 4,\n      '10': 'anchorEnterTipType'\n    },\n  ],\n};\n\n/// Descriptor for `MemberMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List memberMessageDescriptor = $convert.base64Decode(\n    'Cg1NZW1iZXJNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb25SBmNvbW1vbh'\n    'IgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISIAoLbWVtYmVyQ291bnQYAyABKARS'\n    'C21lbWJlckNvdW50EigKCG9wZXJhdG9yGAQgASgLMgwuZG91eWluLlVzZXJSCG9wZXJhdG9yEi'\n    'IKDGlzU2V0VG9BZG1pbhgFIAEoCFIMaXNTZXRUb0FkbWluEhwKCWlzVG9wVXNlchgGIAEoCFIJ'\n    'aXNUb3BVc2VyEhwKCXJhbmtTY29yZRgHIAEoBFIJcmFua1Njb3JlEhwKCXRvcFVzZXJObxgIIA'\n    'EoBFIJdG9wVXNlck5vEhwKCWVudGVyVHlwZRgJIAEoBFIJZW50ZXJUeXBlEhYKBmFjdGlvbhgK'\n    'IAEoBFIGYWN0aW9uEiwKEWFjdGlvbkRlc2NyaXB0aW9uGAsgASgJUhFhY3Rpb25EZXNjcmlwdG'\n    'lvbhIWCgZ1c2VySWQYDCABKARSBnVzZXJJZBI4CgxlZmZlY3RDb25maWcYDSABKAsyFC5kb3V5'\n    'aW4uRWZmZWN0Q29uZmlnUgxlZmZlY3RDb25maWcSFgoGcG9wU3RyGA4gASgJUgZwb3BTdHISQg'\n    'oRZW50ZXJFZmZlY3RDb25maWcYDyABKAsyFC5kb3V5aW4uRWZmZWN0Q29uZmlnUhFlbnRlckVm'\n    'ZmVjdENvbmZpZxI3Cg9iYWNrZ3JvdW5kSW1hZ2UYECABKAsyDS5kb3V5aW4uSW1hZ2VSD2JhY2'\n    'tncm91bmRJbWFnZRI7ChFiYWNrZ3JvdW5kSW1hZ2VWMhgRIAEoCzINLmRvdXlpbi5JbWFnZVIR'\n    'YmFja2dyb3VuZEltYWdlVjISOgoRYW5jaG9yRGlzcGxheVRleHQYEiABKAsyDC5kb3V5aW4uVG'\n    'V4dFIRYW5jaG9yRGlzcGxheVRleHQSRAoQcHVibGljQXJlYUNvbW1vbhgTIAEoCzIYLmRvdXlp'\n    'bi5QdWJsaWNBcmVhQ29tbW9uUhBwdWJsaWNBcmVhQ29tbW9uEioKEHVzZXJFbnRlclRpcFR5cG'\n    'UYFCABKARSEHVzZXJFbnRlclRpcFR5cGUSLgoSYW5jaG9yRW50ZXJUaXBUeXBlGBUgASgEUhJh'\n    'bmNob3JFbnRlclRpcFR5cGU=');\n\n@$core.Deprecated('Use publicAreaCommonDescriptor instead')\nconst PublicAreaCommon$json = {\n  '1': 'PublicAreaCommon',\n  '2': [\n    {\n      '1': 'userLabel',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'userLabel'\n    },\n    {\n      '1': 'userConsumeInRoom',\n      '3': 2,\n      '4': 1,\n      '5': 4,\n      '10': 'userConsumeInRoom'\n    },\n    {\n      '1': 'userSendGiftCntInRoom',\n      '3': 3,\n      '4': 1,\n      '5': 4,\n      '10': 'userSendGiftCntInRoom'\n    },\n  ],\n};\n\n/// Descriptor for `PublicAreaCommon`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List publicAreaCommonDescriptor = $convert.base64Decode(\n    'ChBQdWJsaWNBcmVhQ29tbW9uEisKCXVzZXJMYWJlbBgBIAEoCzINLmRvdXlpbi5JbWFnZVIJdX'\n    'NlckxhYmVsEiwKEXVzZXJDb25zdW1lSW5Sb29tGAIgASgEUhF1c2VyQ29uc3VtZUluUm9vbRI0'\n    'ChV1c2VyU2VuZEdpZnRDbnRJblJvb20YAyABKARSFXVzZXJTZW5kR2lmdENudEluUm9vbQ==');\n\n@$core.Deprecated('Use effectConfigDescriptor instead')\nconst EffectConfig$json = {\n  '1': 'EffectConfig',\n  '2': [\n    {'1': 'type', '3': 1, '4': 1, '5': 4, '10': 'type'},\n    {'1': 'icon', '3': 2, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'icon'},\n    {'1': 'avatarPos', '3': 3, '4': 1, '5': 4, '10': 'avatarPos'},\n    {'1': 'text', '3': 4, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'text'},\n    {\n      '1': 'textIcon',\n      '3': 5,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'textIcon'\n    },\n    {'1': 'stayTime', '3': 6, '4': 1, '5': 13, '10': 'stayTime'},\n    {'1': 'animAssetId', '3': 7, '4': 1, '5': 4, '10': 'animAssetId'},\n    {\n      '1': 'badge',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'badge'\n    },\n    {\n      '1': 'flexSettingArrayList',\n      '3': 9,\n      '4': 3,\n      '5': 4,\n      '10': 'flexSettingArrayList'\n    },\n    {\n      '1': 'textIconOverlay',\n      '3': 10,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'textIconOverlay'\n    },\n    {\n      '1': 'animatedBadge',\n      '3': 11,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'animatedBadge'\n    },\n    {'1': 'hasSweepLight', '3': 12, '4': 1, '5': 8, '10': 'hasSweepLight'},\n    {\n      '1': 'textFlexSettingArrayList',\n      '3': 13,\n      '4': 3,\n      '5': 4,\n      '10': 'textFlexSettingArrayList'\n    },\n    {\n      '1': 'centerAnimAssetId',\n      '3': 14,\n      '4': 1,\n      '5': 4,\n      '10': 'centerAnimAssetId'\n    },\n    {\n      '1': 'dynamicImage',\n      '3': 15,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'dynamicImage'\n    },\n    {\n      '1': 'extraMap',\n      '3': 16,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.EffectConfig.ExtraMapEntry',\n      '10': 'extraMap'\n    },\n    {'1': 'mp4AnimAssetId', '3': 17, '4': 1, '5': 4, '10': 'mp4AnimAssetId'},\n    {'1': 'priority', '3': 18, '4': 1, '5': 4, '10': 'priority'},\n    {'1': 'maxWaitTime', '3': 19, '4': 1, '5': 4, '10': 'maxWaitTime'},\n    {'1': 'dressId', '3': 20, '4': 1, '5': 9, '10': 'dressId'},\n    {'1': 'alignment', '3': 21, '4': 1, '5': 4, '10': 'alignment'},\n    {'1': 'alignmentOffset', '3': 22, '4': 1, '5': 4, '10': 'alignmentOffset'},\n  ],\n  '3': [EffectConfig_ExtraMapEntry$json],\n};\n\n@$core.Deprecated('Use effectConfigDescriptor instead')\nconst EffectConfig_ExtraMapEntry$json = {\n  '1': 'ExtraMapEntry',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},\n  ],\n  '7': {'7': true},\n};\n\n/// Descriptor for `EffectConfig`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List effectConfigDescriptor = $convert.base64Decode(\n    'CgxFZmZlY3RDb25maWcSEgoEdHlwZRgBIAEoBFIEdHlwZRIhCgRpY29uGAIgASgLMg0uZG91eW'\n    'luLkltYWdlUgRpY29uEhwKCWF2YXRhclBvcxgDIAEoBFIJYXZhdGFyUG9zEiAKBHRleHQYBCAB'\n    'KAsyDC5kb3V5aW4uVGV4dFIEdGV4dBIpCgh0ZXh0SWNvbhgFIAEoCzINLmRvdXlpbi5JbWFnZV'\n    'IIdGV4dEljb24SGgoIc3RheVRpbWUYBiABKA1SCHN0YXlUaW1lEiAKC2FuaW1Bc3NldElkGAcg'\n    'ASgEUgthbmltQXNzZXRJZBIjCgViYWRnZRgIIAEoCzINLmRvdXlpbi5JbWFnZVIFYmFkZ2USMg'\n    'oUZmxleFNldHRpbmdBcnJheUxpc3QYCSADKARSFGZsZXhTZXR0aW5nQXJyYXlMaXN0EjcKD3Rl'\n    'eHRJY29uT3ZlcmxheRgKIAEoCzINLmRvdXlpbi5JbWFnZVIPdGV4dEljb25PdmVybGF5EjMKDW'\n    'FuaW1hdGVkQmFkZ2UYCyABKAsyDS5kb3V5aW4uSW1hZ2VSDWFuaW1hdGVkQmFkZ2USJAoNaGFz'\n    'U3dlZXBMaWdodBgMIAEoCFINaGFzU3dlZXBMaWdodBI6Chh0ZXh0RmxleFNldHRpbmdBcnJheU'\n    'xpc3QYDSADKARSGHRleHRGbGV4U2V0dGluZ0FycmF5TGlzdBIsChFjZW50ZXJBbmltQXNzZXRJ'\n    'ZBgOIAEoBFIRY2VudGVyQW5pbUFzc2V0SWQSMQoMZHluYW1pY0ltYWdlGA8gASgLMg0uZG91eW'\n    'luLkltYWdlUgxkeW5hbWljSW1hZ2USPgoIZXh0cmFNYXAYECADKAsyIi5kb3V5aW4uRWZmZWN0'\n    'Q29uZmlnLkV4dHJhTWFwRW50cnlSCGV4dHJhTWFwEiYKDm1wNEFuaW1Bc3NldElkGBEgASgEUg'\n    '5tcDRBbmltQXNzZXRJZBIaCghwcmlvcml0eRgSIAEoBFIIcHJpb3JpdHkSIAoLbWF4V2FpdFRp'\n    'bWUYEyABKARSC21heFdhaXRUaW1lEhgKB2RyZXNzSWQYFCABKAlSB2RyZXNzSWQSHAoJYWxpZ2'\n    '5tZW50GBUgASgEUglhbGlnbm1lbnQSKAoPYWxpZ25tZW50T2Zmc2V0GBYgASgEUg9hbGlnbm1l'\n    'bnRPZmZzZXQaOwoNRXh0cmFNYXBFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIA'\n    'EoCVIFdmFsdWU6AjgB');\n\n@$core.Deprecated('Use textDescriptor instead')\nconst Text$json = {\n  '1': 'Text',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'defaultPatter', '3': 2, '4': 1, '5': 9, '10': 'defaultPatter'},\n    {\n      '1': 'defaultFormat',\n      '3': 3,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextFormat',\n      '10': 'defaultFormat'\n    },\n    {\n      '1': 'piecesList',\n      '3': 4,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.TextPiece',\n      '10': 'piecesList'\n    },\n  ],\n};\n\n/// Descriptor for `Text`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textDescriptor = $convert.base64Decode(\n    'CgRUZXh0EhAKA2tleRgBIAEoCVIDa2V5EiQKDWRlZmF1bHRQYXR0ZXIYAiABKAlSDWRlZmF1bH'\n    'RQYXR0ZXISOAoNZGVmYXVsdEZvcm1hdBgDIAEoCzISLmRvdXlpbi5UZXh0Rm9ybWF0Ug1kZWZh'\n    'dWx0Rm9ybWF0EjEKCnBpZWNlc0xpc3QYBCADKAsyES5kb3V5aW4uVGV4dFBpZWNlUgpwaWVjZX'\n    'NMaXN0');\n\n@$core.Deprecated('Use textPieceDescriptor instead')\nconst TextPiece$json = {\n  '1': 'TextPiece',\n  '2': [\n    {'1': 'type', '3': 1, '4': 1, '5': 8, '10': 'type'},\n    {\n      '1': 'format',\n      '3': 2,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextFormat',\n      '10': 'format'\n    },\n    {'1': 'stringValue', '3': 3, '4': 1, '5': 9, '10': 'stringValue'},\n    {\n      '1': 'userValue',\n      '3': 4,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextPieceUser',\n      '10': 'userValue'\n    },\n    {\n      '1': 'giftValue',\n      '3': 5,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextPieceGift',\n      '10': 'giftValue'\n    },\n    {\n      '1': 'heartValue',\n      '3': 6,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextPieceHeart',\n      '10': 'heartValue'\n    },\n    {\n      '1': 'patternRefValue',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextPiecePatternRef',\n      '10': 'patternRefValue'\n    },\n    {\n      '1': 'imageValue',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.TextPieceImage',\n      '10': 'imageValue'\n    },\n  ],\n};\n\n/// Descriptor for `TextPiece`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPieceDescriptor = $convert.base64Decode(\n    'CglUZXh0UGllY2USEgoEdHlwZRgBIAEoCFIEdHlwZRIqCgZmb3JtYXQYAiABKAsyEi5kb3V5aW'\n    '4uVGV4dEZvcm1hdFIGZm9ybWF0EiAKC3N0cmluZ1ZhbHVlGAMgASgJUgtzdHJpbmdWYWx1ZRIz'\n    'Cgl1c2VyVmFsdWUYBCABKAsyFS5kb3V5aW4uVGV4dFBpZWNlVXNlclIJdXNlclZhbHVlEjMKCW'\n    'dpZnRWYWx1ZRgFIAEoCzIVLmRvdXlpbi5UZXh0UGllY2VHaWZ0UglnaWZ0VmFsdWUSNgoKaGVh'\n    'cnRWYWx1ZRgGIAEoCzIWLmRvdXlpbi5UZXh0UGllY2VIZWFydFIKaGVhcnRWYWx1ZRJFCg9wYX'\n    'R0ZXJuUmVmVmFsdWUYByABKAsyGy5kb3V5aW4uVGV4dFBpZWNlUGF0dGVyblJlZlIPcGF0dGVy'\n    'blJlZlZhbHVlEjYKCmltYWdlVmFsdWUYCCABKAsyFi5kb3V5aW4uVGV4dFBpZWNlSW1hZ2VSCm'\n    'ltYWdlVmFsdWU=');\n\n@$core.Deprecated('Use textPieceImageDescriptor instead')\nconst TextPieceImage$json = {\n  '1': 'TextPieceImage',\n  '2': [\n    {\n      '1': 'image',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'image'\n    },\n    {'1': 'scalingRate', '3': 2, '4': 1, '5': 2, '10': 'scalingRate'},\n  ],\n};\n\n/// Descriptor for `TextPieceImage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPieceImageDescriptor = $convert.base64Decode(\n    'Cg5UZXh0UGllY2VJbWFnZRIjCgVpbWFnZRgBIAEoCzINLmRvdXlpbi5JbWFnZVIFaW1hZ2USIA'\n    'oLc2NhbGluZ1JhdGUYAiABKAJSC3NjYWxpbmdSYXRl');\n\n@$core.Deprecated('Use textPiecePatternRefDescriptor instead')\nconst TextPiecePatternRef$json = {\n  '1': 'TextPiecePatternRef',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'defaultPattern', '3': 2, '4': 1, '5': 9, '10': 'defaultPattern'},\n  ],\n};\n\n/// Descriptor for `TextPiecePatternRef`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPiecePatternRefDescriptor = $convert.base64Decode(\n    'ChNUZXh0UGllY2VQYXR0ZXJuUmVmEhAKA2tleRgBIAEoCVIDa2V5EiYKDmRlZmF1bHRQYXR0ZX'\n    'JuGAIgASgJUg5kZWZhdWx0UGF0dGVybg==');\n\n@$core.Deprecated('Use textPieceHeartDescriptor instead')\nconst TextPieceHeart$json = {\n  '1': 'TextPieceHeart',\n  '2': [\n    {'1': 'color', '3': 1, '4': 1, '5': 9, '10': 'color'},\n  ],\n};\n\n/// Descriptor for `TextPieceHeart`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPieceHeartDescriptor = $convert\n    .base64Decode('Cg5UZXh0UGllY2VIZWFydBIUCgVjb2xvchgBIAEoCVIFY29sb3I=');\n\n@$core.Deprecated('Use textPieceGiftDescriptor instead')\nconst TextPieceGift$json = {\n  '1': 'TextPieceGift',\n  '2': [\n    {'1': 'giftId', '3': 1, '4': 1, '5': 4, '10': 'giftId'},\n    {\n      '1': 'nameRef',\n      '3': 2,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PatternRef',\n      '10': 'nameRef'\n    },\n  ],\n};\n\n/// Descriptor for `TextPieceGift`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPieceGiftDescriptor = $convert.base64Decode(\n    'Cg1UZXh0UGllY2VHaWZ0EhYKBmdpZnRJZBgBIAEoBFIGZ2lmdElkEiwKB25hbWVSZWYYAiABKA'\n    'syEi5kb3V5aW4uUGF0dGVyblJlZlIHbmFtZVJlZg==');\n\n@$core.Deprecated('Use patternRefDescriptor instead')\nconst PatternRef$json = {\n  '1': 'PatternRef',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'defaultPattern', '3': 2, '4': 1, '5': 9, '10': 'defaultPattern'},\n  ],\n};\n\n/// Descriptor for `PatternRef`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List patternRefDescriptor = $convert.base64Decode(\n    'CgpQYXR0ZXJuUmVmEhAKA2tleRgBIAEoCVIDa2V5EiYKDmRlZmF1bHRQYXR0ZXJuGAIgASgJUg'\n    '5kZWZhdWx0UGF0dGVybg==');\n\n@$core.Deprecated('Use textPieceUserDescriptor instead')\nconst TextPieceUser$json = {\n  '1': 'TextPieceUser',\n  '2': [\n    {'1': 'user', '3': 1, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'withColon', '3': 2, '4': 1, '5': 8, '10': 'withColon'},\n  ],\n};\n\n/// Descriptor for `TextPieceUser`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textPieceUserDescriptor = $convert.base64Decode(\n    'Cg1UZXh0UGllY2VVc2VyEiAKBHVzZXIYASABKAsyDC5kb3V5aW4uVXNlclIEdXNlchIcCgl3aX'\n    'RoQ29sb24YAiABKAhSCXdpdGhDb2xvbg==');\n\n@$core.Deprecated('Use textFormatDescriptor instead')\nconst TextFormat$json = {\n  '1': 'TextFormat',\n  '2': [\n    {'1': 'color', '3': 1, '4': 1, '5': 9, '10': 'color'},\n    {'1': 'bold', '3': 2, '4': 1, '5': 8, '10': 'bold'},\n    {'1': 'italic', '3': 3, '4': 1, '5': 8, '10': 'italic'},\n    {'1': 'weight', '3': 4, '4': 1, '5': 13, '10': 'weight'},\n    {'1': 'italicAngle', '3': 5, '4': 1, '5': 13, '10': 'italicAngle'},\n    {'1': 'fontSize', '3': 6, '4': 1, '5': 13, '10': 'fontSize'},\n    {\n      '1': 'useHeighLightColor',\n      '3': 7,\n      '4': 1,\n      '5': 8,\n      '10': 'useHeighLightColor'\n    },\n    {'1': 'useRemoteClor', '3': 8, '4': 1, '5': 8, '10': 'useRemoteClor'},\n  ],\n};\n\n/// Descriptor for `TextFormat`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List textFormatDescriptor = $convert.base64Decode(\n    'CgpUZXh0Rm9ybWF0EhQKBWNvbG9yGAEgASgJUgVjb2xvchISCgRib2xkGAIgASgIUgRib2xkEh'\n    'YKBml0YWxpYxgDIAEoCFIGaXRhbGljEhYKBndlaWdodBgEIAEoDVIGd2VpZ2h0EiAKC2l0YWxp'\n    'Y0FuZ2xlGAUgASgNUgtpdGFsaWNBbmdsZRIaCghmb250U2l6ZRgGIAEoDVIIZm9udFNpemUSLg'\n    'oSdXNlSGVpZ2hMaWdodENvbG9yGAcgASgIUhJ1c2VIZWlnaExpZ2h0Q29sb3ISJAoNdXNlUmVt'\n    'b3RlQ2xvchgIIAEoCFINdXNlUmVtb3RlQ2xvcg==');\n\n@$core.Deprecated('Use likeMessageDescriptor instead')\nconst LikeMessage$json = {\n  '1': 'LikeMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'count', '3': 2, '4': 1, '5': 4, '10': 'count'},\n    {'1': 'total', '3': 3, '4': 1, '5': 4, '10': 'total'},\n    {'1': 'color', '3': 4, '4': 1, '5': 4, '10': 'color'},\n    {'1': 'user', '3': 5, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'icon', '3': 6, '4': 1, '5': 9, '10': 'icon'},\n    {\n      '1': 'doubleLikeDetail',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.DoubleLikeDetail',\n      '10': 'doubleLikeDetail'\n    },\n    {\n      '1': 'displayControlInfo',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.DisplayControlInfo',\n      '10': 'displayControlInfo'\n    },\n    {'1': 'linkmicGuestUid', '3': 9, '4': 1, '5': 4, '10': 'linkmicGuestUid'},\n    {'1': 'scene', '3': 10, '4': 1, '5': 9, '10': 'scene'},\n    {\n      '1': 'picoDisplayInfo',\n      '3': 11,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PicoDisplayInfo',\n      '10': 'picoDisplayInfo'\n    },\n  ],\n};\n\n/// Descriptor for `LikeMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List likeMessageDescriptor = $convert.base64Decode(\n    'CgtMaWtlTWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SFA'\n    'oFY291bnQYAiABKARSBWNvdW50EhQKBXRvdGFsGAMgASgEUgV0b3RhbBIUCgVjb2xvchgEIAEo'\n    'BFIFY29sb3ISIAoEdXNlchgFIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhIKBGljb24YBiABKA'\n    'lSBGljb24SRAoQZG91YmxlTGlrZURldGFpbBgHIAEoCzIYLmRvdXlpbi5Eb3VibGVMaWtlRGV0'\n    'YWlsUhBkb3VibGVMaWtlRGV0YWlsEkoKEmRpc3BsYXlDb250cm9sSW5mbxgIIAEoCzIaLmRvdX'\n    'lpbi5EaXNwbGF5Q29udHJvbEluZm9SEmRpc3BsYXlDb250cm9sSW5mbxIoCg9saW5rbWljR3Vl'\n    'c3RVaWQYCSABKARSD2xpbmttaWNHdWVzdFVpZBIUCgVzY2VuZRgKIAEoCVIFc2NlbmUSQQoPcG'\n    'ljb0Rpc3BsYXlJbmZvGAsgASgLMhcuZG91eWluLlBpY29EaXNwbGF5SW5mb1IPcGljb0Rpc3Bs'\n    'YXlJbmZv');\n\n@$core.Deprecated('Use socialMessageDescriptor instead')\nconst SocialMessage$json = {\n  '1': 'SocialMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'shareType', '3': 3, '4': 1, '5': 4, '10': 'shareType'},\n    {'1': 'action', '3': 4, '4': 1, '5': 4, '10': 'action'},\n    {'1': 'shareTarget', '3': 5, '4': 1, '5': 9, '10': 'shareTarget'},\n    {'1': 'followCount', '3': 6, '4': 1, '5': 4, '10': 'followCount'},\n    {\n      '1': 'publicAreaCommon',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.PublicAreaCommon',\n      '10': 'publicAreaCommon'\n    },\n  ],\n};\n\n/// Descriptor for `SocialMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List socialMessageDescriptor = $convert.base64Decode(\n    'Cg1Tb2NpYWxNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb25SBmNvbW1vbh'\n    'IgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISHAoJc2hhcmVUeXBlGAMgASgEUglz'\n    'aGFyZVR5cGUSFgoGYWN0aW9uGAQgASgEUgZhY3Rpb24SIAoLc2hhcmVUYXJnZXQYBSABKAlSC3'\n    'NoYXJlVGFyZ2V0EiAKC2ZvbGxvd0NvdW50GAYgASgEUgtmb2xsb3dDb3VudBJEChBwdWJsaWNB'\n    'cmVhQ29tbW9uGAcgASgLMhguZG91eWluLlB1YmxpY0FyZWFDb21tb25SEHB1YmxpY0FyZWFDb2'\n    '1tb24=');\n\n@$core.Deprecated('Use picoDisplayInfoDescriptor instead')\nconst PicoDisplayInfo$json = {\n  '1': 'PicoDisplayInfo',\n  '2': [\n    {'1': 'comboSumCount', '3': 1, '4': 1, '5': 4, '10': 'comboSumCount'},\n    {'1': 'emoji', '3': 2, '4': 1, '5': 9, '10': 'emoji'},\n    {\n      '1': 'emojiIcon',\n      '3': 3,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'emojiIcon'\n    },\n    {'1': 'emojiText', '3': 4, '4': 1, '5': 9, '10': 'emojiText'},\n  ],\n};\n\n/// Descriptor for `PicoDisplayInfo`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List picoDisplayInfoDescriptor = $convert.base64Decode(\n    'Cg9QaWNvRGlzcGxheUluZm8SJAoNY29tYm9TdW1Db3VudBgBIAEoBFINY29tYm9TdW1Db3VudB'\n    'IUCgVlbW9qaRgCIAEoCVIFZW1vamkSKwoJZW1vamlJY29uGAMgASgLMg0uZG91eWluLkltYWdl'\n    'UgllbW9qaUljb24SHAoJZW1vamlUZXh0GAQgASgJUgllbW9qaVRleHQ=');\n\n@$core.Deprecated('Use doubleLikeDetailDescriptor instead')\nconst DoubleLikeDetail$json = {\n  '1': 'DoubleLikeDetail',\n  '2': [\n    {'1': 'doubleFlag', '3': 1, '4': 1, '5': 8, '10': 'doubleFlag'},\n    {'1': 'seqId', '3': 2, '4': 1, '5': 13, '10': 'seqId'},\n    {'1': 'renewalsNum', '3': 3, '4': 1, '5': 13, '10': 'renewalsNum'},\n    {'1': 'triggersNum', '3': 4, '4': 1, '5': 13, '10': 'triggersNum'},\n  ],\n};\n\n/// Descriptor for `DoubleLikeDetail`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List doubleLikeDetailDescriptor = $convert.base64Decode(\n    'ChBEb3VibGVMaWtlRGV0YWlsEh4KCmRvdWJsZUZsYWcYASABKAhSCmRvdWJsZUZsYWcSFAoFc2'\n    'VxSWQYAiABKA1SBXNlcUlkEiAKC3JlbmV3YWxzTnVtGAMgASgNUgtyZW5ld2Fsc051bRIgCgt0'\n    'cmlnZ2Vyc051bRgEIAEoDVILdHJpZ2dlcnNOdW0=');\n\n@$core.Deprecated('Use displayControlInfoDescriptor instead')\nconst DisplayControlInfo$json = {\n  '1': 'DisplayControlInfo',\n  '2': [\n    {'1': 'showText', '3': 1, '4': 1, '5': 8, '10': 'showText'},\n    {'1': 'showIcons', '3': 2, '4': 1, '5': 8, '10': 'showIcons'},\n  ],\n};\n\n/// Descriptor for `DisplayControlInfo`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List displayControlInfoDescriptor = $convert.base64Decode(\n    'ChJEaXNwbGF5Q29udHJvbEluZm8SGgoIc2hvd1RleHQYASABKAhSCHNob3dUZXh0EhwKCXNob3'\n    'dJY29ucxgCIAEoCFIJc2hvd0ljb25z');\n\n@$core.Deprecated('Use episodeChatMessageDescriptor instead')\nconst EpisodeChatMessage$json = {\n  '1': 'EpisodeChatMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Message',\n      '10': 'common'\n    },\n    {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'},\n    {'1': 'visibleToSende', '3': 4, '4': 1, '5': 8, '10': 'visibleToSende'},\n    {\n      '1': 'giftImage',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'giftImage'\n    },\n    {'1': 'agreeMsgId', '3': 8, '4': 1, '5': 4, '10': 'agreeMsgId'},\n    {'1': 'colorValueList', '3': 9, '4': 3, '5': 9, '10': 'colorValueList'},\n  ],\n};\n\n/// Descriptor for `EpisodeChatMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List episodeChatMessageDescriptor = $convert.base64Decode(\n    'ChJFcGlzb2RlQ2hhdE1lc3NhZ2USJwoGY29tbW9uGAEgASgLMg8uZG91eWluLk1lc3NhZ2VSBm'\n    'NvbW1vbhIgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISGAoHY29udGVudBgDIAEo'\n    'CVIHY29udGVudBImCg52aXNpYmxlVG9TZW5kZRgEIAEoCFIOdmlzaWJsZVRvU2VuZGUSKwoJZ2'\n    'lmdEltYWdlGAcgASgLMg0uZG91eWluLkltYWdlUglnaWZ0SW1hZ2USHgoKYWdyZWVNc2dJZBgI'\n    'IAEoBFIKYWdyZWVNc2dJZBImCg5jb2xvclZhbHVlTGlzdBgJIAMoCVIOY29sb3JWYWx1ZUxpc3'\n    'Q=');\n\n@$core.Deprecated('Use matchAgainstScoreMessageDescriptor instead')\nconst MatchAgainstScoreMessage$json = {\n  '1': 'MatchAgainstScoreMessage',\n  '2': [\n    {\n      '1': 'common',\n      '3': 1,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Common',\n      '10': 'common'\n    },\n    {\n      '1': 'against',\n      '3': 2,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Against',\n      '10': 'against'\n    },\n    {'1': 'matchStatus', '3': 3, '4': 1, '5': 13, '10': 'matchStatus'},\n    {'1': 'displayStatus', '3': 4, '4': 1, '5': 13, '10': 'displayStatus'},\n  ],\n};\n\n/// Descriptor for `MatchAgainstScoreMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List matchAgainstScoreMessageDescriptor = $convert.base64Decode(\n    'ChhNYXRjaEFnYWluc3RTY29yZU1lc3NhZ2USJgoGY29tbW9uGAEgASgLMg4uZG91eWluLkNvbW'\n    '1vblIGY29tbW9uEikKB2FnYWluc3QYAiABKAsyDy5kb3V5aW4uQWdhaW5zdFIHYWdhaW5zdBIg'\n    'CgttYXRjaFN0YXR1cxgDIAEoDVILbWF0Y2hTdGF0dXMSJAoNZGlzcGxheVN0YXR1cxgEIAEoDV'\n    'INZGlzcGxheVN0YXR1cw==');\n\n@$core.Deprecated('Use againstDescriptor instead')\nconst Against$json = {\n  '1': 'Against',\n  '2': [\n    {'1': 'leftName', '3': 1, '4': 1, '5': 9, '10': 'leftName'},\n    {\n      '1': 'leftLogo',\n      '3': 2,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'leftLogo'\n    },\n    {'1': 'leftGoal', '3': 3, '4': 1, '5': 9, '10': 'leftGoal'},\n    {'1': 'rightName', '3': 6, '4': 1, '5': 9, '10': 'rightName'},\n    {\n      '1': 'rightLogo',\n      '3': 7,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'rightLogo'\n    },\n    {'1': 'rightGoal', '3': 8, '4': 1, '5': 9, '10': 'rightGoal'},\n    {'1': 'timestamp', '3': 11, '4': 1, '5': 4, '10': 'timestamp'},\n    {'1': 'version', '3': 12, '4': 1, '5': 4, '10': 'version'},\n    {'1': 'leftTeamId', '3': 13, '4': 1, '5': 4, '10': 'leftTeamId'},\n    {'1': 'rightTeamId', '3': 14, '4': 1, '5': 4, '10': 'rightTeamId'},\n    {\n      '1': 'diffSei2absSecond',\n      '3': 15,\n      '4': 1,\n      '5': 4,\n      '10': 'diffSei2absSecond'\n    },\n    {'1': 'finalGoalStage', '3': 16, '4': 1, '5': 13, '10': 'finalGoalStage'},\n    {\n      '1': 'currentGoalStage',\n      '3': 17,\n      '4': 1,\n      '5': 13,\n      '10': 'currentGoalStage'\n    },\n    {\n      '1': 'leftScoreAddition',\n      '3': 18,\n      '4': 1,\n      '5': 13,\n      '10': 'leftScoreAddition'\n    },\n    {\n      '1': 'rightScoreAddition',\n      '3': 19,\n      '4': 1,\n      '5': 13,\n      '10': 'rightScoreAddition'\n    },\n    {'1': 'leftGoalInt', '3': 20, '4': 1, '5': 4, '10': 'leftGoalInt'},\n    {'1': 'rightGoalInt', '3': 21, '4': 1, '5': 4, '10': 'rightGoalInt'},\n  ],\n};\n\n/// Descriptor for `Against`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List againstDescriptor = $convert.base64Decode(\n    'CgdBZ2FpbnN0EhoKCGxlZnROYW1lGAEgASgJUghsZWZ0TmFtZRIpCghsZWZ0TG9nbxgCIAEoCz'\n    'INLmRvdXlpbi5JbWFnZVIIbGVmdExvZ28SGgoIbGVmdEdvYWwYAyABKAlSCGxlZnRHb2FsEhwK'\n    'CXJpZ2h0TmFtZRgGIAEoCVIJcmlnaHROYW1lEisKCXJpZ2h0TG9nbxgHIAEoCzINLmRvdXlpbi'\n    '5JbWFnZVIJcmlnaHRMb2dvEhwKCXJpZ2h0R29hbBgIIAEoCVIJcmlnaHRHb2FsEhwKCXRpbWVz'\n    'dGFtcBgLIAEoBFIJdGltZXN0YW1wEhgKB3ZlcnNpb24YDCABKARSB3ZlcnNpb24SHgoKbGVmdF'\n    'RlYW1JZBgNIAEoBFIKbGVmdFRlYW1JZBIgCgtyaWdodFRlYW1JZBgOIAEoBFILcmlnaHRUZWFt'\n    'SWQSLAoRZGlmZlNlaTJhYnNTZWNvbmQYDyABKARSEWRpZmZTZWkyYWJzU2Vjb25kEiYKDmZpbm'\n    'FsR29hbFN0YWdlGBAgASgNUg5maW5hbEdvYWxTdGFnZRIqChBjdXJyZW50R29hbFN0YWdlGBEg'\n    'ASgNUhBjdXJyZW50R29hbFN0YWdlEiwKEWxlZnRTY29yZUFkZGl0aW9uGBIgASgNUhFsZWZ0U2'\n    'NvcmVBZGRpdGlvbhIuChJyaWdodFNjb3JlQWRkaXRpb24YEyABKA1SEnJpZ2h0U2NvcmVBZGRp'\n    'dGlvbhIgCgtsZWZ0R29hbEludBgUIAEoBFILbGVmdEdvYWxJbnQSIgoMcmlnaHRHb2FsSW50GB'\n    'UgASgEUgxyaWdodEdvYWxJbnQ=');\n\n@$core.Deprecated('Use commonDescriptor instead')\nconst Common$json = {\n  '1': 'Common',\n  '2': [\n    {'1': 'method', '3': 1, '4': 1, '5': 9, '10': 'method'},\n    {'1': 'msgId', '3': 2, '4': 1, '5': 4, '10': 'msgId'},\n    {'1': 'roomId', '3': 3, '4': 1, '5': 4, '10': 'roomId'},\n    {'1': 'createTime', '3': 4, '4': 1, '5': 4, '10': 'createTime'},\n    {'1': 'monitor', '3': 5, '4': 1, '5': 13, '10': 'monitor'},\n    {'1': 'isShowMsg', '3': 6, '4': 1, '5': 8, '10': 'isShowMsg'},\n    {'1': 'describe', '3': 7, '4': 1, '5': 9, '10': 'describe'},\n    {'1': 'foldType', '3': 9, '4': 1, '5': 4, '10': 'foldType'},\n    {'1': 'anchorFoldType', '3': 10, '4': 1, '5': 4, '10': 'anchorFoldType'},\n    {'1': 'priorityScore', '3': 11, '4': 1, '5': 4, '10': 'priorityScore'},\n    {'1': 'logId', '3': 12, '4': 1, '5': 9, '10': 'logId'},\n    {\n      '1': 'msgProcessFilterK',\n      '3': 13,\n      '4': 1,\n      '5': 9,\n      '10': 'msgProcessFilterK'\n    },\n    {\n      '1': 'msgProcessFilterV',\n      '3': 14,\n      '4': 1,\n      '5': 9,\n      '10': 'msgProcessFilterV'\n    },\n    {'1': 'user', '3': 15, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'},\n    {\n      '1': 'anchorFoldTypeV2',\n      '3': 17,\n      '4': 1,\n      '5': 4,\n      '10': 'anchorFoldTypeV2'\n    },\n    {\n      '1': 'processAtSeiTimeMs',\n      '3': 18,\n      '4': 1,\n      '5': 4,\n      '10': 'processAtSeiTimeMs'\n    },\n    {\n      '1': 'randomDispatchMs',\n      '3': 19,\n      '4': 1,\n      '5': 4,\n      '10': 'randomDispatchMs'\n    },\n    {'1': 'isDispatch', '3': 20, '4': 1, '5': 8, '10': 'isDispatch'},\n    {'1': 'channelId', '3': 21, '4': 1, '5': 4, '10': 'channelId'},\n    {\n      '1': 'diffSei2absSecond',\n      '3': 22,\n      '4': 1,\n      '5': 4,\n      '10': 'diffSei2absSecond'\n    },\n    {\n      '1': 'anchorFoldDuration',\n      '3': 23,\n      '4': 1,\n      '5': 4,\n      '10': 'anchorFoldDuration'\n    },\n  ],\n};\n\n/// Descriptor for `Common`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List commonDescriptor = $convert.base64Decode(\n    'CgZDb21tb24SFgoGbWV0aG9kGAEgASgJUgZtZXRob2QSFAoFbXNnSWQYAiABKARSBW1zZ0lkEh'\n    'YKBnJvb21JZBgDIAEoBFIGcm9vbUlkEh4KCmNyZWF0ZVRpbWUYBCABKARSCmNyZWF0ZVRpbWUS'\n    'GAoHbW9uaXRvchgFIAEoDVIHbW9uaXRvchIcCglpc1Nob3dNc2cYBiABKAhSCWlzU2hvd01zZx'\n    'IaCghkZXNjcmliZRgHIAEoCVIIZGVzY3JpYmUSGgoIZm9sZFR5cGUYCSABKARSCGZvbGRUeXBl'\n    'EiYKDmFuY2hvckZvbGRUeXBlGAogASgEUg5hbmNob3JGb2xkVHlwZRIkCg1wcmlvcml0eVNjb3'\n    'JlGAsgASgEUg1wcmlvcml0eVNjb3JlEhQKBWxvZ0lkGAwgASgJUgVsb2dJZBIsChFtc2dQcm9j'\n    'ZXNzRmlsdGVySxgNIAEoCVIRbXNnUHJvY2Vzc0ZpbHRlcksSLAoRbXNnUHJvY2Vzc0ZpbHRlcl'\n    'YYDiABKAlSEW1zZ1Byb2Nlc3NGaWx0ZXJWEiAKBHVzZXIYDyABKAsyDC5kb3V5aW4uVXNlclIE'\n    'dXNlchIqChBhbmNob3JGb2xkVHlwZVYyGBEgASgEUhBhbmNob3JGb2xkVHlwZVYyEi4KEnByb2'\n    'Nlc3NBdFNlaVRpbWVNcxgSIAEoBFIScHJvY2Vzc0F0U2VpVGltZU1zEioKEHJhbmRvbURpc3Bh'\n    'dGNoTXMYEyABKARSEHJhbmRvbURpc3BhdGNoTXMSHgoKaXNEaXNwYXRjaBgUIAEoCFIKaXNEaX'\n    'NwYXRjaBIcCgljaGFubmVsSWQYFSABKARSCWNoYW5uZWxJZBIsChFkaWZmU2VpMmFic1NlY29u'\n    'ZBgWIAEoBFIRZGlmZlNlaTJhYnNTZWNvbmQSLgoSYW5jaG9yRm9sZER1cmF0aW9uGBcgASgEUh'\n    'JhbmNob3JGb2xkRHVyYXRpb24=');\n\n@$core.Deprecated('Use userDescriptor instead')\nconst User$json = {\n  '1': 'User',\n  '2': [\n    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},\n    {'1': 'shortId', '3': 2, '4': 1, '5': 4, '10': 'shortId'},\n    {'1': 'nickName', '3': 3, '4': 1, '5': 9, '10': 'nickName'},\n    {'1': 'gender', '3': 4, '4': 1, '5': 13, '10': 'gender'},\n    {'1': 'Signature', '3': 5, '4': 1, '5': 9, '10': 'Signature'},\n    {'1': 'Level', '3': 6, '4': 1, '5': 13, '10': 'Level'},\n    {'1': 'Birthday', '3': 7, '4': 1, '5': 4, '10': 'Birthday'},\n    {'1': 'Telephone', '3': 8, '4': 1, '5': 9, '10': 'Telephone'},\n    {\n      '1': 'AvatarThumb',\n      '3': 9,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'AvatarThumb'\n    },\n    {\n      '1': 'AvatarMedium',\n      '3': 10,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'AvatarMedium'\n    },\n    {\n      '1': 'AvatarLarge',\n      '3': 11,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'AvatarLarge'\n    },\n    {'1': 'Verified', '3': 12, '4': 1, '5': 8, '10': 'Verified'},\n    {'1': 'Experience', '3': 13, '4': 1, '5': 13, '10': 'Experience'},\n    {'1': 'city', '3': 14, '4': 1, '5': 9, '10': 'city'},\n    {'1': 'Status', '3': 15, '4': 1, '5': 5, '10': 'Status'},\n    {'1': 'CreateTime', '3': 16, '4': 1, '5': 4, '10': 'CreateTime'},\n    {'1': 'ModifyTime', '3': 17, '4': 1, '5': 4, '10': 'ModifyTime'},\n    {'1': 'Secret', '3': 18, '4': 1, '5': 13, '10': 'Secret'},\n    {'1': 'ShareQrcodeUri', '3': 19, '4': 1, '5': 9, '10': 'ShareQrcodeUri'},\n    {\n      '1': 'IncomeSharePercent',\n      '3': 20,\n      '4': 1,\n      '5': 13,\n      '10': 'IncomeSharePercent'\n    },\n    {\n      '1': 'BadgeImageList',\n      '3': 21,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'BadgeImageList'\n    },\n    {\n      '1': 'FollowInfo',\n      '3': 22,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.FollowInfo',\n      '10': 'FollowInfo'\n    },\n    {'1': 'SpecialId', '3': 26, '4': 1, '5': 9, '10': 'SpecialId'},\n    {\n      '1': 'AvatarBorder',\n      '3': 27,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'AvatarBorder'\n    },\n    {\n      '1': 'Medal',\n      '3': 28,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'Medal'\n    },\n    {\n      '1': 'RealTimeIconsList',\n      '3': 29,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.Image',\n      '10': 'RealTimeIconsList'\n    },\n    {'1': 'displayId', '3': 38, '4': 1, '5': 9, '10': 'displayId'},\n    {'1': 'secUid', '3': 46, '4': 1, '5': 9, '10': 'secUid'},\n    {'1': 'fanTicketCount', '3': 1022, '4': 1, '5': 4, '10': 'fanTicketCount'},\n    {'1': 'idStr', '3': 1028, '4': 1, '5': 9, '10': 'idStr'},\n    {'1': 'ageRange', '3': 1045, '4': 1, '5': 13, '10': 'ageRange'},\n  ],\n};\n\n/// Descriptor for `User`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List userDescriptor = $convert.base64Decode(\n    'CgRVc2VyEg4KAmlkGAEgASgEUgJpZBIYCgdzaG9ydElkGAIgASgEUgdzaG9ydElkEhoKCG5pY2'\n    'tOYW1lGAMgASgJUghuaWNrTmFtZRIWCgZnZW5kZXIYBCABKA1SBmdlbmRlchIcCglTaWduYXR1'\n    'cmUYBSABKAlSCVNpZ25hdHVyZRIUCgVMZXZlbBgGIAEoDVIFTGV2ZWwSGgoIQmlydGhkYXkYBy'\n    'ABKARSCEJpcnRoZGF5EhwKCVRlbGVwaG9uZRgIIAEoCVIJVGVsZXBob25lEi8KC0F2YXRhclRo'\n    'dW1iGAkgASgLMg0uZG91eWluLkltYWdlUgtBdmF0YXJUaHVtYhIxCgxBdmF0YXJNZWRpdW0YCi'\n    'ABKAsyDS5kb3V5aW4uSW1hZ2VSDEF2YXRhck1lZGl1bRIvCgtBdmF0YXJMYXJnZRgLIAEoCzIN'\n    'LmRvdXlpbi5JbWFnZVILQXZhdGFyTGFyZ2USGgoIVmVyaWZpZWQYDCABKAhSCFZlcmlmaWVkEh'\n    '4KCkV4cGVyaWVuY2UYDSABKA1SCkV4cGVyaWVuY2USEgoEY2l0eRgOIAEoCVIEY2l0eRIWCgZT'\n    'dGF0dXMYDyABKAVSBlN0YXR1cxIeCgpDcmVhdGVUaW1lGBAgASgEUgpDcmVhdGVUaW1lEh4KCk'\n    '1vZGlmeVRpbWUYESABKARSCk1vZGlmeVRpbWUSFgoGU2VjcmV0GBIgASgNUgZTZWNyZXQSJgoO'\n    'U2hhcmVRcmNvZGVVcmkYEyABKAlSDlNoYXJlUXJjb2RlVXJpEi4KEkluY29tZVNoYXJlUGVyY2'\n    'VudBgUIAEoDVISSW5jb21lU2hhcmVQZXJjZW50EjUKDkJhZGdlSW1hZ2VMaXN0GBUgAygLMg0u'\n    'ZG91eWluLkltYWdlUg5CYWRnZUltYWdlTGlzdBIyCgpGb2xsb3dJbmZvGBYgASgLMhIuZG91eW'\n    'luLkZvbGxvd0luZm9SCkZvbGxvd0luZm8SHAoJU3BlY2lhbElkGBogASgJUglTcGVjaWFsSWQS'\n    'MQoMQXZhdGFyQm9yZGVyGBsgASgLMg0uZG91eWluLkltYWdlUgxBdmF0YXJCb3JkZXISIwoFTW'\n    'VkYWwYHCABKAsyDS5kb3V5aW4uSW1hZ2VSBU1lZGFsEjsKEVJlYWxUaW1lSWNvbnNMaXN0GB0g'\n    'AygLMg0uZG91eWluLkltYWdlUhFSZWFsVGltZUljb25zTGlzdBIcCglkaXNwbGF5SWQYJiABKA'\n    'lSCWRpc3BsYXlJZBIWCgZzZWNVaWQYLiABKAlSBnNlY1VpZBInCg5mYW5UaWNrZXRDb3VudBj+'\n    'ByABKARSDmZhblRpY2tldENvdW50EhUKBWlkU3RyGIQIIAEoCVIFaWRTdHISGwoIYWdlUmFuZ2'\n    'UYlQggASgNUghhZ2VSYW5nZQ==');\n\n@$core.Deprecated('Use followInfoDescriptor instead')\nconst FollowInfo$json = {\n  '1': 'FollowInfo',\n  '2': [\n    {'1': 'followingCount', '3': 1, '4': 1, '5': 4, '10': 'followingCount'},\n    {'1': 'followerCount', '3': 2, '4': 1, '5': 4, '10': 'followerCount'},\n    {'1': 'followStatus', '3': 3, '4': 1, '5': 4, '10': 'followStatus'},\n    {'1': 'pushStatus', '3': 4, '4': 1, '5': 4, '10': 'pushStatus'},\n    {'1': 'remarkName', '3': 5, '4': 1, '5': 9, '10': 'remarkName'},\n    {'1': 'followerCountStr', '3': 6, '4': 1, '5': 9, '10': 'followerCountStr'},\n    {\n      '1': 'followingCountStr',\n      '3': 7,\n      '4': 1,\n      '5': 9,\n      '10': 'followingCountStr'\n    },\n  ],\n};\n\n/// Descriptor for `FollowInfo`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List followInfoDescriptor = $convert.base64Decode(\n    'CgpGb2xsb3dJbmZvEiYKDmZvbGxvd2luZ0NvdW50GAEgASgEUg5mb2xsb3dpbmdDb3VudBIkCg'\n    '1mb2xsb3dlckNvdW50GAIgASgEUg1mb2xsb3dlckNvdW50EiIKDGZvbGxvd1N0YXR1cxgDIAEo'\n    'BFIMZm9sbG93U3RhdHVzEh4KCnB1c2hTdGF0dXMYBCABKARSCnB1c2hTdGF0dXMSHgoKcmVtYX'\n    'JrTmFtZRgFIAEoCVIKcmVtYXJrTmFtZRIqChBmb2xsb3dlckNvdW50U3RyGAYgASgJUhBmb2xs'\n    'b3dlckNvdW50U3RyEiwKEWZvbGxvd2luZ0NvdW50U3RyGAcgASgJUhFmb2xsb3dpbmdDb3VudF'\n    'N0cg==');\n\n@$core.Deprecated('Use imageDescriptor instead')\nconst Image$json = {\n  '1': 'Image',\n  '2': [\n    {'1': 'urlListList', '3': 1, '4': 3, '5': 9, '10': 'urlListList'},\n    {'1': 'uri', '3': 2, '4': 1, '5': 9, '10': 'uri'},\n    {'1': 'height', '3': 3, '4': 1, '5': 4, '10': 'height'},\n    {'1': 'width', '3': 4, '4': 1, '5': 4, '10': 'width'},\n    {'1': 'avgColor', '3': 5, '4': 1, '5': 9, '10': 'avgColor'},\n    {'1': 'imageType', '3': 6, '4': 1, '5': 13, '10': 'imageType'},\n    {'1': 'openWebUrl', '3': 7, '4': 1, '5': 9, '10': 'openWebUrl'},\n    {\n      '1': 'content',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.ImageContent',\n      '10': 'content'\n    },\n    {'1': 'isAnimated', '3': 9, '4': 1, '5': 8, '10': 'isAnimated'},\n    {\n      '1': 'FlexSettingList',\n      '3': 10,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.NinePatchSetting',\n      '10': 'FlexSettingList'\n    },\n    {\n      '1': 'TextSettingList',\n      '3': 11,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.NinePatchSetting',\n      '10': 'TextSettingList'\n    },\n  ],\n};\n\n/// Descriptor for `Image`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List imageDescriptor = $convert.base64Decode(\n    'CgVJbWFnZRIgCgt1cmxMaXN0TGlzdBgBIAMoCVILdXJsTGlzdExpc3QSEAoDdXJpGAIgASgJUg'\n    'N1cmkSFgoGaGVpZ2h0GAMgASgEUgZoZWlnaHQSFAoFd2lkdGgYBCABKARSBXdpZHRoEhoKCGF2'\n    'Z0NvbG9yGAUgASgJUghhdmdDb2xvchIcCglpbWFnZVR5cGUYBiABKA1SCWltYWdlVHlwZRIeCg'\n    'pvcGVuV2ViVXJsGAcgASgJUgpvcGVuV2ViVXJsEi4KB2NvbnRlbnQYCCABKAsyFC5kb3V5aW4u'\n    'SW1hZ2VDb250ZW50Ugdjb250ZW50Eh4KCmlzQW5pbWF0ZWQYCSABKAhSCmlzQW5pbWF0ZWQSQg'\n    'oPRmxleFNldHRpbmdMaXN0GAogASgLMhguZG91eWluLk5pbmVQYXRjaFNldHRpbmdSD0ZsZXhT'\n    'ZXR0aW5nTGlzdBJCCg9UZXh0U2V0dGluZ0xpc3QYCyABKAsyGC5kb3V5aW4uTmluZVBhdGNoU2'\n    'V0dGluZ1IPVGV4dFNldHRpbmdMaXN0');\n\n@$core.Deprecated('Use ninePatchSettingDescriptor instead')\nconst NinePatchSetting$json = {\n  '1': 'NinePatchSetting',\n  '2': [\n    {'1': 'settingListList', '3': 1, '4': 3, '5': 9, '10': 'settingListList'},\n  ],\n};\n\n/// Descriptor for `NinePatchSetting`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List ninePatchSettingDescriptor = $convert.base64Decode(\n    'ChBOaW5lUGF0Y2hTZXR0aW5nEigKD3NldHRpbmdMaXN0TGlzdBgBIAMoCVIPc2V0dGluZ0xpc3'\n    'RMaXN0');\n\n@$core.Deprecated('Use imageContentDescriptor instead')\nconst ImageContent$json = {\n  '1': 'ImageContent',\n  '2': [\n    {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},\n    {'1': 'fontColor', '3': 2, '4': 1, '5': 9, '10': 'fontColor'},\n    {'1': 'level', '3': 3, '4': 1, '5': 4, '10': 'level'},\n    {'1': 'alternativeText', '3': 4, '4': 1, '5': 9, '10': 'alternativeText'},\n  ],\n};\n\n/// Descriptor for `ImageContent`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List imageContentDescriptor = $convert.base64Decode(\n    'CgxJbWFnZUNvbnRlbnQSEgoEbmFtZRgBIAEoCVIEbmFtZRIcCglmb250Q29sb3IYAiABKAlSCW'\n    'ZvbnRDb2xvchIUCgVsZXZlbBgDIAEoBFIFbGV2ZWwSKAoPYWx0ZXJuYXRpdmVUZXh0GAQgASgJ'\n    'Ug9hbHRlcm5hdGl2ZVRleHQ=');\n\n@$core.Deprecated('Use pushFrameDescriptor instead')\nconst PushFrame$json = {\n  '1': 'PushFrame',\n  '2': [\n    {'1': 'seqId', '3': 1, '4': 1, '5': 4, '10': 'seqId'},\n    {'1': 'logId', '3': 2, '4': 1, '5': 4, '10': 'logId'},\n    {'1': 'service', '3': 3, '4': 1, '5': 4, '10': 'service'},\n    {'1': 'method', '3': 4, '4': 1, '5': 4, '10': 'method'},\n    {\n      '1': 'headersList',\n      '3': 5,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.HeadersList',\n      '10': 'headersList'\n    },\n    {'1': 'payloadEncoding', '3': 6, '4': 1, '5': 9, '10': 'payloadEncoding'},\n    {'1': 'payloadType', '3': 7, '4': 1, '5': 9, '10': 'payloadType'},\n    {'1': 'payload', '3': 8, '4': 1, '5': 12, '10': 'payload'},\n  ],\n};\n\n/// Descriptor for `PushFrame`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List pushFrameDescriptor = $convert.base64Decode(\n    'CglQdXNoRnJhbWUSFAoFc2VxSWQYASABKARSBXNlcUlkEhQKBWxvZ0lkGAIgASgEUgVsb2dJZB'\n    'IYCgdzZXJ2aWNlGAMgASgEUgdzZXJ2aWNlEhYKBm1ldGhvZBgEIAEoBFIGbWV0aG9kEjUKC2hl'\n    'YWRlcnNMaXN0GAUgAygLMhMuZG91eWluLkhlYWRlcnNMaXN0UgtoZWFkZXJzTGlzdBIoCg9wYX'\n    'lsb2FkRW5jb2RpbmcYBiABKAlSD3BheWxvYWRFbmNvZGluZxIgCgtwYXlsb2FkVHlwZRgHIAEo'\n    'CVILcGF5bG9hZFR5cGUSGAoHcGF5bG9hZBgIIAEoDFIHcGF5bG9hZA==');\n\n@$core.Deprecated('Use kkDescriptor instead')\nconst kk$json = {\n  '1': 'kk',\n  '2': [\n    {'1': 'k', '3': 14, '4': 1, '5': 13, '10': 'k'},\n  ],\n};\n\n/// Descriptor for `kk`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List kkDescriptor =\n    $convert.base64Decode('CgJraxIMCgFrGA4gASgNUgFr');\n\n@$core.Deprecated('Use sendMessageBodyDescriptor instead')\nconst SendMessageBody$json = {\n  '1': 'SendMessageBody',\n  '2': [\n    {'1': 'conversationId', '3': 1, '4': 1, '5': 9, '10': 'conversationId'},\n    {\n      '1': 'conversationType',\n      '3': 2,\n      '4': 1,\n      '5': 13,\n      '10': 'conversationType'\n    },\n    {\n      '1': 'conversationShortId',\n      '3': 3,\n      '4': 1,\n      '5': 4,\n      '10': 'conversationShortId'\n    },\n    {'1': 'content', '3': 4, '4': 1, '5': 9, '10': 'content'},\n    {'1': 'ext', '3': 5, '4': 3, '5': 11, '6': '.douyin.ExtList', '10': 'ext'},\n    {'1': 'messageType', '3': 6, '4': 1, '5': 13, '10': 'messageType'},\n    {'1': 'ticket', '3': 7, '4': 1, '5': 9, '10': 'ticket'},\n    {'1': 'clientMessageId', '3': 8, '4': 1, '5': 9, '10': 'clientMessageId'},\n  ],\n};\n\n/// Descriptor for `SendMessageBody`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List sendMessageBodyDescriptor = $convert.base64Decode(\n    'Cg9TZW5kTWVzc2FnZUJvZHkSJgoOY29udmVyc2F0aW9uSWQYASABKAlSDmNvbnZlcnNhdGlvbk'\n    'lkEioKEGNvbnZlcnNhdGlvblR5cGUYAiABKA1SEGNvbnZlcnNhdGlvblR5cGUSMAoTY29udmVy'\n    'c2F0aW9uU2hvcnRJZBgDIAEoBFITY29udmVyc2F0aW9uU2hvcnRJZBIYCgdjb250ZW50GAQgAS'\n    'gJUgdjb250ZW50EiEKA2V4dBgFIAMoCzIPLmRvdXlpbi5FeHRMaXN0UgNleHQSIAoLbWVzc2Fn'\n    'ZVR5cGUYBiABKA1SC21lc3NhZ2VUeXBlEhYKBnRpY2tldBgHIAEoCVIGdGlja2V0EigKD2NsaW'\n    'VudE1lc3NhZ2VJZBgIIAEoCVIPY2xpZW50TWVzc2FnZUlk');\n\n@$core.Deprecated('Use extListDescriptor instead')\nconst ExtList$json = {\n  '1': 'ExtList',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},\n  ],\n};\n\n/// Descriptor for `ExtList`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List extListDescriptor = $convert.base64Decode(\n    'CgdFeHRMaXN0EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZQ==');\n\n@$core.Deprecated('Use rspDescriptor instead')\nconst Rsp$json = {\n  '1': 'Rsp',\n  '2': [\n    {'1': 'a', '3': 1, '4': 1, '5': 5, '10': 'a'},\n    {'1': 'b', '3': 2, '4': 1, '5': 5, '10': 'b'},\n    {'1': 'c', '3': 3, '4': 1, '5': 5, '10': 'c'},\n    {'1': 'd', '3': 4, '4': 1, '5': 9, '10': 'd'},\n    {'1': 'e', '3': 5, '4': 1, '5': 5, '10': 'e'},\n    {'1': 'f', '3': 6, '4': 1, '5': 11, '6': '.douyin.Rsp.F', '10': 'f'},\n    {'1': 'g', '3': 7, '4': 1, '5': 9, '10': 'g'},\n    {'1': 'h', '3': 10, '4': 1, '5': 4, '10': 'h'},\n    {'1': 'i', '3': 11, '4': 1, '5': 4, '10': 'i'},\n    {'1': 'j', '3': 13, '4': 1, '5': 4, '10': 'j'},\n  ],\n  '3': [Rsp_F$json],\n};\n\n@$core.Deprecated('Use rspDescriptor instead')\nconst Rsp_F$json = {\n  '1': 'F',\n  '2': [\n    {'1': 'q1', '3': 1, '4': 1, '5': 4, '10': 'q1'},\n    {'1': 'q3', '3': 3, '4': 1, '5': 4, '10': 'q3'},\n    {'1': 'q4', '3': 4, '4': 1, '5': 9, '10': 'q4'},\n    {'1': 'q5', '3': 5, '4': 1, '5': 4, '10': 'q5'},\n  ],\n};\n\n/// Descriptor for `Rsp`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List rspDescriptor = $convert.base64Decode(\n    'CgNSc3ASDAoBYRgBIAEoBVIBYRIMCgFiGAIgASgFUgFiEgwKAWMYAyABKAVSAWMSDAoBZBgEIA'\n    'EoCVIBZBIMCgFlGAUgASgFUgFlEhsKAWYYBiABKAsyDS5kb3V5aW4uUnNwLkZSAWYSDAoBZxgH'\n    'IAEoCVIBZxIMCgFoGAogASgEUgFoEgwKAWkYCyABKARSAWkSDAoBahgNIAEoBFIBahpDCgFGEg'\n    '4KAnExGAEgASgEUgJxMRIOCgJxMxgDIAEoBFICcTMSDgoCcTQYBCABKAlSAnE0Eg4KAnE1GAUg'\n    'ASgEUgJxNQ==');\n\n@$core.Deprecated('Use preMessageDescriptor instead')\nconst PreMessage$json = {\n  '1': 'PreMessage',\n  '2': [\n    {'1': 'cmd', '3': 1, '4': 1, '5': 13, '10': 'cmd'},\n    {'1': 'sequenceId', '3': 2, '4': 1, '5': 13, '10': 'sequenceId'},\n    {'1': 'sdkVersion', '3': 3, '4': 1, '5': 9, '10': 'sdkVersion'},\n    {'1': 'token', '3': 4, '4': 1, '5': 9, '10': 'token'},\n    {'1': 'refer', '3': 5, '4': 1, '5': 13, '10': 'refer'},\n    {'1': 'inboxType', '3': 6, '4': 1, '5': 13, '10': 'inboxType'},\n    {'1': 'buildNumber', '3': 7, '4': 1, '5': 9, '10': 'buildNumber'},\n    {\n      '1': 'sendMessageBody',\n      '3': 8,\n      '4': 1,\n      '5': 11,\n      '6': '.douyin.SendMessageBody',\n      '10': 'sendMessageBody'\n    },\n    {'1': 'aa', '3': 9, '4': 1, '5': 9, '10': 'aa'},\n    {'1': 'devicePlatform', '3': 11, '4': 1, '5': 9, '10': 'devicePlatform'},\n    {\n      '1': 'headers',\n      '3': 15,\n      '4': 3,\n      '5': 11,\n      '6': '.douyin.HeadersList',\n      '10': 'headers'\n    },\n    {'1': 'authType', '3': 18, '4': 1, '5': 13, '10': 'authType'},\n    {'1': 'biz', '3': 21, '4': 1, '5': 9, '10': 'biz'},\n    {'1': 'access', '3': 22, '4': 1, '5': 9, '10': 'access'},\n  ],\n};\n\n/// Descriptor for `PreMessage`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List preMessageDescriptor = $convert.base64Decode(\n    'CgpQcmVNZXNzYWdlEhAKA2NtZBgBIAEoDVIDY21kEh4KCnNlcXVlbmNlSWQYAiABKA1SCnNlcX'\n    'VlbmNlSWQSHgoKc2RrVmVyc2lvbhgDIAEoCVIKc2RrVmVyc2lvbhIUCgV0b2tlbhgEIAEoCVIF'\n    'dG9rZW4SFAoFcmVmZXIYBSABKA1SBXJlZmVyEhwKCWluYm94VHlwZRgGIAEoDVIJaW5ib3hUeX'\n    'BlEiAKC2J1aWxkTnVtYmVyGAcgASgJUgtidWlsZE51bWJlchJBCg9zZW5kTWVzc2FnZUJvZHkY'\n    'CCABKAsyFy5kb3V5aW4uU2VuZE1lc3NhZ2VCb2R5Ug9zZW5kTWVzc2FnZUJvZHkSDgoCYWEYCS'\n    'ABKAlSAmFhEiYKDmRldmljZVBsYXRmb3JtGAsgASgJUg5kZXZpY2VQbGF0Zm9ybRItCgdoZWFk'\n    'ZXJzGA8gAygLMhMuZG91eWluLkhlYWRlcnNMaXN0UgdoZWFkZXJzEhoKCGF1dGhUeXBlGBIgAS'\n    'gNUghhdXRoVHlwZRIQCgNiaXoYFSABKAlSA2JpehIWCgZhY2Nlc3MYFiABKAlSBmFjY2Vzcw==');\n\n@$core.Deprecated('Use headersListDescriptor instead')\nconst HeadersList$json = {\n  '1': 'HeadersList',\n  '2': [\n    {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},\n    {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},\n  ],\n};\n\n/// Descriptor for `HeadersList`. Decode as a `google.protobuf.DescriptorProto`.\nfinal $typed_data.Uint8List headersListDescriptor = $convert.base64Decode(\n    'CgtIZWFkZXJzTGlzdBIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU=');\n"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/proto/douyin.proto",
    "content": "syntax = \"proto3\";\n\npackage douyin;\n\n\nmessage Response {\n  repeated Message messagesList = 1;\n  string cursor = 2;\n  uint64 fetchInterval = 3;\n  uint64 now = 4;\n  string internalExt = 5;\n  uint32 fetchType = 6;\n  map<string, string> routeParams = 7;\n  uint64 heartbeatDuration = 8;\n  bool needAck = 9;\n  string pushServer = 10;\n  string liveCursor = 11;\n  bool historyNoMore = 12;\n}\n\nmessage Message{\n    string method = 1;\n    bytes payload = 2;\n    int64 msgId = 3;\n    int32 msgType = 4;\n    int64 offset = 5;\n    bool needWrdsStore = 6;\n    int64 wrdsVersion = 7;\n    string wrdsSubKey = 8;\n}\n\n// 聊天\nmessage ChatMessage {\n  Common common = 1;\n  User user = 2;\n  string content = 3;\n  bool visibleToSender = 4;\n  Image backgroundImage = 5;\n  string fullScreenTextColor = 6;\n  Image backgroundImageV2 = 7;\n  PublicAreaCommon publicAreaCommon = 8;\n  Image giftImage = 9;\n  uint64 agreeMsgId = 11;\n  uint32 priorityLevel = 12;\n  LandscapeAreaCommon landscapeAreaCommon = 13;\n  uint64 eventTime = 15;\n  bool sendReview = 16;\n  bool fromIntercom = 17;\n  bool intercomHideUserCard = 18;\n//  repeated chatTagsList = 19;\n  string chatBy  = 20;\n  uint32 individualChatPriority = 21;\n  Text rtfContent = 22;\n}\n\n\nmessage LandscapeAreaCommon {\n  bool showHead = 1;\n  bool showNickname = 2;\n  bool showFontColor = 3;\n  repeated string colorValueList = 4;\n  repeated CommentTypeTag commentTypeTagsList = 5;\n}\n\nmessage RoomUserSeqMessage {\n  Common common = 1;\n  repeated RoomUserSeqMessageContributor ranksList = 2;\n  int64 total = 3;\n  string popStr = 4;\n  repeated RoomUserSeqMessageContributor seatsList = 5;\n  int64 popularity = 6;\n  int64 totalUser = 7;\n  string totalUserStr = 8;\n  string totalStr = 9;\n  string onlineUserForAnchor = 10;\n  string totalPvForAnchor = 11;\n  string upRightStatsStr = 12;\n  string upRightStatsStrComplete = 13;\n\n}\n\nmessage CommonTextMessage {\n  Common common = 1;\n  User user = 2;\n  string scene = 3;\n}\n\nmessage UpdateFanTicketMessage {\n  Common common = 1;\n  string roomFanTicketCountText = 2;\n  uint64 roomFanTicketCount = 3;\n  bool forceUpdate = 4;\n}\n\nmessage RoomUserSeqMessageContributor {\n  uint64 score = 1;\n  User user = 2;\n  uint64 rank  = 3;\n  uint64 delta  = 4;\n  bool isHidden = 5;\n  string scoreDescription = 6;\n  string exactlyScore = 7;\n}\n\n// 礼物消息\nmessage GiftMessage {\n  Common common = 1;\n  uint64 giftId = 2;\n  uint64 fanTicketCount = 3;\n  uint64 groupCount = 4;\n  uint64 repeatCount = 5;\n  uint64 comboCount = 6;\n  User user = 7;\n  User toUser = 8;\n  uint32 repeatEnd = 9;\n  TextEffect textEffect = 10;\n  uint64 groupId = 11;\n  uint64 incomeTaskgifts = 12;\n  uint64 roomFanTicketCount = 13;\n  GiftIMPriority priority = 14;\n  GiftStruct gift = 15;\n  string logId = 16;\n  uint64 sendType = 17;\n  PublicAreaCommon publicAreaCommon = 18;\n  Text trayDisplayText = 19;\n  uint64 bannedDisplayEffects = 20;\n//  GiftTrayInfo trayInfo = 21;\n//  AssetEffectMixInfo assetEffectMixInfo = 22;\n  bool displayForSelf = 25;\n  string interactGiftInfo = 26;\n  string diyItemInfo = 27;\n  repeated uint64 minAssetSetList = 28;\n  uint64 totalCount = 29;\n  uint32 clientGiftSource = 30;\n//  AnchorGiftData anchorGift = 31;\n  repeated uint64 toUserIdsList = 32;\n  uint64 sendTime = 33;\n  uint64 forceDisplayEffects = 34;\n  string traceId = 35;\n  uint64 effectDisplayTs = 36;\n}\n\nmessage GiftStruct {\n  Image image = 1;\n  string describe = 2;\n  bool notify = 3;\n  uint64 duration = 4;\n  uint64 id = 5;\n//  GiftStructFansClubInfo fansclubInfo = 6;\n  bool forLinkmic = 7;\n  bool doodle = 8;\n  bool forFansclub = 9;\n  bool combo = 10;\n  uint32 type = 11;\n  uint32 diamondCount = 12;\n  bool isDisplayedOnPanel = 13;\n  uint64 primaryEffectId = 14;\n  Image giftLabelIcon = 15;\n  string name = 16;\n  string region = 17;\n  string manual = 18;\n  bool forCustom = 19;\n  //  specialEffectsMap = 20;\n  Image icon = 21;\n  uint32 actionType = 22;\n  // fixme 后面的就不写了还有几十个属性\n\n}\n\nmessage GiftIMPriority {\n    repeated uint64 queueSizesList = 1;\n    uint64 selfQueuePriority = 2;\n    uint64 priority = 3;\n}\n\nmessage TextEffect {\n  TextEffectDetail portrait = 1;\n  TextEffectDetail landscape = 2;\n}\n\nmessage TextEffectDetail {\n  Text text = 1;\n  uint32 textFontSize = 2;\n  Image background = 3;\n  uint32 start = 4;\n  uint32 duration = 5;\n  uint32 x = 6;\n  uint32 y = 7;\n  uint32 width = 8;\n  uint32 height = 9;\n  uint32 shadowDx = 10;\n  uint32 shadowDy = 11;\n  uint32 shadowRadius = 12;\n  string shadowColor = 13;\n  string strokeColor = 14;\n  uint32 strokeWidth = 15;\n}\n\n// 成员消息\nmessage MemberMessage {\n  Common common = 1;\n  User user = 2;\n  uint64 memberCount = 3;\n  User operator = 4;\n  bool isSetToAdmin = 5;\n  bool isTopUser = 6;\n  uint64 rankScore = 7;\n  uint64 topUserNo = 8;\n  uint64 enterType = 9;\n  uint64 action = 10;\n  string actionDescription = 11;\n  uint64 userId = 12;\n  EffectConfig effectConfig = 13;\n  string popStr = 14;\n  EffectConfig enterEffectConfig = 15;\n  Image backgroundImage = 16;\n  Image backgroundImageV2 = 17;\n  Text anchorDisplayText = 18;\n  PublicAreaCommon publicAreaCommon = 19;\n  uint64 userEnterTipType = 20;\n  uint64 anchorEnterTipType = 21;\n}\n\n\nmessage PublicAreaCommon {\n  Image userLabel = 1;\n  uint64 userConsumeInRoom = 2;\n  uint64 userSendGiftCntInRoom = 3;\n}\n\nmessage EffectConfig {\n  uint64 type = 1;\n  Image icon = 2;\n  uint64 avatarPos = 3;\n  Text text = 4;\n  Image textIcon = 5;\n  uint32 stayTime = 6;\n  uint64 animAssetId = 7;\n  Image badge = 8;\n  repeated uint64 flexSettingArrayList = 9;\n  Image textIconOverlay = 10;\n  Image animatedBadge = 11;\n  bool hasSweepLight = 12;\n  repeated uint64 textFlexSettingArrayList = 13;\n  uint64 centerAnimAssetId = 14;\n  Image dynamicImage = 15;\n  map<string,string> extraMap = 16;\n  uint64 mp4AnimAssetId = 17;\n  uint64 priority = 18;\n  uint64 maxWaitTime = 19;\n  string dressId = 20;\n  uint64 alignment = 21;\n  uint64 alignmentOffset = 22;\n}\n\nmessage Text {\n  string key = 1;\n  string defaultPatter = 2;\n  TextFormat defaultFormat = 3;\n  repeated TextPiece piecesList = 4;\n}\n\nmessage TextPiece {\n  bool type = 1;\n  TextFormat format = 2;\n  string stringValue = 3;\n  TextPieceUser userValue = 4;\n  TextPieceGift giftValue = 5;\n  TextPieceHeart heartValue = 6;\n  TextPiecePatternRef patternRefValue = 7;\n  TextPieceImage imageValue = 8;\n}\n\n\nmessage TextPieceImage {\n  Image image = 1;\n  float scalingRate = 2;\n}\n\nmessage TextPiecePatternRef {\n  string key = 1;\n  string defaultPattern = 2;\n}\n\nmessage TextPieceHeart {\n  string color = 1;\n}\n\nmessage TextPieceGift {\n  uint64 giftId = 1;\n  PatternRef nameRef = 2;\n}\n\nmessage PatternRef {\n  string key = 1;\n  string defaultPattern = 2;\n}\n\nmessage TextPieceUser {\n  User user = 1;\n  bool withColon = 2;\n}\n\nmessage TextFormat {\n  string color = 1;\n  bool bold = 2;\n  bool italic = 3;\n  uint32 weight = 4;\n  uint32 italicAngle = 5;\n  uint32 fontSize = 6;\n  bool useHeighLightColor = 7;\n  bool useRemoteClor = 8;\n}\n\n// 点赞\nmessage LikeMessage {\n  Common common = 1;\n  uint64 count = 2;\n  uint64 total = 3;\n  uint64 color = 4;\n  User user = 5;\n  string icon = 6;\n  DoubleLikeDetail doubleLikeDetail = 7;\n  DisplayControlInfo displayControlInfo = 8;\n  uint64 linkmicGuestUid = 9;\n  string scene = 10;\n  PicoDisplayInfo picoDisplayInfo = 11;\n\n}\n\nmessage SocialMessage {\n  Common common = 1;\n  User user = 2;\n  uint64 shareType = 3;\n  uint64 action = 4;\n  string shareTarget = 5;\n  uint64 followCount = 6;\n  PublicAreaCommon publicAreaCommon = 7;\n}\n\nmessage PicoDisplayInfo {\n  uint64 comboSumCount = 1;\n  string emoji = 2;\n  Image emojiIcon = 3;\n  string emojiText = 4;\n}\n\nmessage DoubleLikeDetail {\n  bool doubleFlag = 1;\n  uint32 seqId = 2;\n  uint32 renewalsNum = 3;\n  uint32 triggersNum = 4;\n}\n\nmessage DisplayControlInfo {\n  bool showText = 1;\n  bool showIcons = 2;\n}\n\nmessage EpisodeChatMessage {\n   Message common = 1;\n   User user = 2;\n   string content = 3;\n   bool visibleToSende = 4;\n//   BackgroundImage backgroundImage = 5;\n//   PublicAreaCommon publicAreaCommon = 6;\n   Image giftImage = 7;\n   uint64 agreeMsgId = 8;\n   repeated string colorValueList = 9;\n}\n\n\nmessage MatchAgainstScoreMessage {\n  Common common = 1;\n  Against against = 2;\n  uint32 matchStatus = 3;\n  uint32 displayStatus = 4;\n}\n\nmessage Against {\n  string leftName = 1;\n  Image leftLogo = 2;\n  string leftGoal = 3;\n//  LeftPlayersList leftPlayersList = 4;\n//  LeftGoalStageDetail leftGoalStageDetail = 5;\n  string rightName = 6;\n  Image rightLogo = 7;\n  string rightGoal = 8;\n//  RightPlayersList rightPlayersList  = 9;\n//  RightGoalStageDetail rightGoalStageDetail = 10;\n  uint64 timestamp = 11;\n  uint64 version = 12;\n  uint64 leftTeamId = 13;\n  uint64 rightTeamId = 14;\n  uint64 diffSei2absSecond = 15;\n  uint32 finalGoalStage = 16;\n  uint32 currentGoalStage  =17;\n  uint32 leftScoreAddition  =18;\n  uint32 rightScoreAddition  =19;\n  uint64 leftGoalInt = 20;\n  uint64 rightGoalInt = 21;\n}\n\nmessage Common {\n  string method = 1;\n  uint64 msgId = 2;\n  uint64 roomId = 3;\n  uint64 createTime = 4;\n  uint32 monitor = 5;\n  bool isShowMsg = 6;\n  string describe = 7;\n//  DisplayText displayText = 8;\n  uint64 foldType = 9;\n  uint64 anchorFoldType = 10;\n  uint64 priorityScore = 11;\n  string logId = 12;\n  string msgProcessFilterK = 13;\n  string msgProcessFilterV = 14;\n  User user = 15;\n//  Room room = 16;\n  uint64 anchorFoldTypeV2  = 17;\n  uint64 processAtSeiTimeMs  = 18;\n  uint64 randomDispatchMs  = 19;\n  bool isDispatch = 20;\n  uint64 channelId = 21;\n  uint64 diffSei2absSecond = 22;\n  uint64 anchorFoldDuration = 23;\n}\n\nmessage User {\n  uint64 id = 1;\n  uint64 shortId = 2;\n  string nickName = 3;\n  uint32 gender = 4;\n  string Signature = 5;\n  uint32 Level = 6;\n  uint64 Birthday = 7;\n  string Telephone = 8;\n  Image AvatarThumb = 9;\n  Image AvatarMedium = 10;\n  Image AvatarLarge = 11;\n  bool Verified = 12;\n  uint32 Experience = 13;\n  string city = 14;\n  int32 Status = 15;\n  uint64 CreateTime = 16;\n  uint64 ModifyTime = 17;\n  uint32 Secret = 18;\n  string ShareQrcodeUri = 19;\n  uint32 IncomeSharePercent = 20;\n  repeated Image BadgeImageList = 21;\n  FollowInfo FollowInfo = 22;\n//  PayGrade PayGrade = 23;\n//  FansClub FansClub = 24;\n//  Border Border = 25;\n  string SpecialId = 26;\n  Image AvatarBorder = 27;\n  Image Medal = 28;\n  repeated Image RealTimeIconsList = 29;\n  string displayId = 38;\n  string secUid = 46;\n  uint64 fanTicketCount = 1022;\n  string idStr = 1028;\n  uint32 ageRange = 1045;\n}\n\nmessage FollowInfo {\n  uint64 followingCount = 1;\n  uint64 followerCount = 2;\n  uint64 followStatus = 3;\n  uint64 pushStatus = 4;\n  string remarkName = 5;\n  string followerCountStr = 6;\n  string followingCountStr = 7;\n\n}\nmessage Image {\n  repeated string urlListList = 1;\n  string uri = 2;\n  uint64 height = 3;\n  uint64 width = 4;\n  string avgColor = 5;\n  uint32 imageType = 6;\n  string openWebUrl = 7;\n  ImageContent content = 8;\n  bool isAnimated = 9;\n  NinePatchSetting FlexSettingList = 10;\n  NinePatchSetting TextSettingList = 11;\n}\n\nmessage NinePatchSetting {\n  repeated string settingListList = 1;\n}\n\nmessage ImageContent {\n  string name = 1;\n  string fontColor = 2;\n  uint64 level = 3;\n  string alternativeText = 4;\n}\n\nmessage PushFrame {\n  uint64 seqId = 1;\n  uint64 logId = 2;\n  uint64 service = 3;\n  uint64 method = 4;\n  repeated HeadersList headersList = 5;\n  string payloadEncoding = 6;\n  string payloadType = 7;\n  bytes payload = 8;\n\n}\n\nmessage kk {\n  uint32 k=14;\n}\n\nmessage SendMessageBody {\n  string conversationId = 1;\n  uint32 conversationType = 2;\n  uint64 conversationShortId = 3;\n  string content = 4;\n  repeated ExtList ext = 5;\n  uint32 messageType = 6;\n  string ticket = 7;\n  string clientMessageId = 8;\n\n}\n\nmessage ExtList {\n  string key = 1;\n  string value = 2;\n}\n\nmessage Rsp{\n  int32 a = 1;\n  int32 b = 2;\n  int32 c = 3;\n  string d = 4;\n  int32 e = 5;\n  message F {\n    uint64 q1 = 1;\n    uint64 q3 = 3;\n    string q4 = 4;\n    uint64 q5 = 5;\n  }\n  F f = 6;\n  string g = 7;\n  uint64 h = 10;\n  uint64 i = 11;\n  uint64 j = 13;\n}\n\nmessage PreMessage {\n  uint32 cmd = 1;\n  uint32 sequenceId = 2;\n  string sdkVersion = 3;\n  string token = 4;\n  uint32 refer = 5;\n  uint32 inboxType = 6;\n  string buildNumber = 7;\n  SendMessageBody sendMessageBody = 8;\n  // 字段名待定\n  string aa = 9;\n  string devicePlatform = 11;\n  repeated HeadersList headers = 15;\n  uint32 authType = 18;\n  string biz = 21;\n  string access = 22;\n}\n\nmessage HeadersList {\n  string key = 1;\n  string value = 2;\n}\n\nenum CommentTypeTag {\n  COMMENTTYPETAGUNKNOWN = 0;\n  COMMENTTYPETAGSTAR = 1;\n}"
  },
  {
    "path": "simple_live_core/lib/src/danmaku/twitch_danmaku.dart",
    "content": "﻿import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/web_socket_util.dart';\n\nclass TwitchDanmaku implements LiveDanmaku {\n  WebScoketUtils? webScoketUtils;\n\n  @override\n  int heartbeatTime = 40 * 1000; //默认是40s\n\n  var serverUrl = \"wss://irc-ws.chat.twitch.tv\";\n\n  @override\n  Function(String msg)? onClose;\n\n  @override\n  Function(LiveMessage msg)? onMessage;\n\n  @override\n  Function()? onReady;\n\n  @override\n  void heartbeat() {\n    // 发送心跳包\n    var data = utf8.encode(\"PONG :tmi.twitch.tv\");\n    webScoketUtils?.sendMessage(data);\n  }\n\n  @override\n  Future start(args) async {\n    webScoketUtils = WebScoketUtils(\n      url: serverUrl,\n      heartBeatTime: heartbeatTime,\n      onMessage: (e) {\n        decodeMessage(e);\n      },\n      onReady: () {\n        onReady?.call();\n        joinRoom(args);\n      },\n      onHeartBeat: () {\n        heartbeat();\n      },\n      onReconnect: () {\n        onClose?.call(\"与服务器断开连接，正在尝试重连\");\n      },\n      onClose: (e) {\n        onClose?.call(\"服务器连接失败$e\");\n      },\n    );\n    webScoketUtils?.connect();\n  }\n\n  void joinRoom(String roomId) {\n    var user = \"justinfan${1000 + Random().nextInt(99999 - 1000 + 1)}\";\n    webScoketUtils?..sendMessage(\n        \"CAP REQ :twitch.tv/tags twitch.tv/commands twitch.tv/membership\")..sendMessage(\n        \"PASS SCHMOOPIIE\")..sendMessage(\"NICK $user\")..sendMessage(\n        \"USER $user 8 * :$user\")..sendMessage(\"JOIN #$roomId\");\n  }\n\n\n  @override\n  Future stop() async {\n    onMessage = null;\n    onClose = null;\n    webScoketUtils?.close();\n  }\n\n  void decodeMessage(String data) {\n    try {\n      var message = data;\n\n      if (message.startsWith(\"PING\")) {\n        // respond to PING according to https://dev.twitch.tv/docs/irc/#keepalive-messages\n        webScoketUtils?.sendMessage(message.replaceFirst(\"PING\", \"PONG\"));\n      }\n\n      if (!message.contains(\"PRIVMSG\")) {}\n\n      final lines = message.split('\\n');\n      for (final d in lines) {\n        final contentMatch = RegExp(r\"PRIVMSG [^:]+:(.+)\").firstMatch(d);\n        final nameMatch = RegExp(r\"display-name=([^;]+);\").firstMatch(d);\n        final colorMatch = RegExp(r\"color=#([a-zA-Z0-9]{6});\").firstMatch(d);\n\n        if (contentMatch != null && nameMatch != null && colorMatch != null) {\n          final liveMsg = LiveMessage(\n            type: LiveMessageType.chat,\n            message: contentMatch.group(1) ?? \"\",\n            userName: nameMatch.group(1) ?? \"\",\n            color: LiveMessageColor.numberToColor(\n                int.parse(colorMatch.group(1) ?? \"FFFFFF\", radix: 16)),\n          );\n          onMessage?.call(liveMsg);\n        }\n      }\n    } catch (e) {\n      CoreLog.error(e);\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/interface/live_danmaku.dart",
    "content": "import 'dart:async';\n\nimport 'package:simple_live_core/src/model/live_message.dart';\n\nclass LiveDanmaku {\n  Function(LiveMessage msg)? onMessage;\n  Function(String msg)? onClose;\n  Function()? onReady;\n\n  /// 心跳时间\n  int heartbeatTime = 0;\n\n  /// 发生心跳\n  void heartbeat() {}\n\n  /// 开始接收信息\n  Future start(dynamic args) {\n    return Future.value();\n  }\n\n  /// 停止接收信息\n  Future stop() {\n    return Future.value();\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/interface/live_site.dart",
    "content": "import 'package:simple_live_core/src/model/live_anchor_item.dart';\n\nimport '../interface/live_danmaku.dart';\nimport '../model/live_category_result.dart';\nimport '../model/live_message.dart';\nimport '../model/live_play_url.dart';\nimport '../model/live_room_detail.dart';\nimport '../model/live_search_result.dart';\n\nimport '../model/live_category.dart';\nimport '../model/live_play_quality.dart';\nimport '../model/live_room_item.dart';\n\nclass LiveSite {\n  /// 站点唯一ID\n  String id = \"\";\n\n  /// 站点名称\n  String name = \"\";\n\n  /// 站点名称\n  LiveDanmaku getDanmaku() => LiveDanmaku();\n\n  /// 读取网站的分类\n  Future<List<LiveCategory>> getCategores() {\n    return Future.value(<LiveCategory>[]);\n  }\n\n  /// 搜索直播间\n  Future<LiveSearchRoomResult> searchRooms(String keyword, {int page = 1}) {\n    return Future.value(\n        LiveSearchRoomResult(hasMore: false, items: <LiveRoomItem>[]));\n  }\n\n  /// 搜索直播间\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword, {int page = 1}) {\n    return Future.value(\n        LiveSearchAnchorResult(hasMore: false, items: <LiveAnchorItem>[]));\n  }\n\n  /// 读取类目下房间\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) {\n    return Future.value(\n        LiveCategoryResult(hasMore: false, items: <LiveRoomItem>[]));\n  }\n\n  /// 读取推荐的房间\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) {\n    return Future.value(\n        LiveCategoryResult(hasMore: false, items: <LiveRoomItem>[]));\n  }\n\n  /// 读取房间详情\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) {\n    return Future.value(LiveRoomDetail(\n      cover: '',\n      online: 0,\n      roomId: '',\n      status: false,\n      title: '',\n      url: '',\n      userAvatar: '',\n      userName: '',\n    ));\n  }\n\n  /// 读取房间清晰度\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) {\n    return Future.value(<LivePlayQuality>[]);\n  }\n\n  /// 读取播放链接\n  Future<LivePlayUrl> getPlayUrls(\n      {required LiveRoomDetail detail, required LivePlayQuality quality}) {\n    return Future.value(LivePlayUrl(urls: []));\n  }\n\n  /// 查询直播状态\n  Future<bool> getLiveStatus({required String roomId}) {\n    return Future.value(false);\n  }\n\n  /// 读取指定房间的SC\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) {\n    return Future.value([]);\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_anchor_item.dart",
    "content": "import 'dart:convert';\n\nclass LiveAnchorItem {\n  /// 房间ID\n  final String roomId;\n\n  /// 封面\n  final String avatar;\n\n  /// 用户名\n  final String userName;\n\n  /// 直播中\n  final bool liveStatus;\n\n  LiveAnchorItem({\n    required this.roomId,\n    required this.avatar,\n    required this.userName,\n    required this.liveStatus,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"roomId\": roomId,\n      \"avatar\": avatar,\n      \"userName\": userName,\n      \"liveStatus\": liveStatus,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_category.dart",
    "content": "import 'dart:convert';\n\nclass LiveCategory {\n  final String name;\n  final String id;\n  final List<LiveSubCategory> children;\n  LiveCategory({\n    required this.id,\n    required this.name,\n    required this.children,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"name\": name,\n      \"id\": id,\n      \"children\": children,\n    });\n  }\n}\n\nclass LiveSubCategory {\n  final String name;\n  final String? pic;\n  final String id;\n  final String parentId;\n  LiveSubCategory({\n    required this.id,\n    required this.name,\n    required this.parentId,\n    this.pic,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"name\": name,\n      \"id\": id,\n      \"parentId\": parentId,\n      \"pic\": pic,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_category_result.dart",
    "content": "import 'package:simple_live_core/src/model/live_room_item.dart';\n\nclass LiveCategoryResult {\n  final bool hasMore;\n  final List<LiveRoomItem> items;\n  LiveCategoryResult({\n    required this.hasMore,\n    required this.items,\n  });\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_message.dart",
    "content": "import 'dart:convert';\n\nenum LiveMessageType {\n  /// 聊天\n  chat,\n\n  /// 礼物,暂时不支持\n  gift,\n\n  /// 在线人数\n  online,\n\n  /// 醒目留言\n  superChat,\n}\n\nclass LiveMessage {\n  /// 消息类型\n  final LiveMessageType type;\n\n  /// 用户名\n  final String userName;\n\n  /// 信息\n  final String message;\n\n  /// 数据\n  /// 单Type=Online时，Data为人气值(long)\n  final dynamic data;\n\n  /// 弹幕颜色\n  final LiveMessageColor color;\n  LiveMessage({\n    required this.type,\n    required this.userName,\n    required this.message,\n    this.data,\n    required this.color,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"type\": type.index,\n      \"userName\": userName,\n      \"message\": message,\n      \"data\": data.toString(),\n      \"color\": color.toString(),\n    });\n  }\n}\n\nclass LiveMessageColor {\n  final int r, g, b;\n  LiveMessageColor(this.r, this.g, this.b);\n  static LiveMessageColor get white => LiveMessageColor(255, 255, 255);\n  static LiveMessageColor numberToColor(int intColor) {\n    var obj = intColor.toRadixString(16);\n\n    LiveMessageColor color = LiveMessageColor.white;\n    if (obj.length == 4) {\n      obj = \"00$obj\";\n    }\n    if (obj.length == 6) {\n      var R = int.parse(obj.substring(0, 2), radix: 16);\n      var G = int.parse(obj.substring(2, 4), radix: 16);\n      var B = int.parse(obj.substring(4, 6), radix: 16);\n\n      color = LiveMessageColor(R, G, B);\n    }\n    if (obj.length == 8) {\n      var R = int.parse(obj.substring(2, 4), radix: 16);\n      var G = int.parse(obj.substring(4, 6), radix: 16);\n      var B = int.parse(obj.substring(6, 8), radix: 16);\n      //var A = int.parse(obj.substring(0, 2), radix: 16);\n      color = LiveMessageColor(R, G, B);\n    }\n\n    return color;\n  }\n\n  @override\n  String toString() {\n    return \"#${r.toRadixString(16).padLeft(2, '0')}${g.toRadixString(16).padLeft(2, '0')}${b.toRadixString(16).padLeft(2, '0')}\";\n  }\n}\n\nclass LiveSuperChatMessage {\n  final String userName;\n  final String face;\n  final String message;\n  final int price;\n  final DateTime startTime;\n  final DateTime endTime;\n  final String backgroundColor;\n  final String backgroundBottomColor;\n  LiveSuperChatMessage({\n    required this.backgroundBottomColor,\n    required this.backgroundColor,\n    required this.endTime,\n    required this.face,\n    required this.message,\n    required this.price,\n    required this.startTime,\n    required this.userName,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"userName\": userName,\n      \"face\": face,\n      \"message\": message,\n      \"price\": price,\n      \"startTime\": startTime,\n      \"endTime\": endTime,\n      \"backgroundColor\": backgroundColor,\n      \"backgroundBottomColor\": backgroundBottomColor,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_play_quality.dart",
    "content": "import 'dart:convert';\n\nclass LivePlayQuality {\n  /// 清晰度\n  final String quality;\n\n  /// 清晰度信息\n  final dynamic data;\n\n  final int sort;\n\n  LivePlayQuality({\n    required this.quality,\n    required this.data,\n    this.sort = 0,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"quality\": quality,\n      \"data\": data.toString(),\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_play_url.dart",
    "content": "import 'dart:convert';\n\nclass LivePlayUrl {\n  /// 播放地址\n  final List<String> urls;\n\n  /// 请求头\n  final Map<String, String>? headers;\n\n  LivePlayUrl({\n    required this.urls,\n    this.headers,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"urls\": urls,\n      \"headers\": headers.toString(),\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_room_detail.dart",
    "content": "import 'dart:convert';\n\nclass LiveRoomDetail {\n  /// 房间ID\n  final String roomId;\n\n  /// 房间标题\n  final String title;\n\n  /// 封面\n  final String cover;\n\n  /// 用户名\n  final String userName;\n\n  /// 头像\n  final String userAvatar;\n\n  /// 在线\n  final int online;\n\n  /// 介绍\n  final String? introduction;\n\n  /// 公告\n  final String? notice;\n\n  /// 状态\n  final bool status;\n\n  /// 附加信息\n  final dynamic data;\n\n  /// 弹幕附加信息\n  final dynamic danmakuData;\n\n  /// 是否录播\n  final bool isRecord;\n\n  /// 链接\n  final String url;\n\n  LiveRoomDetail({\n    required this.roomId,\n    required this.title,\n    required this.cover,\n    required this.userName,\n    required this.userAvatar,\n    required this.online,\n    this.introduction,\n    this.notice,\n    required this.status,\n    this.data,\n    this.danmakuData,\n    required this.url,\n    this.isRecord = false,\n  });\n\n  LiveRoomDetail copyWith({\n    String? roomId,\n    String? title,\n    String? cover,\n    String? userName,\n    String? userAvatar,\n    int? online,\n    String? introduction,\n    String? notice,\n    bool? status,\n    dynamic data,\n    dynamic danmakuData,\n    String? url,\n    bool? isRecord,\n  }) {\n    return LiveRoomDetail(\n      roomId: roomId ?? this.roomId,\n      title: title ?? this.title,\n      cover: cover ?? this.cover,\n      userName: userName ?? this.userName,\n      userAvatar: userAvatar ?? this.userAvatar,\n      online: online ?? this.online,\n      introduction: introduction ?? this.introduction,\n      notice: notice ?? this.notice,\n      status: status ?? this.status,\n      data: data ?? this.data,\n      danmakuData: danmakuData ?? this.danmakuData,\n      isRecord: isRecord ?? this.isRecord,\n      url: url ?? this.url,\n    );\n  }\n\n  LiveRoomDetail updateData(dynamic newData) {\n    return copyWith(data: newData);\n  }\n\n  LiveRoomDetail updateDanmakuData(dynamic newDanmakuData) {\n    return copyWith(danmakuData: newDanmakuData);\n  }\n\n  @override\n  String toString() {\n    return json.encode({\n      \"roomId\": roomId,\n      \"title\": title,\n      \"cover\": cover,\n      \"userName\": userName,\n      \"userAvatar\": userAvatar,\n      \"online\": online,\n      \"introduction\": introduction,\n      \"notice\": notice,\n      \"status\": status,\n      \"data\": data,\n      \"danmakuData\": danmakuData.toString(),\n      \"url\": url,\n      \"isRecord\": isRecord,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_room_item.dart",
    "content": "import 'dart:convert';\n\nclass LiveRoomItem {\n  /// 房间ID\n  final String roomId;\n\n  /// 标题\n  final String title;\n\n  /// 封面\n  final String cover;\n\n  /// 用户名\n  final String userName;\n\n  /// 人气/在线人数\n  final int online;\n  LiveRoomItem({\n    required this.roomId,\n    required this.title,\n    required this.cover,\n    required this.userName,\n    this.online = 0,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"roomId\": roomId,\n      \"title\": title,\n      \"cover\": cover,\n      \"userName\": userName,\n      \"online\": online,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/live_search_result.dart",
    "content": "import 'dart:convert';\nimport 'package:simple_live_core/src/model/live_anchor_item.dart';\nimport 'package:simple_live_core/src/model/live_room_item.dart';\n\nclass LiveSearchRoomResult {\n  final bool hasMore;\n  final List<LiveRoomItem> items;\n  LiveSearchRoomResult({\n    required this.hasMore,\n    required this.items,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"hasMore\": hasMore,\n      \"items\": items.map((e) => json.decode(e.toString())).toList(),\n    });\n  }\n}\n\nclass LiveSearchAnchorResult {\n  final bool hasMore;\n  final List<LiveAnchorItem> items;\n  LiveSearchAnchorResult({\n    required this.hasMore,\n    required this.items,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"hasMore\": hasMore,\n      \"items\": items.map((e) => json.decode(e.toString())).toList(),\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/get_cdn_token_ex_req.dart",
    "content": "﻿import 'package:simple_live_core/src/model/tars/types.dart';\nimport 'package:tars_dart/tars/codec/tars_displayer.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass GetCdnTokenExReq extends TarsStruct {\n  String sFlvUrl = \"\"; //tag 0\n  String sStreamName = \"\"; //tag 1\n  int iLoopTime = 0; //tag 2\n  HuyaUserId tId = HuyaUserId(); //tag 3\n  int iAppId = 66; //tag 4\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    sFlvUrl = _is.read(sFlvUrl, 0, false);\n    sStreamName = _is.read(sStreamName, 1, false);\n    iLoopTime = _is.read(iLoopTime, 2, false);\n    tId = _is.read(tId, 3, false);\n    iAppId = _is.read(iAppId, 4, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(sFlvUrl, 0);\n    _os.write(sStreamName, 1);\n    _os.write(iLoopTime, 2);\n    _os.write(tId, 3);\n    _os.write(iAppId, 4);\n  }\n\n  @override\n  TarsStruct deepCopy() {\n    return GetCdnTokenExReq()\n      ..sFlvUrl = sFlvUrl\n      ..sStreamName = sStreamName\n      ..iLoopTime = iLoopTime\n      ..tId = tId\n      ..iAppId = iAppId;\n  }\n\n  @override\n  displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayString(sFlvUrl, \"sFlvUrl\");\n    _ds.DisplayString(sStreamName, \"sStreamName\");\n    _ds.DisplayInt(iLoopTime, \"iLoopTime\");\n    _ds.DisplayTarsStruct(tId, \"tId\");\n    _ds.DisplayInt(iAppId, \"iAppId\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/get_cdn_token_ex_resp.dart",
    "content": "﻿import 'package:tars_dart/tars/codec/tars_displayer.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass GetCdnTokenExResp extends TarsStruct {\n  String sFlvToken = \"\"; //tag 0\n  int iExpireTime = 0; //tag 1\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    sFlvToken = _is.read(sFlvToken, 0, false);\n    iExpireTime = _is.read(iExpireTime, 1, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(sFlvToken, 0);\n    _os.write(iExpireTime, 1);\n  }\n\n  @override\n  TarsStruct deepCopy() {\n    return GetCdnTokenExResp()\n      ..sFlvToken = sFlvToken\n      ..iExpireTime = iExpireTime;\n  }\n\n  @override\n  displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayString(sFlvToken, \"sFlvToken\");\n    _ds.DisplayInt(iExpireTime, \"iExpireTime\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/get_cdn_token_req.dart",
    "content": "// ignore_for_file: no_leading_underscores_for_local_identifiers\n\nimport 'package:tars_dart/tars/codec/tars_displayer.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass GetCdnTokenReq extends TarsStruct {\n  String url = \"\";\n\n  String cdnType = \"\";\n\n  String streamName = \"\";\n\n  int presenterUid = 0;\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    url = _is.read(url, 0, false);\n    cdnType = _is.read(cdnType, 1, false);\n    streamName = _is.read(streamName, 2, false);\n    presenterUid = _is.read(presenterUid, 3, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(url, 0);\n    _os.write(cdnType, 1);\n    _os.write(streamName, 2);\n    _os.write(presenterUid, 3);\n  }\n\n  @override\n  Object deepCopy() {\n    return GetCdnTokenReq()\n      ..url = url\n      ..cdnType = cdnType\n      ..streamName = streamName\n      ..presenterUid = presenterUid;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayString(url, \"url\");\n    _ds.DisplayString(cdnType, \"cdnType\");\n    _ds.DisplayString(streamName, \"streamName\");\n    _ds.DisplayInt(presenterUid, \"presenterUid\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/get_cdn_token_resp.dart",
    "content": "// ignore_for_file: no_leading_underscores_for_local_identifiers\n\nimport 'package:tars_dart/tars/codec/tars_displayer.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass GetCdnTokenResp extends TarsStruct {\n  String url = \"\";\n\n  String cdnType = \"\";\n\n  String streamName = \"\";\n\n  int presenterUid = 0;\n\n  String antiCode = \"\";\n\n  String sTime = \"\";\n\n  String flvAntiCode = \"\";\n\n  String hlsAntiCode = \"\";\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    url = _is.read(url, 0, false);\n    cdnType = _is.read(cdnType, 1, false);\n    streamName = _is.read(streamName, 2, false);\n    presenterUid = _is.read(presenterUid, 3, false);\n    antiCode = _is.read(antiCode, 4, false);\n    sTime = _is.read(sTime, 5, false);\n    flvAntiCode = _is.read(flvAntiCode, 6, false);\n    hlsAntiCode = _is.read(hlsAntiCode, 7, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(url, 0);\n    _os.write(cdnType, 1);\n    _os.write(streamName, 2);\n    _os.write(presenterUid, 3);\n    _os.write(antiCode, 4);\n    _os.write(sTime, 5);\n    _os.write(flvAntiCode, 6);\n    _os.write(hlsAntiCode, 7);\n  }\n\n  @override\n  Object deepCopy() {\n    return GetCdnTokenResp()\n      ..url = url\n      ..cdnType = cdnType\n      ..streamName = streamName\n      ..presenterUid = presenterUid\n      ..antiCode = antiCode\n      ..sTime = sTime\n      ..flvAntiCode = flvAntiCode\n      ..hlsAntiCode = hlsAntiCode;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayString(url, \"url\");\n    _ds.DisplayString(cdnType, \"cdnType\");\n    _ds.DisplayString(streamName, \"streamName\");\n    _ds.DisplayInt(presenterUid, \"presenterUid\");\n    _ds.DisplayString(antiCode, \"antiCode\");\n    _ds.DisplayString(sTime, \"sTime\");\n    _ds.DisplayString(flvAntiCode, \"flvAntiCode\");\n    _ds.DisplayString(hlsAntiCode, \"hlsAntiCode\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/huya_danmaku.dart",
    "content": "// ignore_for_file: no_leading_underscores_for_local_identifiers\n\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass HYPushMessage extends TarsStruct {\n  int pushType = 0;\n  int uri = 0;\n  List<int> msg = <int>[];\n  int protocolType = 0;\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    pushType = _is.read(pushType, 0, false);\n    uri = _is.read(uri, 1, false);\n    msg = _is.readBytes(2, false);\n    protocolType = _is.read(protocolType, 3, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {}\n\n  @override\n  Object deepCopy() {\n    return HYPushMessage()\n      ..pushType = pushType\n      ..uri = uri\n      ..msg = List<int>.from(msg)\n      ..protocolType = protocolType;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {}\n}\n\nclass HYSender extends TarsStruct {\n  int uid = 0;\n  int lMid = 0;\n  String nickName = \"\";\n  int gender = 0;\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    uid = _is.read(uid, 0, false);\n    lMid = _is.read(lMid, 0, false);\n    nickName = _is.read(nickName, 2, false);\n    gender = _is.read(gender, 3, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {}\n\n  @override\n  Object deepCopy() {\n    return HYSender()\n      ..uid = uid\n      ..lMid = lMid\n      ..nickName = nickName\n      ..gender = gender;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {}\n}\n\nclass HYMessage extends TarsStruct {\n  HYSender userInfo = HYSender();\n  String content = \"\";\n  HYBulletFormat bulletFormat = HYBulletFormat();\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    userInfo = _is.readTarsStruct(userInfo, 0, false) as HYSender;\n    content = _is.read(content, 3, false);\n    bulletFormat = _is.readTarsStruct(bulletFormat, 6, false) as HYBulletFormat;\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {}\n\n  @override\n  Object deepCopy() {\n    return HYMessage()\n      ..userInfo = userInfo.deepCopy() as HYSender\n      ..content = content\n      ..bulletFormat = bulletFormat.deepCopy() as HYBulletFormat;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {}\n}\n\nclass HYBulletFormat extends TarsStruct {\n  int fontColor = 0;\n  int fontSize = 4;\n  int textSpeed = 0;\n  int transitionType = 1;\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    fontColor = _is.read(fontColor, 0, false);\n    fontSize = _is.read(fontSize, 1, false);\n    textSpeed = _is.read(textSpeed, 2, false);\n    transitionType = _is.read(transitionType, 3, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {}\n\n  @override\n  Object deepCopy() {\n    return HYBulletFormat()\n      ..fontColor = fontColor\n      ..fontSize = fontSize\n      ..textSpeed = textSpeed\n      ..transitionType = transitionType;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {}\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/tar2dart.dart",
    "content": "﻿import 'dart:io';\n\n// 需要所有字段有 //tag n 注释方便定位-多行编辑生成\n// 可以自动生成这个tag,懒得弄了\nfinal fieldRegex = RegExp(\n  r'^\\s*(\\w+(?:<[^>]+>)?)\\s+(\\w+)\\s*=\\s*[^;]+;\\s*//\\s*tag\\s*(\\d+)',\n);\nfinal classRegex = RegExp(r'class\\s+(\\w+)\\s+extends\\s+TarsStruct');\n\nvoid main(List<String> args) {\n  if (args.isEmpty) {\n    print('Usage: dart run tars_codegen.dart <file.dart>');\n    exit(1);\n  }\n\n  final file = File(args[0]);\n  final lines = file.readAsLinesSync();\n\n  final fields = <Field>[];\n  for (final line in lines) {\n    final m = classRegex.firstMatch(line);\n    if (m != null) {\n      className = m.group(1);\n      break;\n    }\n  }\n  if (className == null) {\n    throw Exception('No class extends TarsStruct found');\n  }\n  for (final line in lines) {\n    final match = fieldRegex.firstMatch(line);\n    if (match != null) {\n      fields.add(Field(\n        type: match.group(1)!,\n        name: match.group(2)!,\n        tag: int.parse(match.group(3)!),\n      ));\n    }\n  }\n\n  fields.sort((a, b) => a.tag.compareTo(b.tag));\n\n  print(generate(fields));\n}\n\nString generate(List<Field> fields) {\n  final sb = StringBuffer();\n\n  // readFrom\n  sb.writeln('@override');\n  sb.writeln('void readFrom(TarsInputStream _is) {');\n  for (final f in fields) {\n    sb.writeln(\n      '  ${padRight(f.name, 20)} = _is.read(${f.name}, ${f.tag}, false);',\n    );\n  }\n  sb.writeln('}\\n');\n\n  // writeTo\n  sb.writeln('@override');\n  sb.writeln('void writeTo(TarsOutputStream _os) {');\n  for (final f in fields) {\n    sb.writeln('  _os.write(${f.name}, ${f.tag});');\n  }\n  sb.writeln('}\\n');\n\n  // deepCopy\n  sb.writeln('@override');\n  sb.writeln('TarsStruct deepCopy() {');\n  sb.writeln('  return $className()');\n  for (final f in fields) {\n    sb.writeln('    ..${f.name} = ${f.name}');\n  }\n  sb.writeln('  ;');\n  sb.writeln('}\\n');\n\n  // display\n  sb.writeln('@override');\n  sb.writeln('displayAsString(StringBuffer sb, int level) {');\n  sb.writeln('  TarsDisplayer _ds = TarsDisplayer(sb, level: level);');\n\n  for (final f in fields) {\n    sb.writeln(\n      '  _ds.${displayMethod(f.type)}(${f.name}, \"${f.name}\");',\n    );\n  }\n  sb.writeln('}');\n\n  return sb.toString();\n}\n\nString displayMethod(String type) {\n  if (type.startsWith('List')) return 'DisplayList';\n  if (type.startsWith('Map')) return 'DisplayMap';\n  if (type == 'String') return 'DisplayString';\n  if (type == 'int') return 'DisplayInt';\n  return 'DisplayTarsStruct';\n}\n\nString padRight(String s, int width) => s + ' ' * (width - s.length);\n\nlate String? className;\n\nclass Field {\n  final String type;\n  final String name;\n  final int tag;\n\n  Field({\n    required this.type,\n    required this.name,\n    required this.tag,\n  });\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/model/tars/types.dart",
    "content": "﻿import 'package:tars_dart/tars/codec/tars_displayer.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_struct.dart';\n\nclass HuyaUserId extends TarsStruct {\n  int lUid = 0;\n  String sGuid = \"\";\n  String sToken = \"\";\n  String sHuYaUA = \"\";\n  String sCookie = \"\";\n  int iTokenType = 0;\n  String sDeviceInfo = \"\";\n  String sQIMEI = \"\";\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    lUid = _is.read(lUid, 0, false);\n    sGuid = _is.read(sGuid, 1, false);\n    sToken = _is.read(sToken, 2, false);\n    sHuYaUA = _is.read(sHuYaUA, 3, false);\n    sCookie = _is.read(sCookie, 4, false);\n    iTokenType = _is.read(iTokenType, 5, false);\n    sDeviceInfo = _is.read(sDeviceInfo, 6, false);\n    sQIMEI = _is.read(sQIMEI, 7, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(lUid, 0);\n    _os.write(sGuid, 1);\n    _os.write(sToken, 2);\n    _os.write(sHuYaUA, 3);\n    _os.write(sCookie, 4);\n    _os.write(iTokenType, 5);\n    _os.write(sDeviceInfo, 6);\n    _os.write(sQIMEI, 7);\n  }\n\n  @override\n  Object deepCopy() {\n    return HuyaUserId()\n      ..lUid = lUid\n      ..sGuid = sGuid\n      ..sToken = sToken\n      ..sHuYaUA = sHuYaUA\n      ..sCookie = sCookie\n      ..iTokenType = iTokenType\n      ..sDeviceInfo = sDeviceInfo\n      ..sQIMEI = sQIMEI;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayInt(lUid, \"lUid\");\n    _ds.DisplayString(sGuid, \"sGuid\");\n    _ds.DisplayString(sToken, \"sToken\");\n    _ds.DisplayString(sHuYaUA, \"sHuYaUA\");\n    _ds.DisplayString(sCookie, \"sCookie\");\n    _ds.DisplayInt(iTokenType, \"iTokenType\");\n    _ds.DisplayString(sDeviceInfo, \"sDeviceInfo\");\n    _ds.DisplayString(sQIMEI, \"sQIMEI\");\n  }\n}\n\nclass GetLivingInfoReq extends TarsStruct {\n  HuyaUserId tId = HuyaUserId();\n  int lTopSid = 0;\n  int lSubSid = 0;\n  int lPresenterUid = 0;\n  int lRoomId = 0;\n  String sTraceSource = \"\";\n  String sPassword = \"\";\n  int iRoomId = 0;\n  int iFreeFlowFlag = 0;\n  int iIpStack = 0;\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    tId = _is.read(tId, 0, false);\n    lTopSid = _is.read(lTopSid, 1, false);\n    lSubSid = _is.read(lSubSid, 2, false);\n    lPresenterUid = _is.read(lPresenterUid, 3, false);\n    lRoomId = _is.read(lRoomId, 4, false);\n    sTraceSource = _is.read(sTraceSource, 5, false);\n    sPassword = _is.read(sPassword, 6, false);\n    iRoomId = _is.read(iRoomId, 7, false);\n    iFreeFlowFlag = _is.read(iFreeFlowFlag, 8, false);\n    iIpStack = _is.read(iIpStack, 9, false);\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(tId, 0);\n    _os.write(lTopSid, 1);\n    _os.write(lSubSid, 2);\n    _os.write(lPresenterUid, 3);\n    _os.write(lRoomId, 4);\n    _os.write(sTraceSource, 5);\n    _os.write(sPassword, 6);\n    _os.write(iRoomId, 7);\n    _os.write(iFreeFlowFlag, 8);\n    _os.write(iIpStack, 9);\n  }\n\n  @override\n  Object deepCopy() {\n    return GetLivingInfoReq()\n      ..tId = tId.deepCopy() as HuyaUserId\n      ..lTopSid = lTopSid\n      ..lSubSid = lSubSid\n      ..lPresenterUid = lPresenterUid\n      ..lRoomId = lRoomId\n      ..sTraceSource = sTraceSource\n      ..sPassword = sPassword\n      ..iRoomId = iRoomId\n      ..iFreeFlowFlag = iFreeFlowFlag\n      ..iIpStack = iIpStack;\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {\n    TarsDisplayer _ds = TarsDisplayer(sb, level: level);\n    _ds.DisplayTarsStruct(tId, \"tId\");\n    _ds.DisplayInt(lTopSid, \"lTopSid\");\n    _ds.DisplayInt(lSubSid, \"lSubSid\");\n    _ds.DisplayInt(lPresenterUid, \"lPresenterUid\");\n    _ds.DisplayInt(lRoomId, \"lRoomId\");\n    _ds.DisplayString(sTraceSource, \"sTraceSource\");\n    _ds.DisplayString(sPassword, \"sPassword\");\n    _ds.DisplayInt(iRoomId, \"iRoomId\");\n    _ds.DisplayInt(iFreeFlowFlag, \"iFreeFlowFlag\");\n    _ds.DisplayInt(iIpStack, \"iIpStack\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/bilibili/bilibili_site.dart",
    "content": "import 'dart:convert';\n\nimport 'package:crypto/crypto.dart';\nimport 'package:simple_live_core/src/common/convert_helper.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\nimport 'package:simple_live_core/src/danmaku/bilibili_danmaku.dart';\nimport 'package:simple_live_core/src/interface/live_danmaku.dart';\nimport 'package:simple_live_core/src/interface/live_site.dart';\nimport 'package:simple_live_core/src/model/live_anchor_item.dart';\nimport 'package:simple_live_core/src/model/live_category.dart';\nimport 'package:simple_live_core/src/model/live_message.dart';\nimport 'package:simple_live_core/src/model/live_play_url.dart';\nimport 'package:simple_live_core/src/model/live_room_item.dart';\nimport 'package:simple_live_core/src/model/live_search_result.dart';\nimport 'package:simple_live_core/src/model/live_room_detail.dart';\nimport 'package:simple_live_core/src/model/live_play_quality.dart';\nimport 'package:simple_live_core/src/model/live_category_result.dart';\n\nclass BiliBiliSite implements LiveSite {\n  @override\n  String id = \"bilibili\";\n\n  @override\n  String name = \"哔哩哔哩直播\";\n\n  String cookie = \"\";\n  int userId = 0;\n\n  @override\n  LiveDanmaku getDanmaku() => BiliBiliDanmaku();\n\n  static const String kDefaultUserAgent =\n      \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0\";\n  static const String kDefaultReferer = \"https://live.bilibili.com/\";\n\n  String buvid3 = \"\";\n  String buvid4 = \"\";\n  String accessId = \"\";\n  Future<Map<String, String>> getHeader() async {\n    if (buvid3.isEmpty) {\n      var buvidInfo = await getBuvid();\n      buvid3 = buvidInfo[\"b_3\"] ?? \"\";\n      buvid4 = buvidInfo[\"b_4\"] ?? \"\";\n    }\n    return cookie.isEmpty\n        ? {\n            \"user-agent\": kDefaultUserAgent,\n            \"referer\": kDefaultReferer,\n            \"cookie\": 'buvid3=$buvid3;buvid4=$buvid4;',\n          }\n        : {\n            \"cookie\": cookie.contains(\"buvid3\")\n                ? cookie\n                : \"$cookie;buvid3=$buvid3;buvid4=$buvid4;\",\n            \"user-agent\": kDefaultUserAgent,\n            \"referer\": kDefaultReferer,\n          };\n  }\n\n  @override\n  Future<List<LiveCategory>> getCategores() async {\n    List<LiveCategory> categories = [];\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/room/v1/Area/getList\",\n      queryParameters: {\n        \"need_entrance\": 1,\n        \"parent_id\": 0,\n      },\n      header: await getHeader(),\n    );\n    for (var item in result[\"data\"]) {\n      List<LiveSubCategory> subs = [];\n      for (var subItem in item[\"list\"]) {\n        var subCategory = LiveSubCategory(\n          id: subItem[\"id\"].toString(),\n          name: asT<String?>(subItem[\"name\"]) ?? \"\",\n          parentId: asT<String?>(subItem[\"parent_id\"]) ?? \"\",\n          pic: \"${asT<String?>(subItem[\"pic\"]) ?? \"\"}@100w.png\",\n        );\n        subs.add(subCategory);\n      }\n      var category = LiveCategory(\n        children: subs,\n        id: item[\"id\"].toString(),\n        name: asT<String?>(item[\"name\"]) ?? \"\",\n      );\n      categories.add(category);\n    }\n    return categories;\n  }\n\n  @override\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) async {\n    const baseUrl =\n        \"https://api.live.bilibili.com/xlive/web-interface/v1/second/getList\";\n\n    var url =\n        \"$baseUrl?platform=web&parent_area_id=${category.parentId}&area_id=${category.id}&sort_type=&page=$page&w_webid=${await getAccessId()}\";\n\n    var queryParams = await getWbiSign(url);\n\n    var result = await HttpClient.instance.getJson(\n      baseUrl,\n      queryParameters: queryParams,\n      header: await getHeader(),\n    );\n\n    var hasMore = result[\"data\"][\"has_more\"] == 1;\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"list\"]) {\n      var roomItem = LiveRoomItem(\n        roomId: item[\"roomid\"].toString(),\n        title: item[\"title\"].toString(),\n        cover: \"${item[\"cover\"]}@400w.jpg\",\n        userName: item[\"uname\"].toString(),\n        online: int.tryParse(item[\"online\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) async {\n    List<LivePlayQuality> qualities = [];\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo\",\n      queryParameters: {\n        \"room_id\": detail.roomId,\n        \"protocol\": \"0,1\",\n        \"format\": \"0,1,2\",\n        \"codec\": \"0,1\",\n        \"platform\": \"web\",\n      },\n      header: await getHeader(),\n    );\n    var qualitiesMap = <int, String>{};\n    for (var item in result[\"data\"][\"playurl_info\"][\"playurl\"][\"g_qn_desc\"]) {\n      qualitiesMap[int.tryParse(item[\"qn\"].toString()) ?? 0] =\n          item[\"desc\"].toString();\n    }\n\n    for (var item in result[\"data\"][\"playurl_info\"][\"playurl\"][\"stream\"][0]\n        [\"format\"][0][\"codec\"][0][\"accept_qn\"]) {\n      var qualityItem = LivePlayQuality(\n        quality: qualitiesMap[item] ?? \"未知清晰度\",\n        data: item,\n      );\n      qualities.add(qualityItem);\n    }\n    return qualities;\n  }\n\n  @override\n  Future<LivePlayUrl> getPlayUrls(\n      {required LiveRoomDetail detail,\n      required LivePlayQuality quality}) async {\n    List<String> urls = [];\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo\",\n      queryParameters: {\n        \"room_id\": detail.roomId,\n        \"protocol\": \"0,1\",\n        \"format\": \"0,2\",\n        \"codec\": \"0\",\n        \"platform\": \"web\",\n        \"qn\": quality.data,\n      },\n      header: await getHeader(),\n    );\n    var streamList = result[\"data\"][\"playurl_info\"][\"playurl\"][\"stream\"];\n    for (var streamItem in streamList) {\n      var formatList = streamItem[\"format\"];\n      for (var formatItem in formatList) {\n        var codecList = formatItem[\"codec\"];\n        for (var codecItem in codecList) {\n          var urlList = codecItem[\"url_info\"];\n          var baseUrl = codecItem[\"base_url\"].toString();\n          for (var urlItem in urlList) {\n            urls.add(\n              \"${urlItem[\"host\"]}$baseUrl${urlItem[\"extra\"]}\",\n            );\n          }\n        }\n      }\n    }\n    // 对链接进行排序，包含mcdn的在后\n    urls.sort((a, b) {\n      if (a.contains(\"mcdn\")) {\n        return 1;\n      } else {\n        return -1;\n      }\n    });\n    return LivePlayUrl(\n      urls: urls,\n      headers: {\n        \"referer\": \"https://live.bilibili.com\",\n        \"user-agent\":\n            \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188\"\n      },\n    );\n  }\n\n  @override\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) async {\n    const baseUrl =\n        \"https://api.live.bilibili.com/xlive/web-interface/v1/second/getListByArea\";\n    var url = \"$baseUrl?platform=web&sort=online&page_size=30&page=$page\";\n\n    var queryParams = await getWbiSign(url);\n\n    var result = await HttpClient.instance.getJson(\n      baseUrl,\n      queryParameters: queryParams,\n      header: await getHeader(),\n    );\n\n    var hasMore = (result[\"data\"][\"list\"] as List).isNotEmpty;\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"list\"]) {\n      var roomItem = LiveRoomItem(\n        roomId: item[\"roomid\"].toString(),\n        title: item[\"title\"].toString(),\n        cover: \"${item[\"cover\"]}@400w.jpg\",\n        userName: item[\"uname\"].toString(),\n        online: int.tryParse(item[\"online\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) async {\n    var roomInfo = await getRoomInfo(roomId: roomId);\n    var realRoomId = roomInfo[\"room_info\"][\"room_id\"].toString();\n    var url =\n        \"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=$realRoomId\";\n    var queryParams = await getWbiSign(url);\n    var roomDanmakuResult = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo\",\n      queryParameters: queryParams,\n      header: await getHeader(),\n    );\n    List<String> serverHosts = (roomDanmakuResult[\"data\"][\"host_list\"] as List)\n        .map<String>((e) => e[\"host\"].toString())\n        .toList();\n\n    //var buvid = await getBuvid();\n    return LiveRoomDetail(\n      roomId: realRoomId,\n      title: roomInfo[\"room_info\"][\"title\"].toString(),\n      cover: roomInfo[\"room_info\"][\"cover\"].toString(),\n      userName: roomInfo[\"anchor_info\"][\"base_info\"][\"uname\"].toString(),\n      userAvatar: \"${roomInfo[\"anchor_info\"][\"base_info\"][\"face\"]}@100w.jpg\",\n      online: asT<int?>(roomInfo[\"room_info\"][\"online\"]) ?? 0,\n      status: (asT<int?>(roomInfo[\"room_info\"][\"live_status\"]) ?? 0) == 1,\n      url: \"https://live.bilibili.com/$roomId\",\n      introduction: roomInfo[\"room_info\"][\"description\"].toString(),\n      notice: \"\",\n      danmakuData: BiliBiliDanmakuArgs(\n        roomId: int.tryParse(realRoomId) ?? 0,\n        uid: userId,\n        token: roomDanmakuResult[\"data\"][\"token\"].toString(),\n        serverHost: serverHosts.isNotEmpty\n            ? serverHosts.first\n            : \"broadcastlv.chat.bilibili.com\",\n        buvid: buvid3,\n        cookie: cookie,\n      ),\n    );\n  }\n\n  Future<Map<String, dynamic>> getRoomInfo({required String roomId}) async {\n    var url =\n        \"https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=$roomId\";\n    var queryParams = await getWbiSign(url);\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom\",\n      queryParameters: queryParams,\n      header: await getHeader(),\n    );\n    return result[\"data\"];\n  }\n\n  @override\n  Future<LiveSearchRoomResult> searchRooms(String keyword,\n      {int page = 1}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://api.bilibili.com/x/web-interface/search/type?context=&search_type=live&cover_type=user_cover\",\n      queryParameters: {\n        \"order\": \"\",\n        \"keyword\": keyword,\n        \"category_id\": \"\",\n        \"__refresh__\": \"\",\n        \"_extra\": \"\",\n        \"highlight\": 0,\n        \"single_column\": 0,\n        \"page\": page\n      },\n      header: await getHeader(),\n    );\n\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"result\"][\"live_room\"] ?? []) {\n      var title = item[\"title\"].toString();\n      //移除title中的<em></em>标签\n      title = title.replaceAll(RegExp(r\"<.*?em.*?>\"), \"\");\n      var roomItem = LiveRoomItem(\n        roomId: item[\"roomid\"].toString(),\n        title: title,\n        cover: \"https:${item[\"cover\"]}@400w.jpg\",\n        userName: item[\"uname\"].toString(),\n        online: int.tryParse(item[\"online\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    return LiveSearchRoomResult(hasMore: items.length >= 40, items: items);\n  }\n\n  @override\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword,\n      {int page = 1}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://api.bilibili.com/x/web-interface/search/type?context=&search_type=live_user&cover_type=user_cover\",\n      queryParameters: {\n        \"order\": \"\",\n        \"keyword\": keyword,\n        \"category_id\": \"\",\n        \"__refresh__\": \"\",\n        \"_extra\": \"\",\n        \"highlight\": 0,\n        \"single_column\": 0,\n        \"page\": page\n      },\n      header: await getHeader(),\n    );\n\n    var items = <LiveAnchorItem>[];\n    for (var item in result[\"data\"][\"result\"] ?? []) {\n      var uname = item[\"uname\"].toString();\n      //移除title中的<em></em>标签\n      uname = uname.replaceAll(RegExp(r\"<.*?em.*?>\"), \"\");\n      var anchorItem = LiveAnchorItem(\n        roomId: item[\"roomid\"].toString(),\n        avatar: \"https:${item[\"uface\"]}@400w.jpg\",\n        userName: uname,\n        liveStatus: item[\"is_live\"],\n      );\n      items.add(anchorItem);\n    }\n    return LiveSearchAnchorResult(hasMore: items.length >= 40, items: items);\n  }\n\n  @override\n  Future<bool> getLiveStatus({required String roomId}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/room/v1/Room/get_info\",\n      queryParameters: {\n        \"room_id\": roomId,\n      },\n      header: await getHeader(),\n    );\n    return (asT<int?>(result[\"data\"][\"live_status\"]) ?? 0) == 1;\n  }\n\n  @override\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://api.live.bilibili.com/av/v1/SuperChat/getMessageList\",\n      queryParameters: {\n        \"room_id\": roomId,\n      },\n      header: await getHeader(),\n    );\n    List<LiveSuperChatMessage> ls = [];\n    for (var item in result[\"data\"]?[\"list\"] ?? []) {\n      var message = LiveSuperChatMessage(\n        backgroundBottomColor: item[\"background_bottom_color\"].toString(),\n        backgroundColor: item[\"background_color\"].toString(),\n        endTime: DateTime.fromMillisecondsSinceEpoch(\n          item[\"end_time\"] * 1000,\n        ),\n        face: \"${item[\"user_info\"][\"face\"]}@200w.jpg\",\n        message: item[\"message\"].toString(),\n        price: item[\"price\"],\n        startTime: DateTime.fromMillisecondsSinceEpoch(\n          item[\"start_time\"] * 1000,\n        ),\n        userName: item[\"user_info\"][\"uname\"].toString(),\n      );\n      ls.add(message);\n    }\n    return ls;\n  }\n\n  /// 获取 buvid3 和 buvid4\n  /// 返回buvid3和buvid4\n  /// ``` json\n  /// {\n  ///   \"b_3\": \"buvid3\",\n  ///   \"b_4\": \"buvid4\",\n  /// }\n  /// ```\n  Future<Map> getBuvid() async {\n    try {\n      if (cookie.contains(\"buvid3\")) {\n        return {\n          \"b_3\": RegExp(r\"buvid3=(.*?);\").firstMatch(cookie)?.group(1) ?? \"\",\n          \"b_4\": RegExp(r\"buvid4=(.*?);\").firstMatch(cookie)?.group(1) ?? \"\",\n        };\n      }\n\n      var result = await HttpClient.instance.getJson(\n        \"https://api.bilibili.com/x/frontend/finger/spi\",\n        queryParameters: {},\n        header: {\n          \"user-agent\": kDefaultUserAgent,\n          \"referer\": kDefaultReferer,\n          \"cookie\": cookie,\n        },\n      );\n      return result[\"data\"];\n    } catch (e) {\n      return {\n        \"b_3\": \"\",\n        \"b_4\": \"\",\n      };\n    }\n  }\n\n  static String kImgKey = '';\n  static String kSubKey = '';\n  static const List<int> mixinKeyEncTab = [\n    46,\n    47,\n    18,\n    2,\n    53,\n    8,\n    23,\n    32,\n    15,\n    50,\n    10,\n    31,\n    58,\n    3,\n    45,\n    35,\n    27,\n    43,\n    5,\n    49,\n    33,\n    9,\n    42,\n    19,\n    29,\n    28,\n    14,\n    39,\n    12,\n    38,\n    41,\n    13,\n    37,\n    48,\n    7,\n    16,\n    24,\n    55,\n    40,\n    61,\n    26,\n    17,\n    0,\n    1,\n    60,\n    51,\n    30,\n    4,\n    22,\n    25,\n    54,\n    21,\n    56,\n    59,\n    6,\n    63,\n    57,\n    62,\n    11,\n    36,\n    20,\n    34,\n    44,\n    52\n  ];\n  Future<(String, String)> getWbiKeys() async {\n    if (kImgKey.isNotEmpty && kSubKey.isNotEmpty) {\n      return (kImgKey, kSubKey);\n    }\n    // 获取最新的 img_key 和 sub_key\n    var resp = await HttpClient.instance.getJson(\n      'https://api.bilibili.com/x/web-interface/nav',\n      header: await getHeader(),\n    );\n\n    var imgUrl = resp[\"data\"][\"wbi_img\"][\"img_url\"].toString();\n    var subUrl = resp[\"data\"][\"wbi_img\"][\"sub_url\"].toString();\n    var imgKey = imgUrl.substring(imgUrl.lastIndexOf('/') + 1).split('.').first;\n    var subKey = subUrl.substring(subUrl.lastIndexOf('/') + 1).split('.').first;\n\n    kImgKey = imgKey;\n    kSubKey = subKey;\n\n    return (imgKey, subKey);\n  }\n\n  String getMixinKey(String origin) {\n    // 对 imgKey 和 subKey 进行字符顺序打乱编码\n    return mixinKeyEncTab.fold(\"\", (s, i) => s + origin[i]).substring(0, 32);\n  }\n\n  Future<Map<String, String>> getWbiSign(String url) async {\n    var (imgKey, subKey) = await getWbiKeys();\n\n    // 为请求参数进行 wbi 签名\n    var mixinKey = getMixinKey(imgKey + subKey);\n    var currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;\n\n    var queryParams = Map<String, String>.from(Uri.parse(url).queryParameters);\n\n    queryParams[\"wts\"] = currentTime.toString(); // 添加 wts 字段\n\n    //按照 key 重排参数\n    Map<String, String> map = {};\n    var sortedKeys = queryParams.keys.toList()..sort();\n    for (var key in sortedKeys) {\n      var value = queryParams[key]!;\n      // 过滤 value 中的 \"!'()*\" 字符\n      map[key] = value\n          .toString()\n          .split('')\n          .where((c) => \"!'()*\".contains(c) == false)\n          .join('');\n    }\n\n    var query = map.keys\n        .map((key) => \"$key=${Uri.encodeQueryComponent(map[key]!)}\")\n        .join(\"&\");\n    var wbiSign = md5.convert(utf8.encode(\"$query$mixinKey\")).toString();\n    queryParams[\"w_rid\"] = wbiSign;\n    return queryParams;\n  }\n\n  Future<String> getAccessId() async {\n    if (accessId.isNotEmpty) {\n      return accessId;\n    }\n\n    // 获取 access_id\n    var resp = await HttpClient.instance.getText(\n      \"https://live.bilibili.com/lol\",\n      queryParameters: {},\n      header: await getHeader(),\n    );\n    var id = RegExp(r'\"access_id\":\"(.*?)\"')\n        .firstMatch(resp)\n        ?.group(1)\n        ?.replaceAll(\"\\\\\", \"\");\n    accessId = id ?? \"\";\n    return accessId;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/douyin/abogus.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\nimport 'dart:typed_data';\nimport 'package:dart_sm/dart_sm.dart';\n\nclass StringProcessor {\n  static String toCharStr(List<int> codes) {\n    return String.fromCharCodes(codes);\n  }\n\n  static List<int> toOrdArray(String s) {\n    return s.codeUnits;\n  }\n\n  static int jsShiftRight(int val, int n) {\n    return (val & 0xFFFFFFFF) >>> n;\n  }\n\n  static String generateRandomBytes({int length = 3}) {\n    List<String> generateByteSequence() {\n      final rd = Random().nextInt(10000);\n      return [\n        String.fromCharCode(((rd & 255) & 170) | 1),\n        String.fromCharCode(((rd & 255) & 85) | 2),\n        String.fromCharCode((jsShiftRight(rd, 8) & 170) | 5),\n        String.fromCharCode((jsShiftRight(rd, 8) & 85) | 40),\n      ];\n    }\n\n    final result = <String>[];\n    for (var i = 0; i < length; i++) {\n      result.addAll(generateByteSequence());\n    }\n\n    return result.join('');\n  }\n}\n\nclass CryptoUtility {\n  final String salt;\n  final List<String> base64Alphabet;\n  late List<int> bigArray;\n\n  CryptoUtility(this.salt, this.base64Alphabet) {\n    // fmt: off\n    bigArray = [\n      121,\n      243,\n      55,\n      234,\n      103,\n      36,\n      47,\n      228,\n      30,\n      231,\n      106,\n      6,\n      115,\n      95,\n      78,\n      101,\n      250,\n      207,\n      198,\n      50,\n      139,\n      227,\n      220,\n      105,\n      97,\n      143,\n      34,\n      28,\n      194,\n      215,\n      18,\n      100,\n      159,\n      160,\n      43,\n      8,\n      169,\n      217,\n      180,\n      120,\n      247,\n      45,\n      90,\n      11,\n      27,\n      197,\n      46,\n      3,\n      84,\n      72,\n      5,\n      68,\n      62,\n      56,\n      221,\n      75,\n      144,\n      79,\n      73,\n      161,\n      178,\n      81,\n      64,\n      187,\n      134,\n      117,\n      186,\n      118,\n      16,\n      241,\n      130,\n      71,\n      89,\n      147,\n      122,\n      129,\n      65,\n      40,\n      88,\n      150,\n      110,\n      219,\n      199,\n      255,\n      181,\n      254,\n      48,\n      4,\n      195,\n      248,\n      208,\n      32,\n      116,\n      167,\n      69,\n      201,\n      17,\n      124,\n      125,\n      104,\n      96,\n      83,\n      80,\n      127,\n      236,\n      108,\n      154,\n      126,\n      204,\n      15,\n      20,\n      135,\n      112,\n      158,\n      13,\n      1,\n      188,\n      164,\n      210,\n      237,\n      222,\n      98,\n      212,\n      77,\n      253,\n      42,\n      170,\n      202,\n      26,\n      22,\n      29,\n      182,\n      251,\n      10,\n      173,\n      152,\n      58,\n      138,\n      54,\n      141,\n      185,\n      33,\n      157,\n      31,\n      252,\n      132,\n      233,\n      235,\n      102,\n      196,\n      191,\n      223,\n      240,\n      148,\n      39,\n      123,\n      92,\n      82,\n      128,\n      109,\n      57,\n      24,\n      38,\n      113,\n      209,\n      245,\n      2,\n      119,\n      153,\n      229,\n      189,\n      214,\n      230,\n      174,\n      232,\n      63,\n      52,\n      205,\n      86,\n      140,\n      66,\n      175,\n      111,\n      171,\n      246,\n      133,\n      238,\n      193,\n      99,\n      60,\n      74,\n      91,\n      225,\n      51,\n      76,\n      37,\n      145,\n      211,\n      166,\n      151,\n      213,\n      206,\n      0,\n      200,\n      244,\n      176,\n      218,\n      44,\n      184,\n      172,\n      49,\n      216,\n      93,\n      168,\n      53,\n      21,\n      183,\n      41,\n      67,\n      85,\n      224,\n      155,\n      226,\n      242,\n      87,\n      177,\n      146,\n      70,\n      190,\n      12,\n      162,\n      19,\n      137,\n      114,\n      25,\n      165,\n      163,\n      192,\n      23,\n      59,\n      9,\n      94,\n      179,\n      107,\n      35,\n      7,\n      142,\n      131,\n      239,\n      203,\n      149,\n      136,\n      61,\n      249,\n      14,\n      156\n    ];\n    // fmt: on\n  }\n\n  static List<int> sm3ToArray(dynamic inputData) {\n    Uint8List inputDataBytes;\n    if (inputData is String) {\n      inputDataBytes = utf8.encode(inputData);\n    } else if (inputData is List<int>) {\n      inputDataBytes = Uint8List.fromList(inputData);\n    } else {\n      throw ArgumentError(\"Input data must be a String or List<int>\");\n    }\n    final hexResult = SM3.hashBytes(inputDataBytes);\n    final result = <int>[];\n    for (var i = 0; i < hexResult.length; i += 2) {\n      result.add(int.parse(hexResult.substring(i, i + 2), radix: 16));\n    }\n    return result;\n  }\n\n  String addSalt(String param) {\n    return param + salt;\n  }\n\n  dynamic processParam(dynamic param, bool addSaltFlag) {\n    if (param is String && addSaltFlag) {\n      return addSalt(param);\n    }\n    return param;\n  }\n\n  List<int> paramsToArray(dynamic param, {bool addSalt = true}) {\n    final processedParam = processParam(param, addSalt);\n    return sm3ToArray(processedParam);\n  }\n\n  String transformBytes(List<int> bytesList) {\n    final bytesStr = StringProcessor.toCharStr(bytesList);\n    final resultStr = <String>[];\n    var indexB = bigArray[1];\n    var initialValue = 0;\n    var valueE = 0; // To hold the value for the next iteration\n\n    for (var index = 0; index < bytesStr.length; index++) {\n      final char = bytesStr[index];\n      var sumInitial = 0;\n\n      if (index == 0) {\n        initialValue = bigArray[indexB];\n        sumInitial = indexB + initialValue;\n\n        bigArray[1] = initialValue;\n        bigArray[indexB] = indexB;\n      } else {\n        sumInitial = initialValue + valueE;\n      }\n\n      final charValue = char.codeUnitAt(0);\n      sumInitial %= bigArray.length;\n      final valueF = bigArray[sumInitial];\n      final encryptedChar = charValue ^ valueF;\n      resultStr.add(String.fromCharCode(encryptedChar));\n\n      valueE = bigArray[(index + 2) % bigArray.length];\n      sumInitial = (indexB + valueE) % bigArray.length;\n      initialValue = bigArray[sumInitial];\n      bigArray[sumInitial] = bigArray[(index + 2) % bigArray.length];\n      bigArray[(index + 2) % bigArray.length] = initialValue;\n      indexB = sumInitial;\n    }\n\n    return resultStr.join('');\n  }\n\n  String base64Encode(String inputString, {int selectedAlphabet = 0}) {\n    var binaryString = inputString.codeUnits\n        .map((c) => c.toRadixString(2).padLeft(8, '0'))\n        .join('');\n\n    final paddingLength = (6 - binaryString.length % 6) % 6;\n    binaryString += '0' * paddingLength;\n\n    final base64Indices = <int>[];\n    for (var i = 0; i < binaryString.length; i += 6) {\n      base64Indices.add(int.parse(binaryString.substring(i, i + 6), radix: 2));\n    }\n\n    var outputString = base64Indices\n        .map((index) => base64Alphabet[selectedAlphabet][index])\n        .join('');\n\n    outputString += '=' * (paddingLength ~/ 2);\n    return outputString;\n  }\n\n  String abogusEncode(String abogusBytesStr, int selectedAlphabet) {\n    final abogus = <String>[];\n    final alphabet = base64Alphabet[selectedAlphabet];\n\n    for (var i = 0; i < abogusBytesStr.length; i += 3) {\n      int n;\n      if (i + 2 < abogusBytesStr.length) {\n        n = (abogusBytesStr.codeUnitAt(i) << 16) |\n            (abogusBytesStr.codeUnitAt(i + 1) << 8) |\n            abogusBytesStr.codeUnitAt(i + 2);\n      } else if (i + 1 < abogusBytesStr.length) {\n        n = (abogusBytesStr.codeUnitAt(i) << 16) |\n            (abogusBytesStr.codeUnitAt(i + 1) << 8);\n      } else {\n        n = abogusBytesStr.codeUnitAt(i) << 16;\n      }\n\n      final shifts = [18, 12, 6, 0];\n      final masks = [0xFC0000, 0x03F000, 0x0FC0, 0x3F];\n\n      for (var j = 0; j < shifts.length; j++) {\n        if (shifts[j] == 6 && i + 1 >= abogusBytesStr.length) break;\n        if (shifts[j] == 0 && i + 2 >= abogusBytesStr.length) break;\n        abogus.add(alphabet[(n & masks[j]) >> shifts[j]]);\n      }\n    }\n\n    abogus.add('=' * ((4 - abogus.length % 4) % 4));\n    return abogus.join('');\n  }\n\n  static Uint8List rc4Encrypt(Uint8List key, String plaintext) {\n    final s = List<int>.generate(256, (i) => i);\n    var j = 0;\n    for (var i = 0; i < 256; i++) {\n      j = (j + s[i] + key[i % key.length]) % 256;\n      final temp = s[i];\n      s[i] = s[j];\n      s[j] = temp;\n    }\n\n    var i = 0;\n    j = 0;\n    final ciphertext = <int>[];\n    for (final char in plaintext.codeUnits) {\n      i = (i + 1) % 256;\n      j = (j + s[i]) % 256;\n      final temp = s[i];\n      s[i] = s[j];\n      s[j] = temp;\n      final k = s[(s[i] + s[j]) % 256];\n      ciphertext.add(char ^ k);\n    }\n\n    return Uint8List.fromList(ciphertext);\n  }\n}\n\nclass BrowserFingerprintGenerator {\n  static String generateFingerprint({String browserType = \"Edge\"}) {\n    final browsers = {\n      \"Chrome\": generateChromeFingerprint,\n      \"Firefox\": generateFirefoxFingerprint,\n      \"Safari\": generateSafariFingerprint,\n      \"Edge\": generateEdgeFingerprint,\n    };\n    return (browsers[browserType] ?? generateChromeFingerprint)();\n  }\n\n  static String generateChromeFingerprint() =>\n      _generateFingerprint(platform: \"Win32\");\n  static String generateFirefoxFingerprint() =>\n      _generateFingerprint(platform: \"Win32\");\n  static String generateSafariFingerprint() =>\n      _generateFingerprint(platform: \"MacIntel\");\n  static String generateEdgeFingerprint() =>\n      _generateFingerprint(platform: \"Win32\");\n\n  static String _generateFingerprint({required String platform}) {\n    final random = Random();\n    final innerWidth = 1024 + random.nextInt(1920 - 1024 + 1);\n    final innerHeight = 768 + random.nextInt(1080 - 768 + 1);\n    final outerWidth = innerWidth + (24 + random.nextInt(32 - 24 + 1));\n    final outerHeight = innerHeight + (75 + random.nextInt(90 - 75 + 1));\n    const screenX = 0;\n    final screenY = [0, 30][random.nextInt(2)];\n    final sizeWidth = 1024 + random.nextInt(1920 - 1024 + 1);\n    final sizeHeight = 768 + random.nextInt(1080 - 768 + 1);\n    final availWidth = 1280 + random.nextInt(1920 - 1280 + 1);\n    final availHeight = 800 + random.nextInt(1080 - 800 + 1);\n\n    return \"$innerWidth|$innerHeight|$outerWidth|$outerHeight|\"\n        \"$screenX|$screenY|0|0|$sizeWidth|$sizeHeight|\"\n        \"$availWidth|$availHeight|$innerWidth|$innerHeight|24|24|$platform\";\n  }\n}\n\nclass ABogus {\n  final String userAgent;\n  final String browserFp;\n  final List<int> options;\n\n  final int aid = 6383;\n  final int pageId = 0;\n  final String salt = \"cus\";\n  final bool boe = false;\n  final double ddrt = 8.5;\n  final double ic = 8.5;\n  final List<String> paths = [\n    \"^/webcast/\",\n    \"^/aweme/v1/\",\n    \"^/aweme/v2/\",\n    \"/v1/message/send\",\n    \"^/live/\",\n    \"^/captcha/\",\n    \"^/ecom/\",\n  ];\n  final Uint8List uaKey = Uint8List.fromList([0, 1, 14]);\n\n  final String character =\n      \"Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe\";\n  final String character2 =\n      \"ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe\";\n  late final List<String> characterList;\n  late final CryptoUtility cryptoUtility;\n\n  // fmt: off\n  final List<int> sortIndex = [\n    18,\n    20,\n    52,\n    26,\n    30,\n    34,\n    58,\n    38,\n    40,\n    53,\n    42,\n    21,\n    27,\n    54,\n    55,\n    31,\n    35,\n    57,\n    39,\n    41,\n    43,\n    22,\n    28,\n    32,\n    60,\n    36,\n    23,\n    29,\n    33,\n    37,\n    44,\n    45,\n    59,\n    46,\n    47,\n    48,\n    49,\n    50,\n    24,\n    25,\n    65,\n    66,\n    70,\n    71\n  ];\n  final List<int> sortIndex2 = [\n    18,\n    20,\n    26,\n    30,\n    34,\n    38,\n    40,\n    42,\n    21,\n    27,\n    31,\n    35,\n    39,\n    41,\n    43,\n    22,\n    28,\n    32,\n    36,\n    23,\n    29,\n    33,\n    37,\n    44,\n    45,\n    46,\n    47,\n    48,\n    49,\n    50,\n    24,\n    25,\n    52,\n    53,\n    54,\n    55,\n    57,\n    58,\n    59,\n    60,\n    65,\n    66,\n    70,\n    71\n  ];\n  // fmt: on\n\n  ABogus({String? fp, String? userAgent, List<int>? options})\n      : userAgent = userAgent != null && userAgent.isNotEmpty\n            ? userAgent\n            : \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0\",\n        browserFp = fp != null && fp.isNotEmpty\n            ? fp\n            : BrowserFingerprintGenerator.generateFingerprint(\n                browserType: \"Edge\"),\n        options = options ?? [0, 1, 14] {\n    characterList = [character, character2];\n    cryptoUtility = CryptoUtility(salt, characterList);\n  }\n\n  String encodeData(String data, {int alphabetIndex = 0}) {\n    return cryptoUtility.abogusEncode(data, alphabetIndex);\n  }\n\n  List<String> generateAbogus(String params, {String body = \"\"}) {\n    final abDir = <int, dynamic>{\n      8: 3,\n      15: {\n        \"aid\": aid,\n        \"pageId\": pageId,\n        \"boe\": boe,\n        \"ddrt\": ddrt,\n        \"paths\": paths,\n        \"track\": {\"mode\": 0, \"delay\": 300, \"paths\": []},\n        \"dump\": true,\n        \"rpU\": \"\",\n      },\n      18: 44,\n      19: [1, 0, 1, 0, 1],\n      66: 0,\n      69: 0,\n      70: 0,\n      71: 0,\n    };\n\n    final startEncryption = DateTime.now().millisecondsSinceEpoch;\n\n    final array1 =\n        cryptoUtility.paramsToArray(cryptoUtility.paramsToArray(params));\n    final array2 =\n        cryptoUtility.paramsToArray(cryptoUtility.paramsToArray(body));\n    final array3 = cryptoUtility.paramsToArray(\n      cryptoUtility.base64Encode(\n        StringProcessor.toCharStr(\n          CryptoUtility.rc4Encrypt(uaKey, userAgent),\n        ),\n        selectedAlphabet: 1,\n      ),\n      addSalt: false,\n    );\n\n    final endEncryption = DateTime.now().millisecondsSinceEpoch;\n\n    abDir[20] = (startEncryption >> 24) & 255;\n    abDir[21] = (startEncryption >> 16) & 255;\n    abDir[22] = (startEncryption >> 8) & 255;\n    abDir[23] = startEncryption & 255;\n    abDir[24] = StringProcessor.jsShiftRight(startEncryption, 32);\n    abDir[25] = StringProcessor.jsShiftRight(startEncryption, 40);\n\n    abDir[26] = (options[0] >> 24) & 255;\n    abDir[27] = (options[0] >> 16) & 255;\n    abDir[28] = (options[0] >> 8) & 255;\n    abDir[29] = options[0] & 255;\n\n    abDir[30] = (options[1] ~/ 256) & 255;\n    abDir[31] = (options[1] % 256) & 255;\n    abDir[32] = (options[1] >> 24) & 255;\n    abDir[33] = (options[1] >> 16) & 255;\n\n    abDir[34] = (options[2] >> 24) & 255;\n    abDir[35] = (options[2] >> 16) & 255;\n    abDir[36] = (options[2] >> 8) & 255;\n    abDir[37] = options[2] & 255;\n\n    abDir[38] = array1[21];\n    abDir[39] = array1[22];\n    abDir[40] = array2[21];\n    abDir[41] = array2[22];\n    abDir[42] = array3[23];\n    abDir[43] = array3[24];\n\n    abDir[44] = (endEncryption >> 24) & 255;\n    abDir[45] = (endEncryption >> 16) & 255;\n    abDir[46] = (endEncryption >> 8) & 255;\n    abDir[47] = endEncryption & 255;\n    abDir[48] = abDir[8];\n    abDir[49] = StringProcessor.jsShiftRight(endEncryption, 32);\n    abDir[50] = StringProcessor.jsShiftRight(endEncryption, 40);\n\n    abDir[51] = (pageId >> 24) & 255;\n    abDir[52] = (pageId >> 16) & 255;\n    abDir[53] = (pageId >> 8) & 255;\n    abDir[54] = pageId & 255;\n    abDir[55] = pageId;\n    abDir[56] = aid;\n    abDir[57] = aid & 255;\n    abDir[58] = (aid >> 8) & 255;\n    abDir[59] = (aid >> 16) & 255;\n    abDir[60] = (aid >> 24) & 255;\n\n    abDir[64] = browserFp.length;\n    abDir[65] = browserFp.length;\n\n    final sortedValues =\n        sortIndex.map((i) => abDir[i] ?? 0).toList().cast<int>();\n    final edgeFpArray = StringProcessor.toOrdArray(browserFp);\n\n    var abXor = 0;\n    for (var index = 0; index < sortIndex2.length; index++) {\n      if (index == 0) {\n        abXor = abDir[sortIndex2[index]] ?? 0;\n      } else {\n        abXor ^= (abDir[sortIndex2[index]] ?? 0);\n      }\n    }\n    sortedValues.addAll(edgeFpArray);\n    sortedValues.add(abXor);\n\n    final abogusBytesStr = StringProcessor.generateRandomBytes() +\n        cryptoUtility.transformBytes(sortedValues);\n\n    final abogus = cryptoUtility.abogusEncode(abogusBytesStr, 0);\n    final finalParams = \"$params&a_bogus=$abogus\";\n    return [finalParams, abogus, userAgent, body];\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/douyin/douyin_request_params.dart",
    "content": "﻿mixin DouyinRequestParams {\n  static const String kDefaultUserAgent =\n      \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\";\n  static const aidValue = \"6383\";\n  static const versionCodeValue = \"180800\";\n  static const sdkVersion = \"1.0.14-beta.0\";\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/douyin/douyin_site.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/convert_helper.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\nimport 'package:simple_live_core/src/platforms/douyin/douyin_utils.dart';\nimport 'douyin_request_params.dart';\n\nclass DouyinSite implements LiveSite {\n  @override\n  String id = \"douyin\";\n\n  @override\n  String name = \"抖音直播\";\n\n  @override\n  LiveDanmaku getDanmaku() => DouyinDanmaku();\n\n  bool hlsFirst = false;\n\n  static const String kDefaultReferer = \"https://live.douyin.com\";\n\n  static const String kDefaultAuthority = \"live.douyin.com\";\n\n  Map<String, dynamic> headers = {\n    \"Authority\": kDefaultAuthority,\n    \"Referer\": kDefaultReferer,\n    \"User-Agent\": DouyinRequestParams.kDefaultUserAgent,\n  };\n\n  Future<Map<String, dynamic>> getRequestHeaders() async {\n    try {\n      final existCookies = headers['cookie'] ?? '';\n      if (existCookies.contains('ttwid')) {\n        return headers;\n      }\n      var head = await HttpClient.instance\n          .head(\"https://live.douyin.com\", header: headers);\n      head.headers[\"set-cookie\"]?.forEach((element) {\n        var cookie = element.split(\";\")[0];\n        if (cookie.contains(\"ttwid\")) {\n          final newCookie = '$cookie; $existCookies';\n          headers['cookie'] = newCookie;\n        }\n      });\n      return headers;\n    } catch (e) {\n      CoreLog.error(e);\n      return headers;\n    }\n  }\n\n  /// 通过 Cookie 获取当前登录用户信息\n  /// 成功返回 data(Map)，失败返回空 Map\n  Future<Map<String, dynamic>> getUserInfoByCookie(String cookie) async {\n    try {\n      final url = \"https://live.douyin.com/webcast/user/me/\";\n      final result = await HttpClient.instance.getJson(\n        url,\n        queryParameters: {\n          \"aid\": DouyinRequestParams.aidValue,\n        },\n        header: {\n          \"user-agent\": DouyinRequestParams.kDefaultUserAgent,\n          'accept': 'application/json, text/plain, */*',\n          'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',\n          \"Cookie\": cookie,\n        },\n      );\n      if (result is Map<String, dynamic>) {\n        final data = result[\"data\"];\n        if (data is Map<String, dynamic>) {\n          return data;\n        }\n      }\n      return {};\n    } catch (e) {\n      CoreLog.error(e);\n    }\n    return {};\n  }\n\n  @override\n  Future<List<LiveCategory>> getCategores() async {\n    List<LiveCategory> categories = [];\n    var result = await HttpClient.instance.getText(\n      \"https://live.douyin.com/\",\n      queryParameters: {},\n      header: await getRequestHeaders(),\n    );\n\n    var renderData =\n        RegExp(r'\\{\\\\\"pathname\\\\\":\\\\\"\\/\\\\\",\\\\\"categoryData.*?\\]\\\\n')\n                .firstMatch(result)\n                ?.group(0) ??\n            \"\";\n    var renderDataJson = json.decode(renderData\n        .trim()\n        .replaceAll('\\\\\"', '\"')\n        .replaceAll(r\"\\\\\", r\"\\\")\n        .replaceAll(']\\\\n', \"\"));\n\n    for (var item in renderDataJson[\"categoryData\"]) {\n      List<LiveSubCategory> subs = [];\n      var id = '${item[\"partition\"][\"id_str\"]},${item[\"partition\"][\"type\"]}';\n      for (var subItem in item[\"sub_partition\"]) {\n        var subCategory = LiveSubCategory(\n          id: '${subItem[\"partition\"][\"id_str\"]},${subItem[\"partition\"][\"type\"]}',\n          name: asT<String?>(subItem[\"partition\"][\"title\"]) ?? \"\",\n          parentId: id,\n          pic: \"\",\n        );\n        subs.add(subCategory);\n      }\n\n      var category = LiveCategory(\n        children: subs,\n        id: id,\n        name: asT<String?>(item[\"partition\"][\"title\"]) ?? \"\",\n      );\n      subs.insert(\n          0,\n          LiveSubCategory(\n            id: category.id,\n            name: category.name,\n            parentId: category.id,\n            pic: \"\",\n          ));\n      categories.add(category);\n    }\n    return categories;\n  }\n\n  @override\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) async {\n    var ids = category.id.split(',');\n    var partitionId = ids[0];\n    var partitionType = ids[1];\n    var queryParameters = {\n      \"aid\": '6383',\n      \"app_name\": \"douyin_web\",\n      \"live_id\": '1',\n      \"device_platform\": \"web\",\n      \"language\": \"zh-CN\",\n      \"enter_from\": \"link_share\",\n      \"cookie_enabled\": \"true\",\n      \"screen_width\": \"1980\",\n      \"screen_height\": \"1080\",\n      \"browser_language\": \"zh-CN\",\n      \"browser_platform\": \"Win32\",\n      \"browser_name\": \"Edge\",\n      \"browser_version\": \"125.0.0.0\",\n      \"browser_online\": \"true\",\n      \"count\": '15',\n      \"offset\": ((page - 1) * 15).toString(),\n      \"partition\": partitionId,\n      \"partition_type\": partitionType,\n      \"req_from\": '2'\n    };\n    var categoryRoomUrl =\n        \"https://live.douyin.com/webcast/web/partition/detail/room/v2/\";\n    var targetUrl =\n        DouyinUtils.buildRequestUrl(categoryRoomUrl, queryParameters);\n    var result = await HttpClient.instance.getJson(\n      targetUrl,\n      header: await getRequestHeaders(),\n    );\n\n    var hasMore = (result[\"data\"][\"data\"] as List).length >= 15;\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"data\"]) {\n      var roomItem = LiveRoomItem(\n        roomId: item[\"web_rid\"],\n        title: item[\"room\"][\"title\"].toString(),\n        cover: item[\"room\"][\"cover\"][\"url_list\"][0].toString(),\n        userName: item[\"room\"][\"owner\"][\"nickname\"].toString(),\n        online: int.tryParse(\n                item[\"room\"][\"room_view_stats\"][\"display_value\"].toString()) ??\n            0,\n      );\n      items.add(roomItem);\n    }\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://live.douyin.com/webcast/feed/\",\n      queryParameters: {\n        \"aid\": \"6383\",\n        \"app_name\": \"douyin_web\",\n        \"need_map\": \"1\",\n        \"is_draw\": \"1\",\n        \"inner_from_drawer\": \"0\",\n        \"enter_source\": \"web_homepage_hot_web_live_card\",\n        \"source_key\": \"web_homepage_hot_web_live_card\"\n      },\n      header: await getRequestHeaders(),\n    );\n\n    var hasMore = (result[\"data\"] as List).length >= 15;\n    var items = <LiveRoomItem>[];\n    for (var i in result[\"data\"]) {\n      var item = i['data'];\n      var roomItem = LiveRoomItem(\n        roomId: item[\"owner\"][\"web_rid\"],\n        title: item[\"title\"].toString(),\n        cover: item[\"cover\"][\"url_list\"][0].toString(),\n        userName: item[\"owner\"][\"nickname\"].toString(),\n        online:\n            int.tryParse(item[\"room_view_stats\"][\"display_value\"].toString()) ??\n                0,\n      );\n      items.add(roomItem);\n    }\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) async {\n    // 有两种roomId，一种是webRid，一种是roomId\n    // roomId是一次性的，用户每次重新开播都会生成一个新的roomId\n    // roomId一般长度为19位，例如：7376429659866598196\n    // webRid是固定的，用户每次开播都是同一个webRid\n    // webRid一般长度为11-12位，例如：416144012050\n    // 这里简单进行判断，如果roomId长度小于15，则认为是webRid\n    var webRid = roomId;\n    if (roomId.length > 16) {\n      webRid = await _getWebRid(roomId);\n    }\n    return await getRoomDetailByWebRid(webRid);\n  }\n\n  /// 非webRid转webRid\n  Future<String> _getWebRid(String roomId) async {\n    var baseUrl = \"https://webcast.amemv.com/douyin/webcast/reflow/\";\n    var response = await HttpClient.instance.getText(\n      \"$baseUrl$roomId\",\n    );\n    final reg = RegExp(\n        r'mysteryMan\\\\\":1,\\\\\\\"webRid\\\\\\\":\\\\\\\"([^\\\\\"]+)\\\\\\\",\\\\\\\"desensitizedNickname'\n    );\n    var webRid = reg.firstMatch(response)?.group(1) ?? \"\";\n    return webRid.isEmpty ? roomId : webRid;\n  }\n\n  /// 通过roomId获取直播间信息\n  /// - [roomId] 直播间ID\n  /// - 返回直播间信息\n  Future<LiveRoomDetail> getRoomDetailByRoomId(String roomId) async {\n    // 读取房间信息\n    var roomData = await _getRoomDataByRoomId(roomId);\n\n    // 通过房间信息获取WebRid\n    var webRid = roomData[\"data\"][\"room\"][\"owner\"][\"web_rid\"].toString();\n\n    // 读取用户唯一ID，用于弹幕连接\n    // 似乎这个参数不是必须的，先随机生成一个\n    //var userUniqueId = await _getUserUniqueId(webRid);\n    var userUniqueId = generateRandomNumber(12).toString();\n\n    var room = roomData[\"data\"][\"room\"];\n    var owner = room[\"owner\"];\n\n    var status = asT<int?>(room[\"status\"]) ?? 0;\n\n    // roomId是一次性的，用户每次重新开播都会生成一个新的roomId\n    // 所以如果roomId对应的直播间状态不是直播中，就通过webRid获取直播间信息\n    if (status == 4) {\n      var result = await getRoomDetailByWebRid(webRid);\n      return result;\n    }\n\n    var roomStatus = status == 2;\n    // 主要是为了获取cookie,用于弹幕websocket连接\n    var headers = await getRequestHeaders();\n\n    return LiveRoomDetail(\n      roomId: webRid,\n      title: room[\"title\"].toString(),\n      cover: roomStatus ? room[\"cover\"][\"url_list\"][0].toString() : \"\",\n      userName: owner[\"nickname\"].toString(),\n      userAvatar: owner[\"avatar_thumb\"][\"url_list\"][0].toString(),\n      online: roomStatus\n          ? asT<int?>(room[\"room_view_stats\"][\"display_value\"]) ?? 0\n          : 0,\n      status: roomStatus,\n      url: \"https://live.douyin.com/$webRid\",\n      introduction: owner[\"signature\"].toString(),\n      notice: \"\",\n      danmakuData: DouyinDanmakuArgs(\n        webRid: webRid,\n        roomId: roomId,\n        userId: userUniqueId,\n        cookie: headers[\"cookie\"],\n      ),\n      data: room[\"stream_url\"],\n    );\n  }\n\n  /// 通过WebRid获取直播间信息\n  /// - [webRid] 直播间RID\n  /// - 返回直播间信息\n  Future<LiveRoomDetail> getRoomDetailByWebRid(String webRid) async {\n    try {\n      var result = await _getRoomDetailByWebRidApi(webRid);\n      return result;\n    } catch (e) {\n      CoreLog.error(e);\n    }\n    return await _getRoomDetailByWebRidHtml(webRid);\n  }\n\n  /// 通过WebRid访问直播间API，从API中获取直播间信息\n  /// - [webRid] 直播间RID\n  /// - 返回直播间信息\n  Future<LiveRoomDetail> _getRoomDetailByWebRidApi(String webRid) async {\n    // 读取房间信息\n    var data = await _getRoomDataByApi(webRid);\n    var roomData = data[\"data\"][0];\n    var userData = data[\"user\"];\n    var roomId = roomData[\"id_str\"].toString();\n\n    // 读取用户唯一ID，用于弹幕连接\n    // 似乎这个参数不是必须的，先随机生成一个\n    //var userUniqueId = await _getUserUniqueId(webRid) ;\n    var userUniqueId = generateRandomNumber(12).toString();\n\n    var owner = roomData[\"owner\"];\n\n    var roomStatus = (asT<int?>(roomData[\"status\"]) ?? 0) == 2;\n\n    // 主要是为了获取cookie,用于弹幕websocket连接\n    var headers = await getRequestHeaders();\n    return LiveRoomDetail(\n      roomId: webRid,\n      title: roomData[\"title\"].toString(),\n      cover: roomStatus ? roomData[\"cover\"][\"url_list\"][0].toString() : \"\",\n      userName: roomStatus\n          ? owner[\"nickname\"].toString()\n          : userData[\"nickname\"].toString(),\n      userAvatar: roomStatus\n          ? owner[\"avatar_thumb\"][\"url_list\"][0].toString()\n          : userData[\"avatar_thumb\"][\"url_list\"][0].toString(),\n      online: roomStatus\n          ? asT<int?>(roomData[\"room_view_stats\"][\"display_value\"]) ?? 0\n          : 0,\n      status: roomStatus,\n      url: \"https://live.douyin.com/$webRid\",\n      introduction: owner?[\"signature\"]?.toString() ?? \"\",\n      notice: \"\",\n      danmakuData: DouyinDanmakuArgs(\n        webRid: webRid,\n        roomId: roomId,\n        userId: userUniqueId,\n        cookie: headers[\"cookie\"],\n      ),\n      data: roomStatus ? roomData[\"stream_url\"] : {},\n    );\n  }\n\n  /// 通过WebRid访问直播间网页，从网页HTML中获取直播间信息\n  /// - [webRid] 直播间RID\n  /// - 返回直播间信息\n  Future<LiveRoomDetail> _getRoomDetailByWebRidHtml(String webRid) async {\n    var roomData = await _getRoomDataByHtml(webRid);\n    var roomId = roomData[\"roomStore\"][\"roomInfo\"][\"room\"][\"id_str\"].toString();\n    var userUniqueId =\n        roomData[\"userStore\"][\"odin\"][\"user_unique_id\"].toString();\n\n    var room = roomData[\"roomStore\"][\"roomInfo\"][\"room\"];\n    var owner = room[\"owner\"];\n    var anchor = roomData[\"roomStore\"][\"roomInfo\"][\"anchor\"];\n    var roomStatus = (asT<int?>(room[\"status\"]) ?? 0) == 2;\n\n    // 主要是为了获取cookie,用于弹幕websocket连接\n    var headers = await getRequestHeaders();\n\n    return LiveRoomDetail(\n      roomId: webRid,\n      title: room[\"title\"].toString(),\n      cover: roomStatus ? room[\"cover\"][\"url_list\"][0].toString() : \"\",\n      userName: roomStatus\n          ? owner[\"nickname\"].toString()\n          : anchor[\"nickname\"].toString(),\n      userAvatar: roomStatus\n          ? owner[\"avatar_thumb\"][\"url_list\"][0].toString()\n          : anchor[\"avatar_thumb\"][\"url_list\"][0].toString(),\n      online: roomStatus\n          ? asT<int?>(room[\"room_view_stats\"][\"display_value\"]) ?? 0\n          : 0,\n      status: roomStatus,\n      url: \"https://live.douyin.com/$webRid\",\n      introduction: owner?[\"signature\"]?.toString() ?? \"\",\n      notice: \"\",\n      danmakuData: DouyinDanmakuArgs(\n        webRid: webRid,\n        roomId: roomId,\n        userId: userUniqueId,\n        cookie: headers[\"cookie\"],\n      ),\n      data: roomStatus ? room[\"stream_url\"] : {},\n    );\n  }\n\n  /// 读取用户的唯一ID\n  /// - [webRid] 直播间RID\n  // ignore: unused_element\n  Future<String> _getUserUniqueId(String webRid) async {\n    try {\n      var webInfo = await _getRoomDataByHtml(webRid);\n      return webInfo[\"userStore\"][\"odin\"][\"user_unique_id\"].toString();\n    } catch (e) {\n      return generateRandomNumber(12).toString();\n    }\n  }\n\n  /// 进入直播间前需要先获取cookie\n  /// - [webRid] 直播间RID\n  Future<String> _getWebCookie(String webRid) async {\n    var headResp = await HttpClient.instance.head(\n      \"https://live.douyin.com/$webRid\",\n      header: headers,\n    );\n    var dyCookie = \"\";\n    headResp.headers[\"set-cookie\"]?.forEach((element) {\n      var cookie = element.split(\";\")[0];\n      if (cookie.contains(\"ttwid\")) {\n        dyCookie += \"$cookie;\";\n      }\n      if (cookie.contains(\"__ac_nonce\")) {\n        dyCookie += \"$cookie;\";\n      }\n      if (cookie.contains(\"msToken\")) {\n        dyCookie += \"$cookie;\";\n      }\n    });\n    return dyCookie;\n  }\n\n  /// 通过webRid获取直播间Web信息\n  /// - [webRid] 直播间RID\n  Future<Map> _getRoomDataByHtml(String webRid) async {\n    var dyCookie = await _getWebCookie(webRid);\n    var result = await HttpClient.instance.getText(\n      \"https://live.douyin.com/$webRid\",\n      queryParameters: {},\n      header: {\n        \"Authority\": kDefaultAuthority,\n        \"Referer\": kDefaultReferer,\n        \"Cookie\": dyCookie,\n        \"User-Agent\": DouyinRequestParams.kDefaultUserAgent,\n      },\n    );\n\n    var renderData = RegExp(r'\\{\\\\\"state\\\\\":\\{\\\\\"appStore.*?\\]\\\\n')\n            .firstMatch(result)\n            ?.group(0) ??\n        \"\";\n    var str = renderData\n        .trim()\n        .replaceAll('\\\\\"', '\"')\n        .replaceAll(r\"\\\\\", r\"\\\")\n        .replaceAll(']\\\\n', \"\");\n    var renderDataJson = json.decode(str);\n    return renderDataJson[\"state\"];\n  }\n\n  /// 通过webRid获取直播间Web信息\n  /// - [webRid] 直播间RID\n  Future<Map> _getRoomDataByApi(String webRid) async {\n    var requestHeader = await getRequestHeaders();\n    var queryParams = {\n      'app_name': 'douyin_web',\n      'enter_from': 'web_live',\n      'live_id': '1',\n      'web_rid': webRid,\n      'is_need_double_stream': \"false\"\n    };\n    var targetUrl = DouyinUtils.buildRequestUrl(\n        \"https://live.douyin.com/webcast/room/web/enter/\", queryParams);\n    CoreLog.d(\"targetUrl: $targetUrl\");\n    var result = await HttpClient.instance.getJson(\n      targetUrl,\n      header: requestHeader,\n    );\n    return result[\"data\"];\n  }\n\n  /// 通过roomId获取直播间信息\n  /// - [roomId] 直播间ID\n  Future<Map> _getRoomDataByRoomId(String roomId) async {\n    var result = await HttpClient.instance.getJson(\n      'https://webcast.amemv.com/webcast/room/reflow/info/',\n      queryParameters: {\n        \"type_id\": 0,\n        \"live_id\": 1,\n        \"room_id\": roomId,\n        \"sec_user_id\": \"\",\n        \"version_code\": \"99.99.99\",\n        \"app_id\": 6383,\n      },\n      header: await getRequestHeaders(),\n    );\n    return result;\n  }\n\n  @override\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) async {\n    List<LivePlayQuality> qualities = [];\n\n    var qulityList =\n        detail.data[\"live_core_sdk_data\"][\"pull_data\"][\"options\"][\"qualities\"];\n    var streamData = detail.data[\"live_core_sdk_data\"][\"pull_data\"]\n            [\"stream_data\"]\n        .toString();\n\n    if (!streamData.startsWith('{')) {\n      var flvList =\n          (detail.data[\"flv_pull_url\"] as Map).values.cast<String>().toList();\n      var hlsList = (detail.data[\"hls_pull_url_map\"] as Map)\n          .values\n          .cast<String>()\n          .toList();\n      for (var quality in qulityList) {\n        int level = quality[\"level\"];\n        List<String> urls = [];\n        var flvIndex = flvList.length - level;\n        if (flvIndex >= 0 && flvIndex < flvList.length) {\n          urls.add(flvList[flvIndex]);\n        }\n        var hlsIndex = hlsList.length - level;\n        if (hlsIndex >= 0 && hlsIndex < hlsList.length) {\n          urls.add(hlsList[hlsIndex]);\n        }\n        var qualityItem = LivePlayQuality(\n          quality: quality[\"name\"],\n          sort: level,\n          data: urls,\n        );\n        if (urls.isNotEmpty) {\n          qualities.add(qualityItem);\n        }\n      }\n    } else {\n      var qualityData = json.decode(streamData)[\"data\"] as Map;\n      for (var quality in qulityList) {\n        List<String> urls = [];\n        var flvUrl =\n            qualityData[quality[\"sdk_key\"]]?[\"main\"]?[\"flv\"]?.toString();\n\n        if (flvUrl != null && flvUrl.isNotEmpty) {\n          urls.add(flvUrl);\n        }\n        var hlsUrl =\n            qualityData[quality[\"sdk_key\"]]?[\"main\"]?[\"hls\"]?.toString();\n        if (hlsUrl != null && hlsUrl.isNotEmpty) {\n          if(hlsFirst){\n            urls.insert(0, hlsUrl);\n          }else{\n            urls.add(hlsUrl);\n          }\n        }\n        var qualityItem = LivePlayQuality(\n          quality: quality[\"name\"],\n          sort: quality[\"level\"],\n          data: urls,\n        );\n        if (urls.isNotEmpty) {\n          qualities.add(qualityItem);\n        }\n      }\n\n      //   // 真原画 media_kit 不支持 hvc1编码\n      //   try{\n      //     String realOriginStream =  (qualityData['ao']['main']['flv'] as String).replaceAll('&only_audio=1','');\n      //     List<String> urls = [realOriginStream];\n      //     var realQualityItem = LivePlayQuality(\n      //       quality: \"真原画\",\n      //       sort: 10,\n      //       data: urls,\n      //     );\n      //     qualities.add(realQualityItem);\n      //   }catch(e){\n      //     CoreLog.error(\"未找到 ao 流 $e\");\n      //   }\n    }\n    qualities.sort((a, b) => b.sort.compareTo(a.sort));\n    return qualities;\n  }\n\n  @override\n  Future<LivePlayUrl> getPlayUrls(\n      {required LiveRoomDetail detail,\n      required LivePlayQuality quality}) async {\n    return LivePlayUrl(urls: quality.data);\n  }\n\n  @override\n  Future<LiveSearchRoomResult> searchRooms(String keyword,\n      {int page = 1}) async {\n    String serverUrl = \"https://www.douyin.com/aweme/v1/web/live/search/\";\n    var uri = Uri.parse(serverUrl)\n        .replace(scheme: \"https\", port: 443, queryParameters: {\n      \"device_platform\": \"webapp\",\n      \"aid\": \"6383\",\n      \"channel\": \"channel_pc_web\",\n      \"search_channel\": \"aweme_live\",\n      \"keyword\": keyword,\n      \"search_source\": \"switch_tab\",\n      \"query_correct_type\": \"1\",\n      \"is_filter_search\": \"0\",\n      \"from_group_id\": \"\",\n      \"offset\": ((page - 1) * 10).toString(),\n      \"count\": \"10\",\n      \"pc_client_type\": \"1\",\n      \"version_code\": \"170400\",\n      \"version_name\": \"17.4.0\",\n      \"cookie_enabled\": \"true\",\n      \"screen_width\": \"1980\",\n      \"screen_height\": \"1080\",\n      \"browser_language\": \"zh-CN\",\n      \"browser_platform\": \"Win32\",\n      \"browser_name\": \"Edge\",\n      \"browser_version\": \"125.0.0.0\",\n      \"browser_online\": \"true\",\n      \"engine_name\": \"Blink\",\n      \"engine_version\": \"125.0.0.0\",\n      \"os_name\": \"Windows\",\n      \"os_version\": \"10\",\n      \"cpu_core_num\": \"12\",\n      \"device_memory\": \"8\",\n      \"platform\": \"PC\",\n      \"downlink\": \"10\",\n      \"effective_type\": \"4g\",\n      \"round_trip_time\": \"100\",\n      \"webid\": \"7382872326016435738\",\n    });\n    var requlestUrl = uri.toString();\n    var headResp = await getRequestHeaders();\n    var dyCookie = headResp['cookie'];\n    var result = await HttpClient.instance.getJson(\n      requlestUrl,\n      queryParameters: {},\n      header: {\n        \"Authority\": 'www.douyin.com',\n        'accept': 'application/json, text/plain, */*',\n        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',\n        'cookie': dyCookie,\n        'priority': 'u=1, i',\n        'referer':\n            'https://www.douyin.com/search/${Uri.encodeComponent(keyword)}?type=live',\n        'sec-ch-ua':\n            '\"Microsoft Edge\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"',\n        'sec-ch-ua-mobile': '?0',\n        'sec-ch-ua-platform': '\"Windows\"',\n        'sec-fetch-dest': 'empty',\n        'sec-fetch-mode': 'cors',\n        'sec-fetch-site': 'same-origin',\n        'user-agent': DouyinRequestParams.kDefaultUserAgent,\n      },\n    );\n    if (result == \"\" || result == 'blocked') {\n      throw Exception(\"抖音直播搜索被限制，请稍后再试\");\n    }\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"] ?? []) {\n      var itemData = json.decode(item[\"lives\"][\"rawdata\"].toString());\n      var roomItem = LiveRoomItem(\n        roomId: itemData[\"owner\"][\"web_rid\"].toString(),\n        title: itemData[\"title\"].toString(),\n        cover: itemData[\"cover\"][\"url_list\"][0].toString(),\n        userName: itemData[\"owner\"][\"nickname\"].toString(),\n        online: int.tryParse(itemData[\"stats\"][\"total_user\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    return LiveSearchRoomResult(hasMore: items.length >= 10, items: items);\n  }\n\n  @override\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword,\n      {int page = 1}) async {\n    throw Exception(\"抖音暂不支持搜索主播，请直接搜索直播间\");\n  }\n\n  @override\n  Future<bool> getLiveStatus({required String roomId}) async {\n    var result = await getRoomDetail(roomId: roomId);\n    return result.status;\n  }\n\n  @override\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) {\n    return Future.value(<LiveSuperChatMessage>[]);\n  }\n\n  //生成指定长度的16进制随机字符串\n  String generateRandomString(int length) {\n    var random = Random.secure();\n    var values = List<int>.generate(length, (i) => random.nextInt(16));\n    StringBuffer stringBuffer = StringBuffer();\n    for (var item in values) {\n      stringBuffer.write(item.toRadixString(16));\n    }\n    return stringBuffer.toString();\n  }\n\n  // 生成随机的数字\n  int generateRandomNumber(int length) {\n    var random = Random.secure();\n    var values = List<int>.generate(length, (i) => random.nextInt(10));\n    StringBuffer stringBuffer = StringBuffer();\n    for (var item in values) {\n      stringBuffer.write(item);\n    }\n    return int.tryParse(stringBuffer.toString()) ??\n        Random().nextInt(1000000000);\n  }\n\n  /// 读取A-Bogus签名后的URL\n  /// - [url] 原始URL\n  /// - 返回签名后的URL\n  ///\n  /// 服务端代码：https://github.com/dengmin/a-bogus，请自行部署后使用\n  Future<String> getAbogusUrl(String url) async {\n    try {\n      var signResult = await HttpClient.instance.postJson(\n        \"https://dy.nsapps.cn/abogus\",\n        queryParameters: {},\n        header: {\"Content-Type\": \"application/json\"},\n        data: {\"url\": url, \"userAgent\": DouyinRequestParams.kDefaultUserAgent},\n      );\n      return signResult[\"data\"][\"url\"];\n    } catch (e) {\n      CoreLog.error(e);\n      return url;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/douyin/douyin_utils.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\n\nimport 'abogus.dart';\nimport 'douyin_request_params.dart';\n\nclass DouyinUtils {\n// 根据传入长度产生随机字符串\n  static String getMSToken({int randomLength = 184}) {\n    var baseStr =\n        'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789=';\n    var sb = StringBuffer();\n    for (var i = 0; i < randomLength; i++) {\n      var index = Random().nextInt(baseStr.length);\n      sb.write(baseStr[index]);\n    }\n    return sb.toString();\n  }\n\n  static String buildRequestUrl(String baseUrl, Map<String, dynamic> params) {\n    var abogus = ABogus(userAgent: DouyinRequestParams.kDefaultUserAgent);\n    var parsedUrl = Uri.parse(baseUrl);\n    var exParams = params;\n    exParams['aid'] = \"6383\";\n    exParams['compress'] = \"gzip\";\n    exParams['device_platform'] = \"web\";\n    exParams['browser_language'] = \"zh-CN\";\n    exParams['browser_platform'] = \"Win32\";\n    exParams['browser_name'] = \"Edge\";\n    exParams['browser_version'] = \"125.0.0.0\";\n    if (!exParams.containsKey('msToken')) {\n      exParams['msToken'] = getMSToken();\n    }\n    var newQueryStr = Uri(queryParameters: exParams).query;\n    var signedQueryStr = abogus.generateAbogus(newQueryStr, body: \"\").first;\n    final newUrl = parsedUrl.replace(\n      query: signedQueryStr,\n    );\n    return newUrl.toString();\n  }\n\n  Future<Map<String, String>> getTtwidWebid({required String reqUrl}) async {\n    // 先请求以获取 ttwid 等 Cookie，再解析页面的 RENDER_DATA 获取 user_unique_id\n    final headers = <String, String>{\n      \"User-Agent\":\n          \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\",\n      \"Accept\":\n          \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\",\n      \"Accept-Language\": \"zh-CN,zh;q=0.9,en;q=0.8\",\n    };\n\n    String? ttwid;\n    String? webid;\n\n    try {\n      // 先用 HEAD 获取 Set-Cookie（包含 ttwid）\n      final headResp = await HttpClient.instance.head(\n        reqUrl,\n        header: headers,\n      );\n      final setCookies = headResp.headers[\"set-cookie\"];\n      if (setCookies != null) {\n        for (final cookieLine in setCookies) {\n          final cookie = cookieLine.split(\";\").first;\n          if (cookie.startsWith(\"ttwid=\")) {\n            ttwid = cookie.substring(\"ttwid=\".length);\n            break;\n          }\n        }\n      }\n\n      // 再用 GET 拉取页面 HTML，解析 RENDER_DATA\n      final html = await HttpClient.instance.getText(\n        reqUrl,\n        header: headers,\n      );\n\n      // 提取 RENDER_DATA 脚本块\n      final renderMatches = RegExp(\n        r'<script id=\\\"RENDER_DATA\\\" type=\\\"application\\/json\\\">(.*?)<\\/script>',\n        dotAll: true,\n      ).allMatches(html);\n      if (renderMatches.isNotEmpty) {\n        var renderDataText = renderMatches.first.group(1) ?? \"\";\n        // URL 解码\n        try {\n          renderDataText = Uri.decodeComponent(renderDataText);\n        } catch (_) {}\n        try {\n          final data = jsonDecode(renderDataText) as Map<String, dynamic>;\n          // 路径 app.odin.user_unique_id\n          final app = data['app'] as Map<String, dynamic>?;\n          final odin = app?['odin'] as Map<String, dynamic>?;\n          final uid = odin?['user_unique_id'];\n          if (uid != null) {\n            webid = uid.toString();\n          }\n        } catch (e) {\n          CoreLog.error('解析 RENDER_DATA 失败: $e');\n        }\n      }\n    } catch (e) {\n      CoreLog.error('get_ttwid_webid 错误: $e');\n    }\n\n    return {\n      'ttwid': ttwid ?? '',\n      'webid': webid ?? '',\n    };\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/douyu/douyu_site.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\nimport 'dart:math';\n\nimport 'package:crypto/crypto.dart';\nimport 'package:html_unescape/html_unescape.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\nimport 'package:simple_live_core/src/common/js_engine.dart';\n\nclass DouyuSite implements LiveSite {\n  @override\n  String id = \"douyu\";\n\n  @override\n  String name = \"斗鱼直播\";\n\n  @override\n  LiveDanmaku getDanmaku() => DouyuDanmaku();\n\n  @override\n  Future<List<LiveCategory>> getCategores() async {\n    List<LiveCategory> categories = [];\n    var result =\n        await HttpClient.instance.getJson(\"https://m.douyu.com/api/cate/list\");\n    var subCateList = result[\"data\"][\"cate2Info\"] as List;\n    for (var item in result[\"data\"][\"cate1Info\"]) {\n      var cate1Id = item[\"cate1Id\"];\n      var cate1Name = item[\"cate1Name\"];\n      List<LiveSubCategory> subCategories = [];\n      subCateList.where((x) => x[\"cate1Id\"] == cate1Id).forEach((element) {\n        subCategories.add(LiveSubCategory(\n          pic: element[\"icon\"],\n          id: element[\"cate2Id\"].toString(),\n          parentId: cate1Id.toString(),\n          name: element[\"cate2Name\"].toString(),\n        ));\n      });\n      categories.add(\n        LiveCategory(\n          id: cate1Id.toString(),\n          name: cate1Name.toString(),\n          children: subCategories,\n        ),\n      );\n    }\n    // 根据ID排序\n    categories.sort((a, b) => int.parse(a.id).compareTo(int.parse(b.id)));\n\n    return categories;\n  }\n\n  @override\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://www.douyu.com/gapi/rkc/directory/mixList/2_${category.id}/$page\",\n      queryParameters: {},\n    );\n\n    var items = <LiveRoomItem>[];\n    for (var item in result['data']['rl']) {\n      if (item[\"type\"] != 1) {\n        continue;\n      }\n      var roomItem = LiveRoomItem(\n        cover: item['rs16'].toString(),\n        online: item['ol'],\n        roomId: item['rid'].toString(),\n        title: item['rn'].toString(),\n        userName: item['nn'].toString(),\n      );\n      items.add(roomItem);\n    }\n    var hasMore = page < result['data']['pgcnt'];\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) async {\n    var data = detail.data.toString();\n    data += \"&cdn=&rate=-1&ver=Douyu_223061205&iar=1&ive=1&hevc=0&fa=0\";\n    List<LivePlayQuality> qualities = [];\n    var result = await HttpClient.instance.postJson(\n      \"https://www.douyu.com/lapi/live/getH5Play/${detail.roomId}\",\n      data: data,\n      formUrlEncoded: true,\n    );\n\n    var cdns = <String>[];\n    for (var item in result[\"data\"][\"cdnsWithName\"]) {\n      cdns.add(item[\"cdn\"].toString());\n    }\n\n    // 如果cdn以scdn开头，将其放到最后\n    cdns.sort((a, b) {\n      if (a.startsWith(\"scdn\") && !b.startsWith(\"scdn\")) {\n        return 1;\n      } else if (!a.startsWith(\"scdn\") && b.startsWith(\"scdn\")) {\n        return -1;\n      }\n      return 0;\n    });\n\n    for (var item in result[\"data\"][\"multirates\"]) {\n      qualities.add(LivePlayQuality(\n        quality: item[\"name\"].toString(),\n        data: DouyuPlayData(item[\"rate\"], cdns),\n      ));\n    }\n    return qualities;\n  }\n\n  @override\n  Future<LivePlayUrl> getPlayUrls(\n      {required LiveRoomDetail detail,\n      required LivePlayQuality quality}) async {\n    var args = detail.data.toString();\n    var data = quality.data as DouyuPlayData;\n\n    List<String> urls = [];\n    for (var item in data.cdns) {\n      var url = await getPlayUrl(detail.roomId, args, data.rate, item);\n      if (url.isNotEmpty) {\n        urls.add(url);\n      }\n    }\n    return LivePlayUrl(urls: urls);\n  }\n\n  Future<String> getPlayUrl(\n      String roomId, String args, int rate, String cdn) async {\n    args += \"&cdn=$cdn&rate=$rate\";\n    var result = await HttpClient.instance.postJson(\n      \"https://www.douyu.com/lapi/live/getH5Play/$roomId\",\n      data: args,\n      header: {\n        'referer': 'https://www.douyu.com/$roomId',\n        'user-agent':\n            \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43\"\n      },\n      formUrlEncoded: true,\n    );\n\n    return \"${result[\"data\"][\"rtmp_url\"]}/${HtmlUnescape().convert(result[\"data\"][\"rtmp_live\"].toString())}\";\n  }\n\n  @override\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://www.douyu.com/japi/weblist/apinc/allpage/6/$page\",\n      queryParameters: {},\n    );\n\n    var items = <LiveRoomItem>[];\n    for (var item in result['data']['rl']) {\n      if (item[\"type\"] != 1) {\n        continue;\n      }\n      var roomItem = LiveRoomItem(\n        cover: item['rs16'].toString(),\n        online: item['ol'],\n        roomId: item['rid'].toString(),\n        title: item['rn'].toString(),\n        userName: item['nn'].toString(),\n      );\n      items.add(roomItem);\n    }\n    var hasMore = page < result['data']['pgcnt'];\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) async {\n    Map roomInfo = await _getRoomInfo(roomId);\n\n    var jsEncResult = await HttpClient.instance.getText(\n        \"https://www.douyu.com/swf_api/homeH5Enc?rids=$roomId\",\n        queryParameters: {},\n        header: {\n          'referer': 'https://www.douyu.com/$roomId',\n          'user-agent':\n              \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43\"\n        });\n    var crptext = json.decode(jsEncResult)[\"data\"][\"room$roomId\"].toString();\n\n    return LiveRoomDetail(\n      cover: roomInfo[\"room_pic\"].toString(),\n      online: int.tryParse(roomInfo[\"room_biz_all\"][\"hot\"].toString()) ?? 0,\n      roomId: roomInfo[\"room_id\"].toString(),\n      title: roomInfo[\"room_name\"].toString(),\n      userName: roomInfo[\"owner_name\"].toString(),\n      userAvatar: roomInfo[\"owner_avatar\"].toString(),\n      introduction: roomInfo[\"show_details\"].toString(),\n      notice: \"\",\n      status: roomInfo[\"show_status\"] == 1 &&\n          roomInfo[\"videoLoop\"] != 1 &&\n          !roomInfo[\"room_name\"].startsWith(\"【回放】\"),\n      danmakuData: roomInfo[\"room_id\"].toString(),\n      data: await getPlayArgs(crptext, roomInfo[\"room_id\"].toString()),\n      url: \"https://www.douyu.com/$roomId\",\n      isRecord: roomInfo[\"videoLoop\"] == 1,\n    );\n  }\n\n  @override\n  Future<LiveSearchRoomResult> searchRooms(String keyword,\n      {int page = 1}) async {\n    var did = generateRandomString(32);\n    var result = await HttpClient.instance.getJson(\n      \"https://www.douyu.com/japi/search/api/searchShow\",\n      queryParameters: {\n        \"kw\": keyword,\n        \"page\": page,\n        \"pageSize\": 20,\n      },\n      header: {\n        'User-Agent':\n            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.51',\n        'referer': 'https://www.douyu.com/search/',\n        'Cookie': 'dy_did=$did;acf_did=$did'\n      },\n    );\n    if (result['error'] != 0) {\n      throw Exception(result['msg']);\n    }\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"relateShow\"]) {\n      var roomItem = LiveRoomItem(\n        roomId: item[\"rid\"].toString(),\n        title: item[\"roomName\"].toString(),\n        cover: item[\"roomSrc\"].toString(),\n        userName: item[\"nickName\"].toString(),\n        online: parseHotNum(item[\"hot\"].toString()),\n      );\n      items.add(roomItem);\n    }\n    var hasMore = result[\"data\"][\"relateShow\"].isNotEmpty;\n    return LiveSearchRoomResult(hasMore: hasMore, items: items);\n  }\n\n  Future<Map> _getRoomInfo(String roomId) async {\n    var result = await HttpClient.instance.getJson(\n        \"https://www.douyu.com/betard/$roomId\",\n        queryParameters: {},\n        header: {\n          'referer': 'https://www.douyu.com/$roomId',\n          'user-agent':\n              'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43',\n        });\n    Map roomInfo;\n    if (result is String) {\n      roomInfo = json.decode(result)[\"room\"];\n    } else {\n      roomInfo = result[\"room\"];\n    }\n    return roomInfo;\n  }\n\n  //生成指定长度的16进制随机字符串\n  String generateRandomString(int length) {\n    var random = Random.secure();\n    var values = List<int>.generate(length, (i) => random.nextInt(16));\n    StringBuffer stringBuffer = StringBuffer();\n    for (var item in values) {\n      stringBuffer.write(item.toRadixString(16));\n    }\n    return stringBuffer.toString();\n  }\n\n  @override\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword,\n      {int page = 1}) async {\n    var did = generateRandomString(32);\n    var result = await HttpClient.instance.getJson(\n      \"https://www.douyu.com/japi/search/api/searchUser\",\n      queryParameters: {\n        \"kw\": keyword,\n        \"page\": page,\n        \"pageSize\": 20,\n        \"filterType\": 1,\n      },\n      header: {\n        'User-Agent':\n            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.51',\n        'referer': 'https://www.douyu.com/search/',\n        'Cookie': 'dy_did=$did;acf_did=$did'\n      },\n    );\n\n    var items = <LiveAnchorItem>[];\n    for (var item in result[\"data\"][\"relateUser\"]) {\n      var liveStatus =\n          (int.tryParse(item[\"anchorInfo\"][\"isLive\"].toString()) ?? 0) == 1;\n      var roomType =\n          (int.tryParse(item[\"anchorInfo\"][\"roomType\"].toString()) ?? 0);\n      var roomItem = LiveAnchorItem(\n        roomId: item[\"anchorInfo\"][\"rid\"].toString(),\n        avatar: item[\"anchorInfo\"][\"avatar\"].toString(),\n        userName: item[\"anchorInfo\"][\"nickName\"].toString(),\n        liveStatus: liveStatus && roomType == 0,\n      );\n      items.add(roomItem);\n    }\n    var hasMore = result[\"data\"][\"relateUser\"].isNotEmpty;\n    return LiveSearchAnchorResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<bool> getLiveStatus({required String roomId}) async {\n    var roomInfo = await _getRoomInfo(roomId);\n    return roomInfo[\"show_status\"] == 1 &&\n        roomInfo[\"videoLoop\"] != 1 &&\n        !roomInfo[\"room_name\"].startsWith(\"【回放】\");\n  }\n\n  Future<String> getPlayArgs(String html, String rid) async {\n    //取加密的js\n    html = RegExp(\n                r\"(vdwdae325w_64we[\\s\\S]*function ub98484234[\\s\\S]*?)function\",\n                multiLine: true)\n            .firstMatch(html)\n            ?.group(1) ??\n        \"\";\n    // 防空\n    if (html == \"\") {\n      return \"\";\n    }\n    //去掉eval\n    html = html.replaceAll(RegExp(r\"eval.*?;}\"), \"strc;}\");\n\n    try {\n      var did = '10000000000000000000000000001501';\n      JsEngine.init();\n      var jsEvalResult = JsEngine.evaluate(\"$html;ub98484234();\");\n      var res = jsEvalResult.toString();\n      String t10 = (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();\n      RegExp vReg = RegExp(r'v=(\\d+)');\n      Match? vMatch = vReg.firstMatch(res);\n      String? v = vMatch?.group(1);\n      String rb =\n          md5.convert(utf8.encode(rid + did + t10 + (v ?? \"\"))).toString();\n      String jsSign = res\n          .replaceAll(RegExp(r'return rt;}\\);?'), 'return rt;}')\n          .replaceAll('(function (', 'function sign(')\n          .replaceAll('CryptoJS.MD5(cb).toString()', '\"$rb\"');\n      var params = JsEngine.evaluate(\"$jsSign;sign($rid,'$did',$t10);\");\n      return params.toString();\n    } catch (e) {\n      CoreLog.error(e);\n      return \"\";\n    } finally {\n      JsEngine.dispose();\n    }\n    // 自部署：https://github.com/SlotSun/simple_live_api\n  }\n\n  int parseHotNum(String hn) {\n    try {\n      var num = double.parse(hn.replaceAll(\"万\", \"\"));\n      if (hn.contains(\"万\")) {\n        num *= 10000;\n      }\n      return num.round();\n    } catch (_) {\n      return -999;\n    }\n  }\n\n  @override\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) {\n    //尚不支持\n    return Future.value([]);\n  }\n}\n\nclass DouyuPlayData {\n  final int rate;\n  final List<String> cdns;\n  DouyuPlayData(this.rate, this.cdns);\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/huya/huya_site.dart",
    "content": "import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:crypto/crypto.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\nimport 'package:simple_live_core/src/model/tars/get_cdn_token_ex_req.dart';\nimport 'package:simple_live_core/src/model/tars/get_cdn_token_ex_resp.dart';\nimport 'package:simple_live_core/src/model/tars/types.dart';\nimport 'package:simple_live_core/src/platforms/huya/utils.dart';\nimport 'package:tars_dart/tars/net/base_tars_http.dart';\n\nclass HuyaSite implements LiveSite {\n  static const String baseUrl = \"https://www.huya.com\";\n  static const String wupUrl = \"http://wup.huya.com\";\n  static const String kUserAgent =\n      \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36 Edg/117.0.0.0\";\n\n  // regex\n  /// 匹配房间数据\n  static const String ROOM_DATA_REGEX =\n      r'var\\s+TT_ROOM_DATA\\s*=\\s*(\\{[\\s\\S]*?\\})';\n\n  /// 匹配流数据\n  static const String STREAM_REGEX = r\"stream:\\s*(\\{[\\s\\S]*?\\n\\s*\\})\";\n\n  /// 匹配 YY ID\n  static const String AYYUID_REGEX = r'\"yyid\":\"?(\\d+)\"?';\n\n  static const String HYSDK_UA =\n      \"HYSDK(Windows,30000002)_APP(pc_exe&7070000&official)_SDK(trans&2.33.0.5678)\";\n\n  static Map<String, String> get requestHeaders {\n    return {\n      'Origin': baseUrl,\n      'Referer': baseUrl,\n      'User-Agent': HYSDK_UA,\n    };\n  }\n\n  final BaseTarsHttp tupClient =\n      BaseTarsHttp(\"http://wup.huya.com\", \"liveui\", headers: requestHeaders);\n\n\n  @override\n  String id = \"huya\";\n\n  @override\n  String name = \"虎牙直播\";\n\n  @override\n  LiveDanmaku getDanmaku() => HuyaDanmaku();\n\n  @override\n  Future<List<LiveCategory>> getCategores() async {\n    List<LiveCategory> categories = [\n      LiveCategory(id: \"1\", name: \"网游\", children: []),\n      LiveCategory(id: \"2\", name: \"单机\", children: []),\n      LiveCategory(id: \"8\", name: \"娱乐\", children: []),\n      LiveCategory(id: \"3\", name: \"手游\", children: []),\n    ];\n\n    for (var item in categories) {\n      var items = await getSubCategores(item.id);\n      item.children.addAll(items);\n    }\n    return categories;\n  }\n\n  Future<List<LiveSubCategory>> getSubCategores(String id) async {\n    var result = await HttpClient.instance.getJson(\n      \"https://live.cdn.huya.com/liveconfig/game/bussLive\",\n      queryParameters: {\n        \"bussType\": id,\n      },\n    );\n\n    List<LiveSubCategory> subs = [];\n    for (var item in result[\"data\"]) {\n      var gid = \"\";\n\n      if (item[\"gid\"] is Map) {\n        gid = item[\"gid\"][\"value\"].toString().split(\",\").first;\n      } else if (item[\"gid\"] is double) {\n        gid = item[\"gid\"].toInt().toString();\n      } else if (item[\"gid\"] is int) {\n        gid = item[\"gid\"].toString();\n      } else {\n        gid = item[\"gid\"].toString();\n      }\n\n      var subCategory = LiveSubCategory(\n        id: gid,\n        name: item[\"gameFullName\"].toString(),\n        parentId: id,\n        pic: \"https://huyaimg.msstatic.com/cdnimage/game/$gid-MS.jpg\",\n      );\n      subs.add(subCategory);\n    }\n\n    return subs;\n  }\n\n  @override\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) async {\n    var resultText = await HttpClient.instance.getJson(\n      \"https://www.huya.com/cache.php\",\n      queryParameters: {\n        \"m\": \"LiveList\",\n        \"do\": \"getLiveListByPage\",\n        \"tagAll\": 0,\n        \"gameId\": category.id,\n        \"page\": page\n      },\n    );\n    var result = json.decode(resultText);\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"datas\"]) {\n      var cover = item[\"screenshot\"].toString();\n      if (!cover.contains(\"?\")) {\n        cover += \"?x-oss-process=style/w338_h190&\";\n      }\n      var title = item[\"introduction\"]?.toString() ?? \"\";\n      if (title.isEmpty) {\n        title = item[\"roomName\"]?.toString() ?? \"\";\n      }\n\n      var roomItem = LiveRoomItem(\n        roomId: item[\"profileRoom\"].toString(),\n        title: title,\n        cover: cover,\n        userName: item[\"nick\"].toString(),\n        online: int.tryParse(item[\"totalCount\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    var hasMore = result[\"data\"][\"page\"] < result[\"data\"][\"totalPage\"];\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) {\n    List<LivePlayQuality> qualities = <LivePlayQuality>[];\n    var urlData = detail.data as HuyaUrlDataModel;\n    if (urlData.bitRates.isEmpty) {\n      urlData.bitRates = [\n        HuyaBitRateModel(\n          name: \"原画\",\n          bitRate: 0,\n        ),\n        HuyaBitRateModel(name: \"高清\", bitRate: 2000),\n      ];\n    }\n\n    for (var item in urlData.bitRates) {\n      qualities.add(LivePlayQuality(\n        data: {\n          \"urls\": urlData.lines,\n          \"bitRate\": item.bitRate,\n        },\n        quality: item.name,\n      ));\n    }\n\n    return Future.value(qualities);\n  }\n\n  @override\n  Future<LivePlayUrl> getPlayUrls(\n      {required LiveRoomDetail detail,\n      required LivePlayQuality quality}) async {\n    var ls = <String>[];\n    for (var element in quality.data[\"urls\"]) {\n      var line = element as HuyaLineModel;\n      var url = await getPlayUrl(line, quality.data[\"bitRate\"]);\n      ls.add(url);\n    }\n    return LivePlayUrl(\n      urls: ls,\n      headers: {\"user-agent\": HYSDK_UA},\n    );\n  }\n\n  Future<String> getPlayUrl(HuyaLineModel line, int bitRate) async {\n    var suffix = line.lineType == HuyaLineType.hls ? \"m3u8\" : \"flv\";\n    var antiCode = await getCndTokenInfoEx(line.streamName);\n    antiCode = buildAntiCode(line.streamName, line.presenterUid, antiCode);\n    var url = '${line.line}/${line.streamName}.$suffix?$antiCode&codec=264';\n    if (bitRate > 0) {\n      url += \"&ratio=$bitRate\";\n    }\n    return url;\n  }\n\n  @override\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) async {\n    var resultText = await HttpClient.instance.getJson(\n      \"https://www.huya.com/cache.php\",\n      queryParameters: {\n        \"m\": \"LiveList\",\n        \"do\": \"getLiveListByPage\",\n        \"tagAll\": 0,\n        \"page\": page\n      },\n    );\n    var result = json.decode(resultText);\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"data\"][\"datas\"]) {\n      var cover = item[\"screenshot\"].toString();\n      if (!cover.contains(\"?\")) {\n        cover += \"?x-oss-process=style/w338_h190&\";\n      }\n      var title = item[\"introduction\"]?.toString() ?? \"\";\n      if (title.isEmpty) {\n        title = item[\"roomName\"]?.toString() ?? \"\";\n      }\n\n      var roomItem = LiveRoomItem(\n        roomId: item[\"profileRoom\"].toString(),\n        title: title,\n        cover: cover,\n        userName: item[\"nick\"].toString(),\n        online: int.tryParse(item[\"totalCount\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    var hasMore = result[\"data\"][\"page\"] < result[\"data\"][\"totalPage\"];\n    return LiveCategoryResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) async {\n    late LiveRoomDetail result;\n    var resultText = await HttpClient.instance.getText(\n      \"$baseUrl/$roomId\",\n      queryParameters: {},\n      header: requestHeaders,\n    );\n    // get_live_status\n    var roomData = RegExp(ROOM_DATA_REGEX, multiLine: false)\n        .firstMatch(resultText)\n        ?.group(0)\n        ?.replaceAll(\"var TT_ROOM_DATA = \", \"\");\n    var streamData = RegExp(STREAM_REGEX)\n            .firstMatch(resultText)\n            ?.group(0)\n            ?.replaceAll(\"stream: \", \"\")\n            .split('\\n')[0] ??\n        '\"\"';\n    if (roomData != null) {\n      try {\n        Map<String, dynamic> roomDataJson = json.decode(roomData);\n        Map<String, dynamic> streamJson = json.decode(streamData);\n        var streamDataJson = streamJson[\"data\"][0];\n        var streamDataGameLiveInfo = streamDataJson[\"gameLiveInfo\"];\n        result = LiveRoomDetail(\n          roomId: roomId,\n          title: streamDataGameLiveInfo[\"introduction\"],\n          cover: streamDataGameLiveInfo[\"screenshot\"],\n          userName: streamDataGameLiveInfo[\"nick\"],\n          userAvatar: streamDataGameLiveInfo[\"avatar180\"],\n          online: streamDataGameLiveInfo[\"totalCount\"],\n          status: roomDataJson[\"state\"] == \"ON\" &&\n              roomDataJson[\"isReplay\"] == false,\n          url: \"https://www.huya.com/$roomId\",\n          introduction: streamDataGameLiveInfo[\"introduction\"],\n          notice: streamDataGameLiveInfo[\"introduction\"],\n          isRecord: roomDataJson[\"isReplay\"],\n        );\n        // live -> add HuyaUrlDataModel and danmaku\n        if (result.status) {\n          var streamDataGameStreamInfo =\n              streamDataJson[\"gameStreamInfoList\"][0];\n          // danmaku\n          // maybe int or string don't know why\n          var topSid =\n              int.tryParse(streamDataGameStreamInfo[\"lChannelId\"].toString());\n          var subSid = int.tryParse(\n              streamDataGameStreamInfo[\"lSubChannelId\"].toString());\n          var yySid = int.tryParse(streamDataGameLiveInfo[\"yyid\"].toString());\n          result = result.updateDanmakuData(\n            HuyaDanmakuArgs(\n              ayyuid: yySid ?? 0,\n              topSid: topSid ?? 0,\n              subSid: subSid ?? 0,\n            ),\n          );\n\n          // HuyaUrlDataModel\n          var huyaLines = <HuyaLineModel>[];\n          var huyaBiterates = <HuyaBitRateModel>[];\n          final lineTypes = {\n            'sFlvUrl': HuyaLineType.flv,\n            'sHlsUrl': HuyaLineType.hls,\n          };\n          //读取可用线路\n          var lines = streamDataJson[\"gameStreamInfoList\"];\n          for (var item in lines) {\n            lineTypes.forEach((key, type) {\n              final url = item[key]?.toString() ?? \"\";\n              if (url.isNotEmpty) {\n                huyaLines.add(\n                  HuyaLineModel(\n                    line: url,\n                    lineType: type,\n                    flvAntiCode: item[\"sFlvAntiCode\"].toString(),\n                    hlsAntiCode: item[\"sHlsAntiCode\"].toString(),\n                    streamName: item[\"sStreamName\"].toString(),\n                    cdnType: item[\"sCdnType\"].toString(),\n                    presenterUid: topSid ?? 0,\n                  ),\n                );\n              }\n            });\n          }\n          //清晰度\n          var biterates = streamJson[\"vMultiStreamInfo\"];\n          for (var item in biterates) {\n            var name = item[\"sDisplayName\"].toString();\n            if (name.contains(\"HDR\")) {\n              continue;\n            }\n            huyaBiterates.add(HuyaBitRateModel(\n              bitRate: item[\"iBitRate\"],\n              name: name,\n            ));\n          }\n          result = result.updateData(\n            HuyaUrlDataModel(\n              url: \"huya need rebuild new url\",\n              lines: huyaLines,\n              bitRates: huyaBiterates,\n              uid: getUid(t: 13, e: 10),\n            ),\n          );\n        }\n      } catch (e) {\n        CoreLog.error('JSON 解析失败: $e');\n        CoreLog.error('原始字符串: $roomData');\n      }\n    }\n\n    return result;\n  }\n\n  // 构造 anticode, python转写\n  /// [stream] streamname [presenterUid] 用户id [antiCode] 页面anti\n  ///\n  /// return ture anticode\n  String buildAntiCode(String stream, int presenterUid, String antiCode) {\n    var mapAnti = Uri(query: antiCode).queryParametersAll;\n    if (!mapAnti.containsKey(\"fm\")) {\n      return antiCode;\n    }\n\n    var ctype = mapAnti[\"ctype\"]?.first ?? \"huya_pc_exe\";\n    var platformId = int.tryParse(mapAnti[\"t\"]?.first ?? \"0\");\n\n    bool isWap = platformId == 103;\n    var clacStartTime = DateTime.now().millisecondsSinceEpoch;\n\n    CoreLog.i(\n        \"using $presenterUid | ctype-{$ctype} | platformId - {$platformId} | isWap - {$isWap} | $clacStartTime\");\n\n    var seqId = presenterUid + clacStartTime;\n    final secretHash =\n        md5.convert(utf8.encode('$seqId|$ctype|$platformId')).toString();\n\n    final convertUid = rotl64(presenterUid);\n    final calcUid = isWap ? presenterUid : convertUid;\n    final fm = Uri.decodeComponent(mapAnti['fm']!.first);\n    final secretPrefix = utf8.decode(base64.decode(fm)).split('_').first;\n    var wsTime = mapAnti['wsTime']!.first;\n    final secretStr =\n        '${secretPrefix}_${calcUid}_${stream}_${secretHash}_$wsTime';\n\n    final wsSecret = md5.convert(utf8.encode(secretStr)).toString();\n\n    final rnd = Random();\n    final ct =\n        ((int.parse(wsTime, radix: 16) + rnd.nextDouble()) * 1000).toInt();\n    final uuid = (((ct % 1e10) + rnd.nextDouble()) * 1e3 % 0xffffffff)\n        .toInt()\n        .toString();\n    final Map<String, dynamic> antiCodeRes = {\n      'wsSecret': wsSecret,\n      'wsTime': wsTime,\n      'seqid': seqId,\n      'ctype': ctype,\n      'ver': '1',\n      'fs': mapAnti['fs']!.first,\n      'fm': fm,\n      't': platformId,\n    };\n    if (isWap) {\n      antiCodeRes.addAll({\n        'uid': presenterUid,\n        'uuid': uuid,\n      });\n    } else {\n      antiCodeRes['u'] = convertUid;\n    }\n\n    return antiCodeRes.entries.map((e) => '${e.key}=${e.value}').join('&');\n  }\n\n  /// return sFlvToken\n  Future<String> getCndTokenInfoEx(String stream) async {\n    var func = \"getCdnTokenInfoEx\";\n    var tid = HuyaUserId();\n    tid.sHuYaUA = \"pc_exe&7060000&official\";\n    var tReq = GetCdnTokenExReq();\n    tReq.tId = tid;\n    tReq.sStreamName = stream;\n    var resp = await tupClient.tupRequest(func, tReq, GetCdnTokenExResp());\n    return resp.sFlvToken;\n  }\n\n  @override\n  Future<LiveSearchRoomResult> searchRooms(String keyword,\n      {int page = 1}) async {\n    var resultText = await HttpClient.instance.getJson(\n      \"https://search.cdn.huya.com/\",\n      queryParameters: {\n        \"m\": \"Search\",\n        \"do\": \"getSearchContent\",\n        \"q\": keyword,\n        \"uid\": 0,\n        \"v\": 4,\n        \"typ\": -5,\n        \"livestate\": 0,\n        \"rows\": 20,\n        \"start\": (page - 1) * 20,\n      },\n    );\n    var result = json.decode(resultText);\n    var items = <LiveRoomItem>[];\n    for (var item in result[\"response\"][\"3\"][\"docs\"]) {\n      var cover = item[\"game_screenshot\"].toString();\n      if (!cover.contains(\"?\")) {\n        cover += \"?x-oss-process=style/w338_h190&\";\n      }\n\n      var title = item[\"game_introduction\"]?.toString() ?? \"\";\n      if (title.isEmpty) {\n        title = item[\"game_roomName\"]?.toString() ?? \"\";\n      }\n\n      var roomItem = LiveRoomItem(\n        roomId: \"yy/${item[\"yyid\"]}\",\n        title: title,\n        cover: cover,\n        userName: item[\"game_nick\"].toString(),\n        online: int.tryParse(item[\"game_total_count\"].toString()) ?? 0,\n      );\n      items.add(roomItem);\n    }\n    var hasMore = result[\"response\"][\"3\"][\"numFound\"] > (page * 20);\n    return LiveSearchRoomResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword,\n      {int page = 1}) async {\n    var resultText = await HttpClient.instance.getJson(\n      \"https://search.cdn.huya.com/\",\n      queryParameters: {\n        \"m\": \"Search\",\n        \"do\": \"getSearchContent\",\n        \"q\": keyword,\n        \"uid\": 0,\n        \"v\": 1,\n        \"typ\": -5,\n        \"livestate\": 0,\n        \"rows\": 20,\n        \"start\": (page - 1) * 20,\n      },\n    );\n    var result = json.decode(resultText);\n    var items = <LiveAnchorItem>[];\n    for (var item in result[\"response\"][\"1\"][\"docs\"]) {\n      var anchorItem = LiveAnchorItem(\n        roomId: item[\"room_id\"].toString(),\n        avatar: item[\"game_avatarUrl180\"].toString(),\n        userName: item[\"game_nick\"].toString(),\n        liveStatus: item[\"gameLiveOn\"],\n      );\n      items.add(anchorItem);\n    }\n    var hasMore = result[\"response\"][\"1\"][\"numFound\"] > (page * 20);\n    return LiveSearchAnchorResult(hasMore: hasMore, items: items);\n  }\n\n  @override\n  Future<bool> getLiveStatus({required String roomId}) async {\n    var resultText = await HttpClient.instance.getText(\n      \"$baseUrl/$roomId\",\n      queryParameters: {},\n      header: requestHeaders,\n    );\n    var jsonString = RegExp(ROOM_DATA_REGEX, multiLine: false)\n        .firstMatch(resultText)\n        ?.group(0)\n        ?.replaceAll(\"var TT_ROOM_DATA = \", \"\");\n    if (jsonString != null) {\n      try {\n        Map<String, dynamic> roomData = json.decode(jsonString);\n        return roomData[\"state\"] == \"ON\" && roomData[\"isReplay\"] == false;\n      } catch (e) {\n        CoreLog.error('JSON 解析失败: $e');\n        CoreLog.error('原始字符串: $jsonString');\n      }\n    }\n    return false;\n  }\n  \n  /// 匿名登录获取uid\n  Future<String> getAnonymousUid() async {\n    var result = await HttpClient.instance.postJson(\n      \"https://udblgn.huya.com/web/anonymousLogin\",\n      data: {\n        \"appId\": 5002,\n        \"byPass\": 3,\n        \"context\": \"\",\n        \"version\": \"2.4\",\n        \"data\": {}\n      },\n      header: {\n        \"user-agent\": kUserAgent,\n      },\n    );\n    return result[\"data\"][\"uid\"].toString();\n  }\n\n  String getUUid() {\n    var currentTime = DateTime.now().millisecondsSinceEpoch;\n    var randomValue = Random().nextInt(4294967295);\n    var result = (currentTime % 10000000000 * 1000 + randomValue) % 4294967295;\n    return result.toString();\n  }\n\n  String getUid({int? t, int? e}) {\n    var n = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"\n        .split(\"\");\n    var o = List.filled(36, '');\n    if (t != null) {\n      for (var i = 0; i < t; i++) {\n        o[i] = n[Random().nextInt(e ?? n.length)];\n      }\n    } else {\n      o[8] = o[13] = o[18] = o[23] = \"-\";\n      o[14] = \"4\";\n      for (var i = 0; i < 36; i++) {\n        if (o[i].isEmpty) {\n          var r = Random().nextInt(16);\n          o[i] = n[19 == i ? 3 & r | 8 : r];\n        }\n      }\n    }\n    return o.join(\"\");\n  }\n\n  @override\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) {\n    //尚不支持\n    return Future.value([]);\n  }\n}\n\nclass HuyaUrlDataModel {\n  final String url;\n  final String uid;\n  List<HuyaLineModel> lines;\n  List<HuyaBitRateModel> bitRates;\n\n  HuyaUrlDataModel({\n    required this.bitRates,\n    required this.lines,\n    required this.url,\n    required this.uid,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"url\": url,\n      \"uid\": uid,\n      \"lines\": lines.map((e) => e.toString()).toList(),\n      \"bitRates\": bitRates.map((e) => e.toString()).toList(),\n    });\n  }\n}\n\nenum HuyaLineType {\n  flv,\n  hls,\n}\n\nclass HuyaLineModel {\n  final String line;\n  final String cdnType;\n  final String flvAntiCode;\n  final String hlsAntiCode;\n  final String streamName;\n  final HuyaLineType lineType;\n  int bitRate;\n  final int presenterUid;\n\n  HuyaLineModel({\n    required this.line,\n    required this.lineType,\n    required this.flvAntiCode,\n    required this.hlsAntiCode,\n    required this.streamName,\n    required this.cdnType,\n    this.bitRate = 0,\n    required this.presenterUid,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"line\": line,\n      \"cdnType\": cdnType,\n      \"flvAntiCode\": flvAntiCode,\n      \"hlsAntiCode\": hlsAntiCode,\n      \"streamName\": streamName,\n      \"lineType\": lineType.toString(),\n      \"presenterUid\": presenterUid,\n    });\n  }\n}\n\nclass HuyaBitRateModel {\n  final String name;\n  final int bitRate;\n\n  HuyaBitRateModel({\n    required this.bitRate,\n    required this.name,\n  });\n\n  @override\n  String toString() {\n    return json.encode({\n      \"name\": name,\n      \"bitRate\": bitRate,\n    });\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/huya/utils.dart",
    "content": "﻿int rotl64(int t) {\n  final low = t & 0xFFFFFFFF;\n  final rotatedLow =\n  ((low << 8) | (low >> 24)) & 0xFFFFFFFF;\n  final high = t & ~0xFFFFFFFF;\n  return high | rotatedLow;\n}"
  },
  {
    "path": "simple_live_core/lib/src/platforms/readme.md",
    "content": "﻿### 自simple_live_core version-1.0.4 新平台开始使用 json to dart model\n- 类型安全\n- 随着平台增多，补全非常重要\n- API 字段变化，有助于重构和维护\n- 数据转换等操作更简单\n- 无缝同步参考项目\n### 工作流程\n- getRoomDetail->getPlayQualities->getPlayUrls"
  },
  {
    "path": "simple_live_core/lib/src/platforms/twitch/models.dart",
    "content": "class TwitchResponse {\n  final Data data;\n\n  TwitchResponse({required this.data});\n\n  factory TwitchResponse.fromJson(Map<String, dynamic> json) {\n    return TwitchResponse(\n      data: Data.fromJson(json['data']),\n    );\n  }\n}\n\nclass Data {\n  final UserOrError? userOrError;\n  final User? user;\n\n  Data({this.userOrError, this.user});\n\n  factory Data.fromJson(Map<String, dynamic> json) {\n    return Data(\n      userOrError: json['userOrError'] != null\n          ? UserOrError.fromJson(json['userOrError'])\n          : null,\n      user: json['user'] != null ? User.fromJson(json['user']) : null,\n    );\n  }\n}\n\nclass Extensions {\n  final int durationMilliseconds;\n  final String operationName;\n  final String requestId;\n\n  Extensions({\n    required this.durationMilliseconds,\n    required this.operationName,\n    required this.requestId,\n  });\n\n  factory Extensions.fromJson(Map<String, dynamic> json) {\n    return Extensions(\n      durationMilliseconds: json['durationMilliseconds'],\n      operationName: json['operationName'],\n      requestId: json['requestId'],\n    );\n  }\n}\n\nclass UserOrError {\n  final String id;\n  final String login;\n  final String displayName;\n  final String primaryColorHex;\n  final String profileImageUrl;\n  final Stream? stream;\n  final String typename;\n\n  UserOrError({\n    required this.id,\n    required this.login,\n    required this.displayName,\n    required this.primaryColorHex,\n    required this.profileImageUrl,\n    this.stream,\n    required this.typename,\n  });\n\n  factory UserOrError.fromJson(Map<String, dynamic> json) {\n    return UserOrError(\n      id: json['id'] ?? '',\n      login: json['login'] ?? '',\n      displayName: json['displayName'] ?? '',\n      primaryColorHex: json['primaryColorHex'] ?? '',\n      profileImageUrl: json['profileImageURL'] ?? '',\n      stream: json['stream'] != null ? Stream.fromJson(json['stream']) : null,\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass User {\n  final String id;\n  final String primaryColorHex;\n  final bool isPartner;\n  final String profileImageUrl;\n  final PrimaryTeam? primaryTeam;\n  final Channel channel;\n  final LastBroadcast? lastBroadcast;\n  final Stream? stream;\n  final String typename;\n\n  User({\n    required this.id,\n    required this.primaryColorHex,\n    required this.isPartner,\n    required this.profileImageUrl,\n    this.primaryTeam,\n    required this.channel,\n    this.lastBroadcast,\n    this.stream,\n    required this.typename,\n  });\n\n  factory User.fromJson(Map<String, dynamic> json) {\n    return User(\n      id: json['id'] ?? '',\n      primaryColorHex: json['primaryColorHex'] ?? '',\n      isPartner: json['isPartner'] ?? false,\n      profileImageUrl: json['profileImageURL'] ?? '',\n      primaryTeam: json['primaryTeam'] != null\n          ? PrimaryTeam.fromJson(json['primaryTeam'])\n          : null,\n      channel: Channel.fromJson(json['channel']),\n      lastBroadcast: json['lastBroadcast'] != null\n          ? LastBroadcast.fromJson(json['lastBroadcast'])\n          : null,\n      stream: json['stream'] != null ? Stream.fromJson(json['stream']) : null,\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass Stream {\n  final String id;\n  final int viewersCount;\n  final String typename;\n  final String? streamType;\n  final String? createdAt;\n  final Game? game;\n\n  Stream({\n    required this.id,\n    required this.viewersCount,\n    required this.typename,\n    this.streamType,\n    this.createdAt,\n    this.game,\n  });\n\n  factory Stream.fromJson(Map<String, dynamic> json) {\n    return Stream(\n      id: json['id'] ?? '',\n      viewersCount: json['viewersCount'] ?? 0,\n      typename: json['__typename'] ?? '',\n      streamType: json['type'],\n      createdAt: json['createdAt'],\n      game: json['game'] != null ? Game.fromJson(json['game']) : null,\n    );\n  }\n}\n\nclass Game {\n  final String id;\n  final String name;\n  final String typename;\n\n  Game({\n    required this.id,\n    required this.name,\n    required this.typename,\n  });\n\n  factory Game.fromJson(Map<String, dynamic> json) {\n    return Game(\n      id: json['id'] ?? '',\n      name: json['name'] ?? '',\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass Channel {\n  final String id;\n  final String typename;\n  final ChannelSelfEdge? selfEdge;\n  final Trailer? trailer;\n\n  Channel({\n    required this.id,\n    required this.typename,\n    this.selfEdge,\n    this.trailer,\n  });\n\n  factory Channel.fromJson(Map<String, dynamic> json) {\n    return Channel(\n      id: json['id'] ?? '',\n      typename: json['__typename'] ?? '',\n      selfEdge:\n          json['self'] != null ? ChannelSelfEdge.fromJson(json['self']) : null,\n      trailer:\n          json['trailer'] != null ? Trailer.fromJson(json['trailer']) : null,\n    );\n  }\n}\n\nclass ChannelSelfEdge {\n  final bool isAuthorized;\n  final String? restrictionType;\n  final String typename;\n\n  ChannelSelfEdge({\n    required this.isAuthorized,\n    this.restrictionType,\n    required this.typename,\n  });\n\n  factory ChannelSelfEdge.fromJson(Map<String, dynamic> json) {\n    return ChannelSelfEdge(\n      isAuthorized: json['isAuthorized'] ?? false,\n      restrictionType: json['restrictionType'],\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass Trailer {\n  final String typename;\n\n  Trailer({\n    required this.typename,\n  });\n\n  factory Trailer.fromJson(Map<String, dynamic> json) {\n    return Trailer(\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass PrimaryTeam {\n  final String id;\n  final String name;\n  final String displayName;\n  final String typename;\n\n  PrimaryTeam({\n    required this.id,\n    required this.name,\n    required this.displayName,\n    required this.typename,\n  });\n\n  factory PrimaryTeam.fromJson(Map<String, dynamic> json) {\n    return PrimaryTeam(\n      id: json['id'] ?? '',\n      name: json['name'] ?? '',\n      displayName: json['displayName'] ?? '',\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n\nclass LastBroadcast {\n  final String id;\n  final String title;\n  final String typename;\n\n  LastBroadcast({\n    required this.id,\n    required this.title,\n    required this.typename,\n  });\n\n  factory LastBroadcast.fromJson(Map<String, dynamic> json) {\n    return LastBroadcast(\n      id: json['id'] ?? '',\n      title: json['title'] ?? '',\n      typename: json['__typename'] ?? '',\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_core/lib/src/platforms/twitch/twitch_site.dart",
    "content": "﻿import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_core/src/common/http_client.dart';\nimport 'package:simple_live_core/src/danmaku/twitch_danmaku.dart';\nimport 'package:simple_live_core/src/platforms/twitch/models.dart';\n\nclass TwitchSite implements LiveSite {\n  @override\n  String id = 'twitch';\n\n  @override\n  String name = 'Twitch';\n\n  final _playUrlList = <String>[];\n\n  static const defaultUa =\n      \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36\";\n  static const gplApiUrl = \"https://gql.twitch.tv/gql\";\n\n  static const baseUrl = \"https://www.twitch.tv\";\n\n  Map<String, String> headers = {\n    'user-agent': defaultUa,\n    'accept-language': 'en-US,en;q=0.9',\n    'accept': 'application/vnd.twitchtv.v5+json',\n    'accept-encoding': 'gzip, deflate',\n    'client-id': 'kimne78kx3ncx6brgo4mv6wki5h1ko',\n  };\n\n  final playSessionIds = [\n    \"bdd22331a986c7f1073628f2fc5b19da\",\n    \"064bc3ff1722b6f53b0b5b8c01e46ca5\"\n  ];\n\n  void getRequestHeaders() {\n    headers['device-id'] = getDeviceId();\n    // no token\n    // no cookie\n  }\n\n  // 生成设备id\n  String getDeviceId() {\n    final random = Random();\n    final deviceId = 1000000000000000 + random.nextInt(1 << 32);\n    return deviceId.toString();\n  }\n\n  String buildPersistedRequest(\n      String operationName, String sha265Hash, Map<String, dynamic> variables) {\n    final variablesJson = jsonEncode(variables);\n    final query = '''\n     {\n       \"operationName\": \"$operationName\",\n       \"extensions\": {\n         \"persistedQuery\": {\n           \"version\": 1,\n           \"sha256Hash\": \"$sha265Hash\"\n         }\n       },\n       \"variables\": $variablesJson\n     }\n     ''';\n    return query.trim();\n  }\n\n  @override\n  Future<List<LiveCategory>> getCategores() {\n    //尚不支持\n    return Future.value([]);\n  }\n\n  @override\n  Future<LiveCategoryResult> getCategoryRooms(LiveSubCategory category,\n      {int page = 1}) {\n    //尚不支持\n    return Future.value(LiveCategoryResult(hasMore: false, items: []));\n  }\n\n  @override\n  LiveDanmaku getDanmaku() => TwitchDanmaku();\n\n  @override\n  Future<bool> getLiveStatus({required String roomId}) async {\n    var detail = await getRoomDetail(roomId: roomId);\n    var status = detail.status;\n    return status;\n  }\n\n  @override\n  Future<List<LivePlayQuality>> getPlayQualites(\n      {required LiveRoomDetail detail}) async {\n    List<LivePlayQuality> qualities = <LivePlayQuality>[];\n    var liveGpl = buildPersistedRequest(\n      \"PlaybackAccessToken\",\n      \"ed230aa1e33e07eebb8928504583da78a5173989fadfb1ac94be06a04f3cdbe9\",\n      {\n        \"isLive\": true,\n        \"login\": detail.roomId,\n        \"isVod\": false,\n        \"vodID\": \"\",\n        \"playerType\": \"site\",\n        \"isClip\": false,\n        \"clipID\": \"\",\n        \"platform\": \"site\"\n      },\n    );\n    var response = await HttpClient.instance.postJson(\n      gplApiUrl,\n      header: headers,\n      data: liveGpl,\n    );\n    var token = response['data']['streamPlaybackAccessToken']['value'];\n    var sign = response['data']['streamPlaybackAccessToken']['signature'];\n    var liveStatus = detail.status;\n    if (liveStatus) {\n      // 随机选择一个sessionId\n      var random = Random();\n      var playSessionId = playSessionIds[random.nextInt(playSessionIds.length)];\n      var epochSecondsStr = DateTime.timestamp().second.toString();\n      var params = {\n        \"acmb\": \"e30=\",\n        \"allow_source\": \"true\",\n        \"cdm\": \"wv\",\n        \"fast_bread\": \"true\",\n        \"p\": epochSecondsStr,\n        \"platform\": \"web\",\n        \"play_session_id\": playSessionId,\n        \"player_backend\": \"mediaplayer\",\n        \"player_version\": \"1.28.0-rc.1\",\n        \"playlist_include_framerate\": \"true\",\n        \"reassignments_supported\": \"true\",\n        \"sig\": sign,\n        \"token\": token,\n        \"transcode_mode\": \"cbr_v1\"\n      };\n      var m3u8Url =\n          \"https://usher.ttvnw.net/api/channel/hls/${detail.roomId}.m3u8\";\n      var content = await HttpClient.instance.getText(\n        m3u8Url,\n        queryParameters: params,\n        header: headers,\n      );\n      // 这里需要一个 m3u8解析器\n      _playUrlList.clear(); // 重置\n      final lines = content.split(\"\\n\");\n\n      for (var i in lines) {\n        if (i.startsWith(\"https://\")) {\n          _playUrlList.add(i.trim());\n        }\n      }\n\n      if (_playUrlList.isEmpty) {\n        for (final i in lines) {\n          if (i.trim().endsWith('m3u8')) {\n            _playUrlList.add(i.trim());\n          }\n        }\n      }\n      // 匹配带宽信息\n      final bandwidthPattern = RegExp(r'BANDWIDTH=(\\d+)');\n      final bandwidthList = bandwidthPattern\n          .allMatches(content)\n          .map((match) => match.group(1)!)\n          .toList();\n      // 映射\n      final urlToBandwidth = <String, int>{};\n      for (int i = 0; i < _playUrlList.length; i++) {\n        final bandwidth =\n            i < bandwidthList.length ? int.parse(bandwidthList[i]) : 0;\n        urlToBandwidth[_playUrlList[i]] = bandwidth;\n      }\n      _playUrlList\n          .sort((a, b) => urlToBandwidth[b]!.compareTo(urlToBandwidth[a]!));\n\n      qualities = _playUrlList.map((url) {\n        final bandwidth = urlToBandwidth[url] ?? 0;\n        return LivePlayQuality(\n          quality: _getQualityName(bandwidth),\n          data: url, // 这里data直接存储播放URL\n          sort: bandwidth,\n        );\n      }).toList();\n    }\n    return qualities;\n  }\n\n  // twitch的清晰度转换\n  String _getQualityName(int bandwidth) {\n    if (bandwidth > 5000000) return '1080P';\n    if (bandwidth > 2500000) return '720P';\n    if (bandwidth > 1000000) return '480P';\n    if (bandwidth > 500000) return '360P';\n    return '自动';\n  }\n\n  @override\n  Future<LivePlayUrl> getPlayUrls({\n    required LiveRoomDetail detail,\n    required LivePlayQuality quality,\n  }) async {\n    return LivePlayUrl(\n      urls: [quality.data],\n      headers: headers,\n    );\n  }\n\n  @override\n  Future<LiveCategoryResult> getRecommendRooms({int page = 1}) {\n    throw UnimplementedError();\n  }\n\n  @override\n  Future<LiveRoomDetail> getRoomDetail({required String roomId}) async {\n    var roomInfo = await _getRoomInfo(roomId);\n    var channelShell = roomInfo.first;\n    var streamMetaData = roomInfo[1];\n\n    final userOrError = channelShell.data.userOrError;\n    if (userOrError == null) {\n      final error = channelShell.data.userOrError;\n      if (error?.typename == 'UserNotFoundError') {\n        CoreLog.e('User not found: ${error?.displayName}', StackTrace.empty);\n        throw Exception('Could not find user_or_error');\n      }\n    }\n    var user = streamMetaData.data.user;\n    if (user == null) {\n      CoreLog.e(\n          'User not found: ${userOrError?.displayName}', StackTrace.empty);\n      throw Exception('Could not find user');\n    }\n    bool online = switch (user.stream) {\n      Stream stream when stream.streamType == 'live' => true,\n      _ => false,\n    };\n    var title = user.lastBroadcast?.title ?? \"null\";\n    return LiveRoomDetail(\n        roomId: roomId,\n        title: title,\n        cover: user.profileImageUrl,\n        userName: userOrError!.displayName,\n        userAvatar: user.profileImageUrl,\n        online: online ? user.stream!.viewersCount : 0,\n        status: online,\n        url: \"$baseUrl/$roomId\",\n        introduction: \"\",\n        notice: \"\",\n        danmakuData: roomId,\n        data: null);\n  }\n\n  Future<List<TwitchResponse>> _getRoomInfo(String roomId) async {\n    var queries = [\n      buildPersistedRequest(\n        \"ChannelShell\",\n        \"fea4573a7bf2644f5b3f2cbbdcbee0d17312e48d2e55f080589d053aad353f11\",\n        {\n          \"login\": roomId,\n        },\n      ),\n      buildPersistedRequest(\n        \"StreamMetadata\",\n        \"b57f9b910f8cd1a4659d894fe7550ccc81ec9052c01e438b290fd66a040b9b93\",\n        {\n          \"channelLogin\": roomId,\n          \"includeIsDJ\": true,\n        },\n      )\n    ];\n    String requestQuery = \"[${queries.map((q) => q.toString()).join(',')}]\";\n    CoreLog.i(\"twitch-queries:$requestQuery\");\n    getRequestHeaders();\n    var response = await HttpClient.instance.postJson(\n      gplApiUrl,\n      header: headers,\n      data: requestQuery,\n    );\n    CoreLog.d(\"twitch-response:$response\");\n\n    final List<dynamic> decoded = response;\n    final responses = decoded\n        .map((item) => TwitchResponse.fromJson(item as Map<String, dynamic>))\n        .toList();\n    if (responses.length < 2) {\n      CoreLog.error('Invalid response from Twitch API');\n    }\n    return responses;\n  }\n\n  @override\n  Future<List<LiveSuperChatMessage>> getSuperChatMessage(\n      {required String roomId}) {\n    //尚不支持\n    return Future.value([]);\n  }\n\n  @override\n  Future<LiveSearchAnchorResult> searchAnchors(String keyword, {int page = 1}) {\n    throw Exception(\"twitch暂不支持搜索主播\");\n  }\n\n  @override\n  Future<LiveSearchRoomResult> searchRooms(String keyword, {int page = 1}) {\n    throw Exception(\"twitch暂不支持搜索房间\");\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/.gitignore",
    "content": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\n.idea/\n.vagrant/\n.sconsign.dblite\n.svn/\n\n*.swp\nprofile\n\nDerivedData/\n\n.generated/\n\n*.pbxuser\n*.mode1v3\n*.mode2v3\n*.perspectivev3\n\n!default.pbxuser\n!default.mode1v3\n!default.mode2v3\n!default.perspectivev3\n\nxcuserdata\n\n*.moved-aside\n\n*.pyc\n*sync/\nIcon?\n.tags*\n\nbuild/\n.android/\n.ios/\n.flutter-plugins\n.flutter-plugins-dependencies\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\ntars_flutter.iml\ntars_flutter_android.iml\n.metadata\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/CHANGELOG.md",
    "content": "## 0.1.0\n\n- add doc\n\n## 0.0.8\n\n- first commit\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2021, THE TARS FOUNDATION\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "simple_live_core/packages/tars_dart/README.md",
    "content": "# Readme\n\nFork from https://github.dev/brooklet/TarsFlutter\n\n- 修改为dart包\n- 增加tup2支持"
  },
  {
    "path": "simple_live_core/packages/tars_dart/analysis_options.yaml",
    "content": "include: package:lints/recommended.yaml\nanalyzer:\n  errors:\n    unintended_html_in_doc_comment: ignore\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_decode_exception.dart",
    "content": "class TarsDecodeException extends Error {\n  String message;\n  TarsDecodeException(this.message);\n  @override\n  String toString() {\n    return message;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_deep_copyable.dart",
    "content": "abstract class DeepCopyable {\n  Object deepCopy();\n}\n\nList<T> listDeepCopy<T>(List list) {\n  List<T> newList = List<T>.filled(0, list[0], growable: true);\n  for (var value in list) {\n    newList.add(value is Map\n        ? mapDeepCopy(value)\n        : value is List\n            ? listDeepCopy(value)\n            : value is Set\n                ? setDeepCopy(value)\n                : value is DeepCopyable\n                    ? value.deepCopy() as T\n                    : value);\n  }\n  return newList;\n}\n\nSet<T> setDeepCopy<T>(Set s) {\n  Set<T> newSet = <T>{};\n  for (var value in s) {\n    newSet.add(value is Map\n        ? mapDeepCopy(value)\n        : value is List\n            ? listDeepCopy(value)\n            : value is Set\n                ? setDeepCopy(value)\n                : value is DeepCopyable\n                    ? value.deepCopy() as T\n                    : value);\n  }\n  return newSet;\n}\n\nMap<K, V> mapDeepCopy<K, V>(Map<K, V> map) {\n  Map<K, V> newMap = <K, V>{};\n\n  map.forEach((key, value) {\n    newMap[key] = (value is Map\n        ? mapDeepCopy(value)\n        : value is List\n            ? listDeepCopy(value)\n            : value is Set\n                ? setDeepCopy(value)\n                : value is DeepCopyable\n                    ? value.deepCopy() as V\n                    : value) as V;\n  });\n\n  return newMap;\n}\n\nMap<K, List<V>> mapListDeepCopy<K, V>(Map<K, List<V>> map) {\n  Map<K, List<V>> newMap = <K, List<V>>{};\n  map.forEach((key, value) {\n    newMap[key] = listDeepCopy<V>(value);\n  });\n  return newMap;\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_displayer.dart",
    "content": "// ignore_for_file: non_constant_identifier_names\n\nimport 'dart:typed_data';\n\nimport './tars_encode_exception.dart';\nimport './tars_struct.dart';\n\nclass TarsDisplayer {\n  late StringBuffer sb;\n  int _level = 0;\n  TarsDisplayer(this.sb, {int level = 0}) {\n    _level = level;\n  }\n\n  void ps(String? fieldName) {\n    for (var i = 0; i < _level; ++i) {\n      sb.write('\\t');\n    }\n\n    if (fieldName != null) {\n      sb.write(fieldName);\n      sb.write(': ');\n    }\n  }\n\n  TarsDisplayer? display(dynamic value, String? fieldName) {\n    if (value is bool) {\n      return DisplayBool(value, fieldName);\n    }\n    if (value is int) {\n      return DisplayInt(value, fieldName);\n    }\n    if (value is double) {\n      return DisplayDouble(value, fieldName);\n    }\n    if (value is String) {\n      return DisplayString(value, fieldName);\n    }\n    if (value is Uint8List) {\n      return DisplayUint8List(value, fieldName);\n    }\n    if (value is List) {\n      return DisplayArray(value, fieldName);\n    }\n    if (value is Map) {\n      return DisplayMap(value, fieldName);\n    }\n    if (value is TarsStruct) {\n      return DisplayTarsStruct(value, fieldName);\n    }\n    throw TarsEncodeException('write object error: unsupport type.');\n  }\n\n  TarsDisplayer DisplayBool(bool b, String? fieldName) {\n    ps(fieldName);\n    sb.write(b ? 'T' : 'F');\n    sb.write('\\n');\n    return this;\n  }\n\n  TarsDisplayer DisplayInt(int n, String? fieldName) {\n    ps(fieldName);\n    sb.write(n);\n    sb.write('\\n');\n    return this;\n  }\n\n  TarsDisplayer DisplayDouble(double n, String? fieldName) {\n    ps(fieldName);\n    sb.write(n);\n    sb.write('\\n');\n    return this;\n  }\n\n  TarsDisplayer DisplayString(String? s, String? fieldName) {\n    ps(fieldName);\n    if (null == s) {\n      sb.write('null');\n      sb.write('\\n');\n    } else {\n      sb.write(s);\n      sb.write('\\n');\n    }\n\n    return this;\n  }\n\n  TarsDisplayer DisplayUint8List(Uint8List? v, String? fieldName) {\n    ps(fieldName);\n    if (null == v) {\n      sb.write('null');\n      sb.write('\\n');\n      return this;\n    }\n    if (v.isEmpty) {\n      sb.write(v.length);\n      sb.write(', []');\n      sb.write('\\n');\n      return this;\n    }\n    sb.write(v.length);\n    sb.write(', []');\n    sb.write('\\n');\n    var jd = TarsDisplayer(sb, level: _level + 1);\n    for (var o in v) {\n      jd.display(o, null);\n    }\n\n    display(']', null);\n    return this;\n  }\n\n  TarsDisplayer DisplayMap<K, V>(Map<K, V>? m, String? fieldName) {\n    ps(fieldName);\n    if (null == m) {\n      sb.write('null');\n      sb.write('\\n');\n      return this;\n    }\n    if (m.isEmpty) {\n      sb.write(m.length);\n      sb.write(', {}');\n      sb.write('\\n');\n      return this;\n    }\n    sb.write(m.length);\n    sb.write(', {');\n    sb.write('\\n');\n    var jd1 = TarsDisplayer(sb, level: _level + 1);\n    var jd = TarsDisplayer(sb, level: _level + 2);\n    for (var key in m.keys) {\n      jd1.display('(', null);\n      jd.display(key, null);\n      jd.display(m[key], null);\n      jd1.display(')', null);\n    }\n    display('}', null);\n    return this;\n  }\n\n  TarsDisplayer DisplayArray<T>(List<T>? v, String? fieldName) {\n    ps(fieldName);\n    if (null == v) {\n      sb.write('null');\n      sb.write('\\n');\n      return this;\n    }\n    if (v.isEmpty) {\n      sb.write(v.length);\n      sb.write(', []');\n      sb.write('\\n');\n      return this;\n    }\n    sb.write(v.length);\n    sb.write(', [');\n    sb.write('\\n');\n    var jd = TarsDisplayer(sb, level: _level + 1);\n    for (var o in v) {\n      jd.display(o, null);\n    }\n    display(']', null);\n    return this;\n  }\n\n  TarsDisplayer DisplayList<T>(List<T>? v, String? fieldName) {\n    if (null == v) {\n      ps(fieldName);\n      sb.write('null');\n      sb.write('\\n');\n      return this;\n    } else {\n      for (var item in v) {\n        display(item, fieldName);\n      }\n\n      return this;\n    }\n  }\n\n  TarsDisplayer DisplayTarsStruct(TarsStruct? v, String? fieldName) {\n    display('{', fieldName);\n    if (null == v) {\n      sb.write('\\t');\n      sb.write('null');\n    } else {\n      v.displayAsString(sb, _level + 1);\n    }\n\n    display('}', null);\n    return this;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_encode_exception.dart",
    "content": "class TarsEncodeException extends Error {\n  String message;\n  TarsEncodeException(this.message);\n\n  @override\n  String toString() {\n    return message;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_input_stream.dart",
    "content": "import 'dart:convert';\nimport 'dart:core';\nimport 'dart:typed_data';\n\nimport 'tars_struct.dart';\nimport 'tars_decode_exception.dart';\n\nclass HeadData {\n  int type = 0;\n  int tag = 0;\n\n  void clear() {\n    type = 0;\n    tag = 0;\n  }\n}\n\nclass BinaryReader {\n  Uint8List buffer;\n  int position = 0;\n\n  BinaryReader(this.buffer);\n\n  int get length => buffer.length;\n\n  /// 从当前流中读取下一个字节，并使流的当前位置提升 1 个字节\n  /// 返回下一个字节(0-255)\n  int read() {\n    var byte = buffer[position];\n    position += 1;\n    return byte;\n  }\n\n  /// 从当前流中读取指定长度的字节整数，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// len=1为int8,2为int16,4为int32,8为int64。dart中统一为int类型\n  /// 返回整数\n  int readInt(int len) {\n    var result = 0;\n    // if (len == 1) {\n    //   result = buffer[position];\n    //   position += len;\n    //   return result;\n    // }\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    var byteBuffer = bytes.buffer;\n    var data = ByteData.view(byteBuffer);\n    if (len == 1) {\n      result = data.getUint8(0);\n    }\n    if (len == 2) {\n      result = data.getInt16(0, Endian.big);\n    }\n    if (len == 4) {\n      result = data.getInt32(0, Endian.big);\n    }\n    if (len == 8) {\n      result = data.getInt64(0, Endian.big);\n    }\n    position += len;\n    return result;\n  }\n\n  /// 从当前流中读取指定长度的字节数组，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// 返回字节数组\n  Uint8List readBytes(int len) {\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    position += len;\n    return bytes;\n  }\n\n  /// 从当前流中读取指定长度的字节浮点数，并使流的当前位置提升指定长度。\n  /// [len] 指定长度\n  /// len=4为float,8为double。dart中统一为double类型\n  /// 返回浮点数\n  double readFloat(int len) {\n    var result = 0.0;\n    var bytes =\n        Uint8List.fromList(buffer.getRange(position, position + len).toList());\n    var byteBuffer = bytes.buffer;\n    var data = ByteData.view(byteBuffer);\n    if (len == 4) {\n      result = data.getFloat32(0, Endian.big);\n    }\n    if (len == 8) {\n      result = data.getFloat64(0, Endian.big);\n    }\n    position += len;\n    return result;\n  }\n}\n\nclass TarsInputStream {\n  late BinaryReader br;\n\n  TarsInputStream(Uint8List? bytes, {int pos = 0}) {\n    if (bytes != null) {\n      br = BinaryReader(bytes);\n      br.position = pos;\n    }\n  }\n\n  void wrap(Uint8List bytes, {int pos = 0}) {\n    br = BinaryReader(bytes);\n    br.position = pos;\n  }\n\n  static int readBinaryReaderHead(HeadData hd, BinaryReader bb) {\n    if (bb.position >= bb.length) {\n      throw TarsDecodeException('read file to end');\n    }\n    var b = bb.read();\n    hd.type = (b & 15);\n    hd.tag = ((b & (15 << 4)) >> 4);\n    if (hd.tag == 15) {\n      hd.tag = bb.read();\n      return 2;\n    }\n    return 1;\n  }\n\n  int readHead(HeadData hd) {\n    return readBinaryReaderHead(hd, br);\n  }\n\n  int peakHead(HeadData hd) {\n    var curPos = br.position;\n    var len = readHead(hd);\n    br.position = curPos;\n    return len;\n  }\n\n  void skip(int len) {\n    br.position += len;\n  }\n\n  bool skipToTag(int tag) {\n    try {\n      var hd = HeadData();\n      while (true) {\n        var len = peakHead(hd);\n        if (tag <= hd.tag || hd.type == TarsStructType.STRUCT_END.index) {\n          return tag == hd.tag;\n        }\n\n        skip(len);\n        skipFieldWithType(hd.type);\n      }\n    } catch (e) {\n      if (e is TarsDecodeException) {\n        print(e);\n      }\n      print(e);\n    }\n    return false;\n  }\n\n  // 跳到当前结构的结束位置\n  void skipToStructEnd() {\n    var hd = HeadData();\n    do {\n      readHead(hd);\n      skipFieldWithType(hd.type);\n    } while (hd.type != TarsStructType.STRUCT_END.index);\n  }\n\n  // 跳过一个字段\n  void skipField() {\n    var hd = HeadData();\n    readHead(hd);\n    skipFieldWithType(hd.type);\n  }\n\n  void skipFieldWithType(int type) {\n    var t = TarsStructType.values[type];\n    switch (t) {\n      case TarsStructType.BYTE:\n        skip(1);\n        break;\n      case TarsStructType.SHORT:\n        skip(2);\n        break;\n      case TarsStructType.INT:\n        skip(4);\n        break;\n      case TarsStructType.LONG:\n        skip(8);\n        break;\n      case TarsStructType.FLOAT:\n        skip(4);\n        break;\n      case TarsStructType.DOUBLE:\n        skip(8);\n        break;\n      case TarsStructType.STRING1:\n        {\n          var len = br.read();\n          if (len < 0) {\n            len += 256;\n          }\n          skip(len);\n          break;\n        }\n      case TarsStructType.STRING4:\n        {\n          skip(br.readInt(4));\n          break;\n        }\n      case TarsStructType.MAP:\n        {\n          var size = readInt(0, true);\n          for (var i = 0; i < size * 2; ++i) {\n            skipField();\n          }\n          break;\n        }\n      case TarsStructType.LIST:\n        {\n          var size = readInt(0, true);\n          for (var i = 0; i < size; ++i) {\n            skipField();\n          }\n          break;\n        }\n      case TarsStructType.SIMPLE_LIST:\n        {\n          var hd = HeadData();\n          readHead(hd);\n          if (hd.type != TarsStructType.BYTE.index) {\n            throw TarsDecodeException(\n                'skipField with invalid type, type value: $type,${hd.type}');\n          }\n          var size = readInt(0, true);\n          skip(size);\n          break;\n        }\n      case TarsStructType.STRUCT_BEGIN:\n        skipToStructEnd();\n        break;\n      case TarsStructType.STRUCT_END:\n      case TarsStructType.ZERO_TAG:\n        break;\n    }\n  }\n\n  dynamic read<T>(dynamic data, int tag, bool isRequire) {\n    if (data is int || data == int) {\n      data = readInt(tag, isRequire);\n    } else if (data is double || data == double) {\n      data = readFloat(tag, isRequire);\n    } else if (data is bool || data == bool) {\n      data = readBool(tag, isRequire);\n    } else if (data is Uint8List || data == Uint8List) {\n      data = readBytes(tag, isRequire);\n    } else if (data is String || data == String) {\n      data = readString(tag, isRequire);\n    } else if (data is List || data == List) {\n      data = readList<T>(data, tag, isRequire);\n    } else if (data is Map || data == Map) {\n      data = readMap(data, tag, isRequire);\n    } else if (data is TarsStruct || data == TarsStruct) {\n      data = readTarsStruct(data, tag, isRequire);\n    } else {\n      throw TarsDecodeException('type:${data.runtimeType} not supported.');\n    }\n    return data;\n  }\n\n  /// 读取整数\n  /// 对应Tars类型：int1、int2、int4、int8\n  int readInt(int tag, bool isRequire) {\n    var n = 0;\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      switch (t) {\n        case TarsStructType.ZERO_TAG:\n          n = 0;\n          break;\n        case TarsStructType.BYTE:\n          n = br.readInt(1);\n          break;\n        case TarsStructType.SHORT:\n          n = br.readInt(2);\n          break;\n        case TarsStructType.INT:\n          n = br.readInt(4);\n          break;\n        case TarsStructType.LONG:\n          n = br.readInt(8);\n          break;\n        default:\n          throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return n;\n  }\n\n  /// 读取bool\n  /// 对应Tars类型：int1\n  bool readBool(int tag, bool isRequire) {\n    return readInt(tag, isRequire) != 0;\n  }\n\n  /// 读取单字char\n  /// 对应Tars类型：int\n  String readChar(int tag, bool isRequire) {\n    var char = readInt(tag, isRequire);\n    return String.fromCharCode(char);\n  }\n\n  /// 读取字符串\n  /// 对应Tars类型：string1、string4\n  String readString(int tag, bool isRequire) {\n    var n = '';\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      switch (t) {\n        case TarsStructType.STRING1:\n          n = _readString1();\n          break;\n        case TarsStructType.STRING4:\n          n = _readString4();\n          break;\n\n        default:\n          throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return n;\n  }\n\n  String _readString1() {\n    var len = 0;\n    len = br.readInt(1);\n    if (len < 0) {\n      len += 256;\n    }\n\n    var ss = br.readBytes(len);\n\n    return utf8.decode(ss);\n  }\n\n  String _readString4() {\n    var len = 0;\n    len = br.readInt(4);\n    if (len > TarsStruct.TARS_MAX_STRING_LENGTH || len < 0) {\n      throw TarsDecodeException('string too long: $len');\n    }\n\n    var ss = br.readBytes(len);\n\n    return utf8.decode(ss);\n  }\n\n  /// 读取浮点数\n  /// 对应Tars类型：double、float\n  double readFloat(int tag, bool isRequire) {\n    var n = 0.0;\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      switch (t) {\n        case TarsStructType.ZERO_TAG:\n          n = 0;\n          break;\n        case TarsStructType.FLOAT:\n          {\n            n = br.readFloat(4);\n          }\n          break;\n        case TarsStructType.DOUBLE:\n          {\n            n = br.readFloat(8);\n          }\n          break;\n        default:\n          throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return n;\n  }\n\n  /// 读取byte[]\n  /// 对应Tars类型：SimpleList\n  Uint8List readBytes(int tag, bool isRequire) {\n    var lr = Uint8List(0);\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      switch (t) {\n        case TarsStructType.SIMPLE_LIST:\n          {\n            var hh = HeadData();\n            readHead(hh);\n            if (hh.type != TarsStructType.BYTE.index) {\n              throw TarsDecodeException(\n                  'type mismatch, tag: $tag,type:${hd.type},${hh.type}');\n            }\n            var size = readInt(0, true);\n            if (size < 0) {\n              throw TarsDecodeException(\n                  'invalid size, tag: $tag, type: ${hd.type}, ${hh.type}  size:$size');\n            }\n\n            lr = Uint8List(size);\n            try {\n              lr = br.readBytes(size);\n            } catch (e) {\n              //QTrace.Trace(e.Message);\n              print(e);\n              return Uint8List(0);\n            }\n          }\n          break;\n        case TarsStructType.LIST:\n          {\n            var size = readInt(0, true);\n            if (size < 0) throw TarsDecodeException('size invalid: $size');\n            lr = Uint8List(size);\n            for (var i = 0; i < size; ++i) {\n              lr[i] = readInt(0, true);\n            }\n          }\n          break;\n        default:\n          throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return lr;\n  }\n\n  /// 读取Map\n  /// 需要指定键、值的类型\n  /// 对应Tars类型：Map\n  Map<K, V> readMap<K, V>(Map<K, V> data, int tag, bool isRequire) {\n    Iterable<MapEntry<K, V>> it = data.entries;\n    MapEntry<K, V> en = it.first;\n    K k = en.key;\n    V v = en.value;\n    Map<K, V> map = <K, V>{};\n\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      if (t == TarsStructType.MAP) {\n        var size = readInt(0, true);\n        if (size < 0) {\n          throw TarsDecodeException('size invalid:$size');\n        }\n        for (var i = 0; i < size; ++i) {\n          var mk = read(k, 0, true);\n          var mv = read(v, 1, true);\n          if (mk != null) {\n            if (map.containsKey(mk)) {\n              map[mk] = mv;\n            } else {\n              map.addAll({mk: mv});\n            }\n          }\n        }\n      } else {\n        throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return map;\n  }\n\n  /// 读取 k list<V> 结构 Map\n  /// 需要指定键、list值的类型\n  /// 对应Tars类型：Map\n  Map<K, List<V>> readMapList<K, V>(\n      Map<K, List<V>> source, int tag, bool isRequire) {\n    var map = <K, List<V>>{};\n    Iterable<MapEntry<K, List<V>>> it = source.entries;\n    MapEntry<K, List<V>> en = it.first;\n    K k = en.key;\n    List<V> v = en.value;\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      if (t == TarsStructType.MAP) {\n        var size = readInt(0, true);\n        if (size < 0) {\n          throw TarsDecodeException('size invalid:$size');\n        }\n        for (var i = 0; i < size; ++i) {\n          var mk = read<K>(k, 0, true);\n          var mv = read<V>(v, 1, true);\n          if (mk != null) {\n            if (map.containsKey(mk)) {\n              map[mk] = mv;\n            } else {\n              map.addAll({mk: mv});\n            }\n          }\n        }\n      } else {\n        throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return map;\n  }\n\n  /// 读取 k map<V2,V2> 结构 Map\n  /// 需要指定键、子Map键值的类型\n  /// 对应Tars类型：Map\n  Map<K, Map<K2, V2>> readMapMap<K, K2, V2>(\n      Map<K, Map<K2, V2>> source, int tag, bool isRequire) {\n    var map = <K, Map<K2, V2>>{};\n    Iterable<MapEntry<K, Map<K2, V2>>> it = source.entries;\n    MapEntry<K, Map<K2, V2>> en = it.first;\n    K k = en.key;\n    Map<K2, V2> v = en.value;\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      if (t == TarsStructType.MAP) {\n        var size = readInt(0, true);\n        if (size < 0) {\n          throw TarsDecodeException('size invalid:$size');\n        }\n        for (var i = 0; i < size; ++i) {\n          var mk = read<K>(k, 0, true);\n          var mv = readMap<K2, V2>(v, 1, true);\n          if (mk != null) {\n            if (map.containsKey(mk)) {\n              map[mk] = mv;\n            } else {\n              map.addAll({mk: mv});\n            }\n          }\n        }\n      } else {\n        throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return map;\n  }\n\n  /// 读取列表\n  /// 对应Tars类型：List\n  List<T> readList<T>(dynamic data, int tag, bool isRequire) {\n    var ls = <T>[];\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      switch (t) {\n        case TarsStructType.LIST:\n          {\n            var size = readInt(0, true);\n            if (size < 0) throw TarsDecodeException('size invalid: $size');\n            ls = <T>[];\n            for (var i = 0; i < size; ++i) {\n              ls.add(read(data[0], 0, true));\n            }\n          }\n          break;\n        default:\n          throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return ls;\n  }\n\n  /// 读取自定义结构\n  /// 对应Tars类型：TarsStruct\n  TarsStruct readTarsStruct(TarsStruct ts, int tag, bool isRequire) {\n    if (skipToTag(tag)) {\n      var hd = HeadData();\n      readHead(hd);\n      var t = TarsStructType.values[hd.type];\n      if (t == TarsStructType.STRUCT_BEGIN) {\n        var copyTs = ts.deepCopy() as TarsStruct;\n        copyTs.readFrom(this);\n        skipToStructEnd();\n        return copyTs;\n      } else {\n        throw TarsDecodeException('type mismatch.');\n      }\n    } else if (isRequire) {\n      throw TarsDecodeException('require field not exist.');\n    }\n    return ts;\n  }\n\n  String sServerEncoding = \"UTF-8\";\n\n  int setServerEncoding(String se) {\n    sServerEncoding = se;\n    return 0;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_output_stream.dart",
    "content": "import 'dart:convert';\nimport 'dart:typed_data';\n\nimport './tars_encode_exception.dart';\nimport './tars_struct.dart';\n\nclass BinaryWriter {\n  List<int> buffer;\n  int position = 0;\n\n  BinaryWriter(this.buffer);\n\n  int get length => buffer.length;\n\n  void writeBytes(Uint8List list) {\n    buffer.addAll(list);\n    position += list.length;\n  }\n\n  void writeInt(int value, int len) {\n    var b = Uint8List(len).buffer;\n    var bytes = ByteData.view(b);\n    if (len == 1) {\n      //写入byte\n      bytes.setUint8(0, value.toUnsigned(8));\n    }\n    if (len == 2) {\n      bytes.setInt16(0, value, Endian.big);\n    }\n    if (len == 4) {\n      bytes.setInt32(0, value, Endian.big);\n    }\n    if (len == 8) {\n      bytes.setInt64(0, value, Endian.big);\n    }\n\n    buffer.addAll(bytes.buffer.asUint8List());\n    position += len;\n  }\n\n  void writeDouble(double value, int len) {\n    var b = Uint8List(len).buffer;\n    var bytes = ByteData.view(b);\n\n    if (len == 4) {\n      bytes.setFloat32(0, value, Endian.big);\n    }\n    if (len == 8) {\n      bytes.setFloat64(0, value, Endian.big);\n    }\n\n    buffer.addAll(bytes.buffer.asUint8List());\n    position += len;\n  }\n}\n\nclass TarsOutputStream {\n  late BinaryWriter bw;\n\n  TarsOutputStream({Uint8List? ls}) {\n    if (ls != null) {\n      bw = BinaryWriter(ls);\n    } else {\n      bw = BinaryWriter([]);\n    }\n  }\n\n  void writeHead(int type, int tag) {\n    if (tag < 15) {\n      var b = ((tag << 4) | type);\n      try {\n        bw.writeInt(b, 1);\n      } catch (e) {\n        print(e.toString());\n      }\n    } else if (tag < 256) {\n      try {\n        var b = ((15 << 4) | type);\n        {\n          bw.writeInt(b, 1);\n          bw.writeInt(tag, 1);\n        }\n      } catch (e) {\n        print('${toString()} writeHead: $e');\n      }\n    } else {\n      throw TarsEncodeException('tag is too large: $tag');\n    }\n  }\n\n  void write(dynamic data, int tag) {\n    if (data is int || data == int) {\n      writeInt(data, tag);\n    } else if (data is double || data == double) {\n      writeDouble(data, tag);\n    } else if (data is bool || data == bool) {\n      writeBool(data, tag);\n    } else if (data is Uint8List || data == Uint8List) {\n      writeUint8List(data, tag);\n    } else if (data is String || data == String) {\n      writeString(data, tag);\n    } else if (data is List || data == List) {\n      writeList(data, tag);\n    } else if (data is Map || data == Map) {\n      writeMap(data, tag);\n    } else if (data is TarsStruct || data == TarsStruct) {\n      writeTarsStruct(data, tag);\n    } else {\n      throw TarsEncodeException('type:${data.runtimeType} not supported.');\n    }\n  }\n\n  /// 写入bool\n  /// 对应Tars类型：int1\n  void writeBool(bool b, int tag) {\n    writeByte(b ? 1 : 0, tag);\n  }\n\n  /// 写入字节\n  /// 对应Tars类型：int1\n  void writeByte(int b, int tag) {\n    //紧跟1个字节整型数据\n    if (b == 0) {\n      writeHead(TarsStructType.ZERO_TAG.index, tag);\n    } else {\n      writeHead(TarsStructType.BYTE.index, tag);\n      try {\n        bw.writeInt(b, 1);\n      } catch (e) {\n        print(e);\n      }\n    }\n  }\n\n  /// 写入整数型\n  /// 对应Tars类型：int1、int2、int4、int8\n  void writeInt(int n, int tag) {\n    //写入byte\n    //紧跟1个字节整型数据\n    if (n >= -128 && n <= 127) {\n      writeByte(n, tag);\n      return;\n    }\n    //int16\n    //紧跟2个字节整型数据\n    if (n >= -32768 && n <= 32767) {\n      writeHead(TarsStructType.SHORT.index, tag);\n      bw.writeInt(n, 2);\n      return;\n    }\n    //int32\n    //紧跟4个字节整型数据\n    if (n >= -2147483648 && n <= 2147483647) {\n      writeHead(TarsStructType.INT.index, tag);\n      bw.writeInt(n, 4);\n      return;\n    }\n    //int64\n    //紧跟8个字节整型数据\n    if (n >= -9223372036854775808 && n <= 9223372036854775807) {\n      writeHead(TarsStructType.LONG.index, tag);\n      bw.writeInt(n, 8);\n      return;\n    }\n  }\n\n  /// 写入浮点数\n  /// 对应Tars类型：float\n  void writeFloat(double n, int tag) {\n    //紧跟4个字节浮点型数据\n    writeHead(TarsStructType.FLOAT.index, tag);\n    bw.writeDouble(n, 4);\n  }\n\n  /// 写入双精度浮点数(Double)\n  /// 对应Tars类型：double\n  void writeDouble(double n, int tag) {\n    //紧跟8个字节浮点型数据\n    writeHead(TarsStructType.DOUBLE.index, tag);\n    bw.writeDouble(n, 8);\n  }\n\n  /// 写入字符串\n  /// 对应Tars类型：string1、string4\n  void writeString(String s, int tag) {\n    //string1:紧跟1个字节长度，再跟内容\n    //string4:紧跟4个字节长度，再跟内容\n    var bytes = utf8.encode(s);\n    if (bytes.isEmpty) {\n      writeHead(TarsStructType.STRING1.index, tag);\n      bw.writeInt(0, 1);\n      return;\n    }\n    if (bytes.length > 255) {\n      writeHead(TarsStructType.STRING4.index, tag);\n      bw.writeInt(bytes.length, 4);\n      bw.writeBytes(Uint8List.fromList(bytes));\n    } else {\n      writeHead(TarsStructType.STRING1.index, tag);\n      bw.writeInt(bytes.length, 1);\n      bw.writeBytes(Uint8List.fromList(bytes));\n    }\n  }\n\n  /// 写入byte[]\n  /// 对应Tars类型：SimpleList\n  void writeUint8List(Uint8List ls, int tag) {\n    //简单列表（目前用在byte数组），紧跟一个类型字段（目前只支持byte），紧跟一个整型数据表示长度，再跟byte数据\n    writeHead(TarsStructType.SIMPLE_LIST.index, tag);\n    writeHead(TarsStructType.BYTE.index, 0);\n    writeInt(ls.length, 0);\n    bw.writeBytes(ls);\n  }\n\n  /// 写入Map\n  /// 对应Tars类型：Map\n  void writeMap<K, V>(Map<K, V> map, int tag) {\n    //紧跟一个整型数据表示Map的大小，再跟[key, value]对列表\n    writeHead(TarsStructType.MAP.index, tag);\n    writeInt(map.length, 0);\n    for (var item in map.keys) {\n      write(item, 0);\n      write(map[item], 1);\n    }\n  }\n\n  /// 写入列表\n  /// 对应Tars类型：List\n  void writeList(List ls, int tag) {\n    //紧跟一个整型数据表示List的大小，再跟元素列表\n    writeHead(TarsStructType.LIST.index, tag);\n    write(ls.length, 0);\n    for (var item in ls) {\n      write(item, 0);\n    }\n  }\n\n  /// 写入自定义结构\n  /// 对应Tars类型：TarsStruct\n  void writeTarsStruct(TarsStruct o, int tag) {\n    writeHead(TarsStructType.STRUCT_BEGIN.index, tag);\n    o.writeTo(this);\n    writeHead(TarsStructType.STRUCT_END.index, 0);\n  }\n\n  Uint8List toUint8List() {\n    return Uint8List.fromList(bw.buffer);\n  }\n\n  String sServerEncoding = \"UTF-8\";\n\n  int setServerEncoding(String se) {\n    sServerEncoding = se;\n    return 0;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/codec/tars_struct.dart",
    "content": "// ignore_for_file: non_constant_identifier_names, constant_identifier_names, no_leading_underscores_for_local_identifiers\n\nimport 'dart:typed_data';\n\nimport './tars_input_stream.dart';\nimport './tars_output_stream.dart';\nimport './tars_deep_copyable.dart';\n\nenum TarsStructType {\n  BYTE,\n  SHORT,\n  INT,\n  LONG,\n  FLOAT,\n  DOUBLE,\n  STRING1,\n  STRING4,\n  MAP,\n  LIST,\n  STRUCT_BEGIN,\n  STRUCT_END,\n  ZERO_TAG,\n  SIMPLE_LIST,\n}\n\nabstract class TarsStruct extends DeepCopyable {\n  static int TARS_MAX_STRING_LENGTH = 100 * 1024 * 1024;\n  void writeTo(TarsOutputStream _os);\n  void readFrom(TarsInputStream _is);\n  void displayAsString(StringBuffer sb, int level);\n\n  Uint8List toByteArray() {\n    TarsOutputStream os = TarsOutputStream();\n    writeTo(os);\n    return os.toUint8List();\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/net/base_tars_http.dart",
    "content": "import 'dart:io';\nimport 'dart:typed_data';\n\nimport 'package:dio/dio.dart';\nimport 'package:logger/logger.dart';\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/tup/const.dart';\nimport 'package:tars_dart/tars/tup/tars_uni_packet.dart';\nimport 'package:tars_dart/tars/tup/tup_response.dart';\nimport 'package:tars_dart/tars/tup/tup_result_exception.dart';\n\n//tup网络请求封装\n//注意:只支持 PACKET_TYPE_TUP3 = 3 类型的封包\nclass BaseTarsHttp {\n  final String baseUrl;\n  final String path;\n  final String servantName;\n  final Map<String, String> headers;\n\n  var timeOut = 60000;\n  var debugLog = false;\n  late final Dio dio;\n  final logger = Logger();\n\n  BaseTarsHttp(\n    this.baseUrl,\n    this.servantName, {\n    this.path = \"\",\n    this.timeOut = 60000,\n    this.debugLog = false,\n    this.headers = const {},\n  }) {\n    dio = Dio(BaseOptions(\n        connectTimeout: Duration(seconds: timeOut),\n        baseUrl: baseUrl,\n        responseType: ResponseType.bytes,\n        headers: {\n          HttpHeaders.contentTypeHeader: \"application/x-wup\",\n          ...headers\n        }));\n    if (debugLog) {\n      dio.interceptors.add(LogInterceptor(responseBody: false)); //开启请求日志\n    }\n  }\n\n  //发送http请求,不返回状态码,异常状态码直接抛出异常TupResultException\n  Future<RSP> tupRequest<REQ, RSP>(\n      String methodName, REQ tReq, RSP tRsp) async {\n    TupResponse<RSP> response =\n        await tupRequestWithRspCode(methodName, tReq, tRsp);\n    if (response.code == 0) {\n      return response.response!;\n    } else {\n      logger.e(\"tupDecode decode error:${response.code}\");\n      throw TupResultException(response.code);\n    }\n  }\n\n  //发送http请求,返回状态码及response\n  Future<TupResponse<RSP>> tupRequestWithRspCode<REQ, RSP>(\n      String methodName, REQ tReq, RSP tRsp) async {\n    final data = buildRequest(methodName, tReq);\n    dio.options.headers[HttpHeaders.contentLengthHeader] = data.lengthInBytes;\n    logger.d(\"send tupRequest, methodName:$methodName\");\n    final result = await dio.post<List<int>>(\n      path,\n      data: Stream.fromIterable(data.map((e) => [e])),\n    );\n    final value = result.data;\n    return tupResponseDecode(methodName, value!, tRsp);\n  }\n\n  //发送无response http请求,返回状态码\n  Future<TupResponse<void>> tupRequestWithRspCodeNoRsp<REQ>(\n      String methodName, REQ tReq) async {\n    final data = buildRequest(methodName, tReq);\n    dio.options.headers[HttpHeaders.contentLengthHeader] = data.lengthInBytes;\n    logger.d(\"send tupRequestNoRsp, methodName:$methodName\");\n    final result = await dio.post<List<int>>(\n      path,\n      data: Stream.fromIterable(data.map((e) => [e])),\n    );\n    final value = result.data;\n    return tupEmptyResponseDecode(methodName, value!);\n  }\n\n  //发送无response http请求,不返回状态码,异常状态码直接抛出异常TupResultException\n  Future<void> tupRequestNoRsp<REQ>(String methodName, REQ tReq) async {\n    TupResponse<void> response =\n        await tupRequestWithRspCodeNoRsp(methodName, tReq);\n    if (response.code == 0) {\n      return;\n    } else {\n      logger.e(\"tupDecode decode error:${response.code}\");\n      throw TupResultException(response.code);\n    }\n  }\n\n  //封包\n  Uint8List buildRequest<REQ>(String methodName, REQ tReq) {\n    TarsUniPacket encodePack = TarsUniPacket();\n    encodePack.requestId = 0;\n    encodePack.setTarsVersion(Const.PACKET_TYPE_TUP3);\n    encodePack.setTarsPacketType(Const.PACKET_TYPE_TARSNORMAL);\n    encodePack.servantName = servantName;\n    encodePack.funcName = methodName;\n    encodePack.put(\"tReq\", tReq);\n    Uint8List bytes = encodePack.encode();\n    return bytes;\n  }\n\n  //有response解包\n  TupResponse<RSP> tupResponseDecode<RSP>(\n      String methodName, List<int> list, RSP tRsp) {\n    var bytes = Uint8List.fromList(list);\n    BinaryReader br = BinaryReader(bytes);\n    int size = br.readInt(4);\n    logger.d(\"size:$size\");\n    TarsUniPacket respPack = TarsUniPacket();\n    respPack.decode(bytes);\n    var code = respPack.get(\"\", 0);\n    logger.d(\"get tupRequest response, methodName:$methodName, code:$code\");\n    RSP rsp = respPack.get<RSP>(\"tRsp\", tRsp);\n    return TupResponse<RSP>(code: code, response: rsp);\n  }\n\n  //无response解包\n  TupResponse<void> tupEmptyResponseDecode(String methodName, List<int> list) {\n    var bytes = Uint8List.fromList(list);\n    BinaryReader br = BinaryReader(bytes);\n    int size = br.readInt(4);\n    logger.d(\"size:$size\");\n    TarsUniPacket respPack = TarsUniPacket();\n    respPack.decode(bytes);\n    var code = respPack.get(\"\", 0);\n    logger.d(\"get tupRequest response, methodName:$methodName, code:$code\");\n    return TupResponse<void>(code: code);\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/basic_class_type_util.dart",
    "content": "class BasicClassTypeUtil {\n  static String dart2UniType(String type, dynamic obj) {\n    if (type == 'String') {\n      return 'string';\n    }\n    if (type.contains('List')) {\n      return 'list';\n    }\n    if (type.contains('Map')) {\n      return 'map';\n    }\n    if (type == 'bool') {\n      return 'bool';\n    }\n    // 如果是int,需要检查short/ushort/int32/uint32\n    if (type == 'int') {\n      if (obj is int) {\n        if (obj >= -32768 && obj <= 32767) {\n          return 'short';\n        }\n        if (obj >= 0 && obj <= 65535) {\n          return 'ushort';\n        }\n        if (obj >= -2147483648 && obj <= 2147483647) {\n          return 'int32';\n        }\n        if (obj >= 0 && obj <= 4294967295) {\n          return 'uint32';\n        }\n      } else {\n        return 'int32';\n      }\n    }\n    // 检查int64/uint64\n    if (type == BigInt.one.runtimeType.toString()) {\n      if (obj is BigInt) {\n        if (obj >= BigInt.from(-9223372036854775808) &&\n            obj <= BigInt.from(9223372036854775807)) {\n          return 'int64';\n        }\n        if (obj >= BigInt.zero && obj <= BigInt.parse('18446744073709551615')) {\n          return 'uint64';\n        }\n      }\n      return 'int64';\n    }\n\n    if (type == 'double') {\n      return 'double';\n    }\n\n    return type;\n  }\n\n  /// 将嵌套的类型转成字符串\n  static String transTypeList(List<String> listType) {\n    var sb = StringBuffer();\n\n    for (var i = 0; i < listType.length; i++) {\n      listType[i] = dart2UniType(listType[i], null);\n    }\n\n    listType = listType.reversed.toList();\n\n    for (var i = 0; i < listType.length; i++) {\n      var type = listType[i];\n\n      if (type == 'Null') {\n        continue;\n      }\n\n      if (type == 'list') {\n        listType[i - 1] = '<${listType[i - 1]}';\n        listType[0] = '${listType[0]}>';\n      } else if (type == 'map') {\n        listType[i - 1] = '<${listType[i - 1]},';\n        listType[0] = '${listType[0]}>';\n      } else if (type == 'Array') {\n        listType[i - 1] = '<${listType[i - 1]}';\n        listType[0] = '${listType[0]}>';\n      }\n    }\n    listType = listType.reversed.toList();\n\n    for (var s in listType) {\n      sb.write(s);\n    }\n    return sb.toString();\n  }\n\n  static Object? createObject(Type type) {\n    if (type == String) {\n      return '';\n    }\n    if (type == int) {\n      return 0;\n    }\n    if (type == double) {\n      return 0.0;\n    }\n    if (type == bool) {\n      return false;\n    }\n    if (type == BigInt) {\n      return BigInt.zero;\n    }\n    if (type == List) {\n      return <dynamic>[];\n    }\n    if (type == Map) {\n      return <dynamic, dynamic>{};\n    }\n    return null;\n  }\n\n  static T createObjectT<T>() {\n    if (T == String) {\n      return '' as T;\n    }\n    if (T == int) {\n      return 0 as T;\n    }\n    if (T == double) {\n      return 0.0 as T;\n    }\n    if (T == bool) {\n      return false as T;\n    }\n    if (T == BigInt) {\n      return BigInt.zero as T;\n    }\n    if (T == List) {\n      return <dynamic>[] as T;\n    }\n    if (T == Map) {\n      return <dynamic, dynamic>{} as T;\n    }\n    return null as T;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/const.dart",
    "content": "// ignore_for_file: non_constant_identifier_names\n\nclass Const {\n  static String STATUS_GRID_KEY = \"STATUS_GRID_KEY\";\n  static String STATUS_DYED_KEY = \"STATUS_DYED_KEY\";\n  static String STATUS_GRID_CODE = \"STATUS_GRID_CODE\";\n  static String STATUS_SAMPLE_KEY = \"STATUS_SAMPLE_KEY\";\n  static String STATUS_RESULT_CODE = \"STATUS_RESULT_CODE\";\n  static String STATUS_RESULT_DESC = \"STATUS_RESULT_DESC\";\n\n  static int INVALID_HASH_CODE = -1;\n  static int INVALID_GRID_CODE = -1;\n\n  static int PACKET_TYPE_TARSNORMAL = 0;\n  static int PACKET_TYPE_TARSONEWAY = 1;\n  static int PACKET_TYPE_TUP = 2;\n  static int PACKET_TYPE_TUP3 = 3;\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/object_create_exception.dart",
    "content": "class ObjectCreateException implements Exception {\n  // ignore: unused_field\n  late String _message;\n\n  ObjectCreateException(String message) {\n    _message = message;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/request_packet.dart",
    "content": "// ignore_for_file: non_constant_identifier_names, avoid_renaming_method_parameters, no_leading_underscores_for_local_identifiers\n\nimport 'dart:core';\nimport 'dart:typed_data';\nimport '/tars/codec/tars_input_stream.dart';\nimport '/tars/codec/tars_output_stream.dart';\nimport '/tars/codec/tars_struct.dart';\nimport '/tars/codec/tars_displayer.dart';\nimport '/tars/codec/tars_deep_copyable.dart';\n\nclass RequestPacket extends TarsStruct {\n  String className() {\n    return \"RequestPacket\";\n  }\n\n  int iVersion = 0;\n\n  int cPacketType = 0;\n\n  int iMessageType = 0;\n\n  int iRequestId = 0;\n\n  String sServantName = \"\";\n\n  String sFuncName = \"\";\n\n  Uint8List? sBuffer;\n\n  int iTimeout = 0;\n\n  Map<String, String>? context;\n\n  Map<String, String>? status;\n\n  RequestPacket(\n      {this.iVersion = 0,\n      this.cPacketType = 0,\n      this.iMessageType = 0,\n      this.iRequestId = 0,\n      this.sServantName = \"\",\n      this.sFuncName = \"\",\n      this.sBuffer,\n      this.iTimeout = 0,\n      this.context,\n      this.status});\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    _os.write(iVersion, 1);\n    _os.write(cPacketType, 2);\n    _os.write(iMessageType, 3);\n    _os.write(iRequestId, 4);\n    _os.write(sServantName, 5);\n    _os.write(sFuncName, 6);\n    _os.write(sBuffer, 7);\n    _os.write(iTimeout, 8);\n    _os.write(context, 9);\n    _os.write(status, 10);\n  }\n\n  static Uint8List cache_sBuffer = Uint8List.fromList([0x0]);\n  static Map<String, String> cache_context = {\"\": \"\"};\n  static Map<String, String> cache_status = {\"\": \"\"};\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    iVersion = _is.read<int>(iVersion, 1, false);\n    cPacketType = _is.read<int>(cPacketType, 2, false);\n    iMessageType = _is.read<int>(iMessageType, 3, false);\n    iRequestId = _is.read<int>(iRequestId, 4, false);\n    sServantName = _is.read<String>(sServantName, 5, false);\n    sFuncName = _is.read<String>(sFuncName, 6, false);\n    sBuffer = _is.read<int>(cache_sBuffer, 7, false);\n    iTimeout = _is.read<int>(iTimeout, 8, false);\n    context = _is.readMap<String, String>(cache_context, 9, false);\n    status = _is.readMap<String, String>(cache_status, 10, false);\n  }\n\n  @override\n  void displayAsString(StringBuffer _os, int _level) {\n    TarsDisplayer _ds = TarsDisplayer(_os, level: _level);\n    _ds.display(iVersion, \"iVersion\");\n    _ds.display(cPacketType, \"cPacketType\");\n    _ds.display(iMessageType, \"iMessageType\");\n    _ds.display(iRequestId, \"iRequestId\");\n    _ds.display(sServantName, \"sServantName\");\n    _ds.display(sFuncName, \"sFuncName\");\n    _ds.display(sBuffer, \"sBuffer\");\n    _ds.display(iTimeout, \"iTimeout\");\n    _ds.display(context, \"context\");\n    _ds.display(status, \"status\");\n  }\n\n  @override\n  Object deepCopy() {\n    var o = RequestPacket();\n    o.iVersion = iVersion;\n    o.cPacketType = cPacketType;\n    o.iMessageType = iMessageType;\n    o.iRequestId = iRequestId;\n    o.sServantName = sServantName;\n    o.sFuncName = sFuncName;\n    o.sBuffer = sBuffer;\n    o.iTimeout = iTimeout;\n    if (null != context) {\n      o.context = mapDeepCopy<String, String>(context!);\n    }\n    if (null != status) {\n      o.status = mapDeepCopy<String, String>(status!);\n    }\n    return o;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/tars_uni_packet.dart",
    "content": "import 'dart:typed_data';\nimport 'uni_packet.dart';\nimport 'const.dart';\n\nclass TarsUniPacket extends UniPacket {\n  TarsUniPacket() {\n    package.iVersion = Const.PACKET_TYPE_TUP3;\n    package.cPacketType = Const.PACKET_TYPE_TARSNORMAL;\n    package.iMessageType = 0;\n    package.iTimeout = 0;\n    package.sBuffer = Uint8List.fromList([0x0]);\n    package.context = <String, String>{};\n    package.status = <String, String>{};\n  }\n\n  /// 设置协议版本\n  void setTarsVersion(int version) {\n    setVersion(version);\n  }\n\n  /// 设置调用类型\n  void setTarsPacketType(int packetType) {\n    package.cPacketType = packetType;\n  }\n\n  /// 设置消息类型\n  void setTarsMessageType(int messageType) {\n    package.iMessageType = messageType;\n  }\n\n  /// 设置超时时间\n  void setTarsTimeout(int timeout) {\n    package.iTimeout = timeout;\n  }\n\n  /// 设置参数编码内容\n  void setTarsBuffer(Uint8List buffer) {\n    package.sBuffer = buffer;\n  }\n\n  /// 设置上下文\n  void setTarsContext(Map<String, String> context) {\n    package.context = context;\n  }\n\n  /// 设置特殊消息的状态值\n  void setTarsStatus(Map<String, String> status) {\n    package.status = status;\n  }\n\n  /// 获取协议版本\n  int getTarsVersion() {\n    return package.iVersion;\n  }\n\n  /// 获取调用类型\n  int getTarsPacketType() {\n    return package.cPacketType;\n  }\n\n  /// 获取消息类型\n  int getTarsMessageType() {\n    return package.iMessageType;\n  }\n\n  /// 获取超时时间\n  int getTarsTimeout() {\n    return package.iTimeout;\n  }\n\n  /// 获取参数编码后内容\n  Uint8List? getTarsBuffer() {\n    return package.sBuffer;\n  }\n\n  /// 获取上下文信息\n  Map<String, String>? getTarsContext() {\n    return package.context;\n  }\n\n  /// 获取特殊消息的状态值\n  Map<String, String>? getTarsStatus() {\n    return package.status;\n  }\n\n  /// 获取调用tars的返回值\n  int getTarsResultCode() {\n    int result = 0;\n    try {\n      String? rcode = package.status?[Const.STATUS_RESULT_CODE];\n      result = (rcode != null ? int.tryParse(rcode) : 0)!;\n    } catch (e) {\n      print('getTarsResultCode exception: $e');\n      return 0;\n    }\n    return result;\n  }\n\n  /// 获取调用tars的返回描述\n  String getTarsResultDesc() {\n    String? rdesc = package.status?[Const.STATUS_RESULT_DESC];\n    String result = rdesc ?? \"\";\n    return result;\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/tup_response.dart",
    "content": "class TupResponse<T> {\n  int code = 0;\n  T? response;\n\n  TupResponse({this.code = 0, this.response});\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/tup_result_exception.dart",
    "content": "class TupResultException implements Exception {\n  late int code;\n  late String? message;\n\n  TupResultException(this.code, {this.message});\n\n  @override\n  String toString() {\n    return '{code: $code, message: $message}';\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/uni_attribute.dart",
    "content": "// ignore_for_file: no_leading_underscores_for_local_identifiers\n\nimport 'dart:core';\nimport 'dart:typed_data';\n\nimport 'package:tars_dart/tars/tup/basic_class_type_util.dart';\n\nimport '/tars/codec/tars_input_stream.dart';\nimport '/tars/codec/tars_output_stream.dart';\nimport '/tars/codec/tars_struct.dart';\nimport 'const.dart';\nimport 'object_create_exception.dart';\n\nclass UniAttribute extends TarsStruct {\n  /// 精简版tup，PACKET_TYPE_TUP3类型\n  Map<String, Uint8List> newData = {};\n\n  //PACKET_TYPE_TUP类型\n  Map<String, Map<String, Uint8List>> oldData = {};\n\n  /// 存储get后的数据 避免多次解析\n  Map<String, Object> cachedData = <String, Object>{};\n\n  int version = Const.PACKET_TYPE_TUP;\n  String encodeName = 'UTF-8';\n\n  final TarsInputStream _is = TarsInputStream(null);\n\n  /// 清除缓存的解析过的数据\n  void clearCacheData() {\n    cachedData.clear();\n  }\n\n  bool isEmpty() {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      return newData.isEmpty;\n    } else {\n      return oldData.isEmpty;\n    }\n  }\n\n  int get length {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      return newData.length;\n    } else {\n      return oldData.length;\n    }\n  }\n\n  bool containsKey(String key) {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      return newData.containsKey(key);\n    } else {\n      return oldData.containsKey(key);\n    }\n  }\n\n  /// 放入一个元素\n  /// @param <T>\n  /// @param name\n  /// @param t\n  void put<T>(String name, T t) {\n    if (name.isEmpty) {\n      throw ArgumentError(\"put key can not is null\");\n    }\n    if (t == null) {\n      throw ArgumentError(\"put value can not is null\");\n    }\n\n    TarsOutputStream _out = TarsOutputStream();\n    _out.setServerEncoding(encodeName);\n    _out.write(t, 0);\n    Uint8List sBuffer = _out.toUint8List();\n\n    if (version == Const.PACKET_TYPE_TUP3) {\n      cachedData.remove(name);\n\n      if (newData.containsKey(name)) {\n        newData[name] = sBuffer;\n      } else {\n        newData[name] = sBuffer;\n      }\n    } else {\n      var listType = <String>[];\n      checkObjectType(listType, t);\n      var className = BasicClassTypeUtil.transTypeList(listType);\n\n      var pair = <String, Uint8List>{};\n      pair[className] = sBuffer;\n      cachedData.remove(name);\n      oldData[name] = pair;\n    }\n  }\n\n  void checkObjectType(List<String> listType, dynamic o) {\n    if (o == null) {\n      throw Exception('object is null');\n    }\n\n    if (o is List) {\n      listType.add('list');\n      if (o.isNotEmpty) {\n        checkObjectType(listType, o[0]);\n      } else {\n        listType.add('?');\n      }\n    } else if (o is Map) {\n      listType.add('map');\n      if (o.isNotEmpty) {\n        var key = o.keys.first;\n        listType.add(\n            BasicClassTypeUtil.dart2UniType(key.runtimeType.toString(), key));\n        checkObjectType(listType, o[key]);\n      } else {\n        listType.add('?');\n        listType.add('?');\n        // throw ArgumentError(\"map cannot be empty\");\n      }\n    } else if (o is Iterable) {\n      listType.add('list');\n      // 如果是Iterable但不是List，可以处理其他类型的集合\n      var iterator = o.iterator;\n      if (iterator.moveNext()) {\n        checkObjectType(listType, iterator.current);\n      } else {\n        listType.add('?');\n      }\n    } else {\n      listType\n          .add(BasicClassTypeUtil.dart2UniType(o.runtimeType.toString(), o));\n    }\n  }\n\n  Object decodeData(Uint8List data, Object? proxy) {\n    _is.wrap(data);\n    _is.setServerEncoding(encodeName);\n    Object o = _is.read(proxy, 0, true);\n    return o;\n  }\n\n  /// 获取tup精简版本编码的数据,兼容旧版本tup\n  /// @param <T>\n  /// @param name\n  /// @param proxy\n  /// @return\n  /// @throws ObjectCreateException\n  T getByClass<T>(String name, T proxy) {\n    Object? obj;\n    if (version == Const.PACKET_TYPE_TUP3) {\n      if (!newData.containsKey(name)) {\n        return obj as T;\n      } else if (cachedData.containsKey(name)) {\n        obj = cachedData[name];\n        return obj as T;\n      } else {\n        try {\n          Uint8List data = newData[name] as Uint8List;\n          Object o = decodeData(data, proxy!);\n          saveDataCache(name, o);\n          return o as T;\n        } catch (ex) {\n          throw ObjectCreateException(ex.toString());\n        }\n      }\n    } else {\n      //兼容tup2\n      return get2<T>(name);\n    }\n  }\n\n  // 获取一个元素,只能用于tup版本2，如果待获取的数据为tup3，则抛异常\n  T get2<T>(String name, {T? proxy}) {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      throw Exception('data is not in tup2 format');\n    }\n\n    if (cachedData.containsKey(name)) {\n      return cachedData[name] as T;\n    }\n\n    if (!oldData.containsKey(name)) {\n      return null as T;\n    }\n\n    var data = oldData[name]!;\n    var className = data.keys.first;\n    var sBuffer = data[className]!;\n    var o = decodeData(sBuffer, proxy);\n    saveDataCache(name, o);\n    return o as T;\n  }\n\n  /// 获取一个元素,tup新旧版本都兼容\n  /// @param Name\n  /// @param DefaultObj\n  /// @return\n  /// @throws ObjectCreateException\n  T get<T>(String name, T defaultObj) {\n    try {\n      Object? result;\n      if (version == Const.PACKET_TYPE_TUP3) {\n        result = getByClass<T>(name, defaultObj);\n      } else {\n        //tup2\n        return get2(name, proxy: defaultObj);\n      }\n      if (result == null) {\n        return defaultObj;\n      }\n      return result as T;\n    } catch (ex) {\n      return defaultObj;\n    }\n  }\n\n  void saveDataCache(String name, Object o) {\n    cachedData[name] = o;\n  }\n\n  Uint8List encode() {\n    TarsOutputStream _os = TarsOutputStream();\n    _os.setServerEncoding(encodeName);\n    if (version == Const.PACKET_TYPE_TUP3) {\n      _os.write(newData, 0);\n    } else {\n      _os.write(oldData, 0);\n    }\n    return _os.toUint8List();\n  }\n\n  void decode(Uint8List buffer, {int index = 0}) {\n    //try tup3\n    try {\n      _is.wrap(buffer, pos: index);\n      _is.setServerEncoding(encodeName);\n      version = Const.PACKET_TYPE_TUP;\n      oldData = _is.readMapMap<String, String, Uint8List>(oldData, 0, false);\n    } catch (ex) {\n      version = Const.PACKET_TYPE_TUP3;\n      _is.wrap(buffer, pos: index);\n      _is.setServerEncoding(encodeName);\n\n      newData = _is.readMap<String, Uint8List>({\n        \"\": Uint8List.fromList([0x0])\n      }, 0, false);\n    }\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      _os.write(newData, 0);\n    } else {\n      _os.write(oldData, 0);\n    }\n  }\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    if (version == Const.PACKET_TYPE_TUP3) {\n      newData = {\n        \"\": Uint8List.fromList([0x0])\n      };\n      _is.readMap<String, Uint8List>(newData, 0, false);\n    } else {\n      oldData = _is.readMapMap<String, String, Uint8List>(oldData, 0, false);\n    }\n  }\n\n  @override\n  Object deepCopy() {\n    throw UnimplementedError();\n  }\n\n  @override\n  void displayAsString(StringBuffer sb, int level) {\n    throw UnimplementedError();\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/uni_packet.dart",
    "content": "// ignore_for_file: no_leading_underscores_for_local_identifiers\n\nimport 'package:tars_dart/tars/codec/tars_input_stream.dart';\nimport 'package:tars_dart/tars/codec/tars_output_stream.dart';\nimport 'package:tars_dart/tars/tup/write_buffer.dart';\n\nimport 'const.dart';\nimport 'request_packet.dart';\nimport 'uni_attribute.dart';\n\nclass UniPacket extends UniAttribute {\n  static const int kUniPacketHeadSize = 4;\n\n  RequestPacket package = RequestPacket();\n\n  /// 获取请求的service名字\n  ///\n  /// @return\n  String get servantName {\n    return package.sServantName;\n  }\n\n  set servantName(String value) {\n    package.sServantName = value;\n  }\n\n  /// 获取请求的函数名字\n  ///\n  /// @return\n  String get funcName {\n    return package.sFuncName;\n  }\n\n  set funcName(String value) {\n    package.sFuncName = value;\n  }\n\n  /// 获取消息序列号\n  ///\n  /// @return\n  int get requestId {\n    return package.iRequestId;\n  }\n\n  set requestId(int value) {\n    package.iRequestId = value;\n  }\n\n  UniPacket() {\n    package.iVersion = Const.PACKET_TYPE_TUP3;\n  }\n\n  void setVersion(int iVer) {\n    version = iVer;\n    package.iVersion = iVer;\n  }\n\n  int getVersion() {\n    return package.iVersion;\n  }\n\n  /// 将put的对象进行编码\n  @override\n  Uint8List encode() {\n    if (package.sServantName.compareTo(\"\") == 0) {\n      throw ArgumentError(\"servantName can not is null\");\n    }\n    if (package.sFuncName.compareTo(\"\") == 0) {\n      throw ArgumentError(\"funcName can not is null\");\n    }\n\n    TarsOutputStream _os = TarsOutputStream();\n    _os.setServerEncoding(encodeName);\n    if (package.iVersion == Const.PACKET_TYPE_TUP) {\n      throw UnimplementedError();\n    } else {\n      _os.write(newData, 0);\n    }\n\n    package.sBuffer = _os.toUint8List();\n\n    _os = TarsOutputStream();\n    _os.setServerEncoding(encodeName);\n    writeTo(_os);\n    Uint8List body = _os.toUint8List();\n    int size = body.lengthInBytes;\n\n    final WriteBuffer buffer = WriteBuffer();\n    buffer.putInt32(size + kUniPacketHeadSize, endian: Endian.big);\n    buffer.putUint8List(body);\n    return buffer.done().buffer.asUint8List();\n  }\n\n  /// 对传入的数据进行解码 填充可get的对象\n  @override\n  void decode(Uint8List buffer, {int index = 0}) {\n    if (buffer.lengthInBytes < kUniPacketHeadSize) {\n      throw ArgumentError(\"Decode namespace must include size head\");\n    }\n    try {\n      TarsInputStream _is =\n          TarsInputStream(buffer, pos: kUniPacketHeadSize + index);\n      _is.setServerEncoding(encodeName);\n      //解码出RequestPacket包\n      readFrom(_is);\n\n      //设置tup版本\n      version = package.iVersion;\n\n      _is = TarsInputStream(package.sBuffer);\n      _is.setServerEncoding(encodeName);\n\n      if (package.iVersion == Const.PACKET_TYPE_TUP) {\n        oldData = _is.readMapMap<String, String, Uint8List>(\n            <String, Map<String, Uint8List>>{\n              \"\": {\n                \"\": Uint8List.fromList([0x0])\n              }\n            },\n            0,\n            false);\n      } else {\n        newData = _is.readMap<String, Uint8List>({\n          \"\": Uint8List.fromList([0x0])\n        }, 0, false);\n      }\n    } catch (e) {\n      print('decode exception: $e');\n      rethrow;\n    }\n  }\n\n  @override\n  void writeTo(TarsOutputStream _os) {\n    package.writeTo(_os);\n  }\n\n  @override\n  void readFrom(TarsInputStream _is) {\n    package.readFrom(_is);\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/lib/tars/tup/write_buffer.dart",
    "content": "// Copyright 2014 The Flutter Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\nimport 'dart:math' as math;\nimport 'dart:typed_data';\nexport 'dart:typed_data'\n    show\n        ByteData,\n        Endian,\n        Float32List,\n        Float64List,\n        Int32List,\n        Int64List,\n        Uint8List;\n\n/// Write-only buffer for incrementally building a [ByteData] instance.\n///\n/// A WriteBuffer instance can be used only once. Attempts to reuse will result\n/// in [StateError]s being thrown.\n///\n/// The byte order used is [Endian.host] throughout.\nclass WriteBuffer {\n  /// Creates an interface for incrementally building a [ByteData] instance.\n  /// [startCapacity] determines the start size of the [WriteBuffer] in bytes.\n  /// The closer that value is to the real size used, the better the\n  /// performance.\n  factory WriteBuffer({int startCapacity = 8}) {\n    assert(startCapacity > 0);\n    final ByteData eightBytes = ByteData(8);\n    final Uint8List eightBytesAsList = eightBytes.buffer.asUint8List();\n    return WriteBuffer._(\n        Uint8List(startCapacity), eightBytes, eightBytesAsList);\n  }\n  WriteBuffer._(this._buffer, this._eightBytes, this._eightBytesAsList);\n  Uint8List _buffer;\n  int _currentSize = 0;\n  bool _isDone = false;\n  final ByteData _eightBytes;\n  final Uint8List _eightBytesAsList;\n  static final Uint8List _zeroBuffer = Uint8List(8);\n  void _add(int byte) {\n    if (_currentSize == _buffer.length) {\n      _resize();\n    }\n    _buffer[_currentSize] = byte;\n    _currentSize += 1;\n  }\n\n  void _append(Uint8List other) {\n    final int newSize = _currentSize + other.length;\n    if (newSize >= _buffer.length) {\n      _resize(newSize);\n    }\n    _buffer.setRange(_currentSize, newSize, other);\n    _currentSize += other.length;\n  }\n\n  void _addAll(Uint8List data, [int start = 0, int? end]) {\n    final int newEnd = end ?? _eightBytesAsList.length;\n    final int newSize = _currentSize + (newEnd - start);\n    if (newSize >= _buffer.length) {\n      _resize(newSize);\n    }\n    _buffer.setRange(_currentSize, newSize, data);\n    _currentSize = newSize;\n  }\n\n  void _resize([int? requiredLength]) {\n    final int doubleLength = _buffer.length * 2;\n    final int newLength = math.max(requiredLength ?? 0, doubleLength);\n    final Uint8List newBuffer = Uint8List(newLength);\n    newBuffer.setRange(0, _buffer.length, _buffer);\n    _buffer = newBuffer;\n  }\n\n  /// Write a Uint8 into the buffer.\n  void putUint8(int byte) {\n    assert(!_isDone);\n    _add(byte);\n  }\n\n  /// Write a Uint16 into the buffer.\n  void putUint16(int value, {Endian? endian}) {\n    assert(!_isDone);\n    _eightBytes.setUint16(0, value, endian ?? Endian.host);\n    _addAll(_eightBytesAsList, 0, 2);\n  }\n\n  /// Write a Uint32 into the buffer.\n  void putUint32(int value, {Endian? endian}) {\n    assert(!_isDone);\n    _eightBytes.setUint32(0, value, endian ?? Endian.host);\n    _addAll(_eightBytesAsList, 0, 4);\n  }\n\n  /// Write an Int32 into the buffer.\n  void putInt32(int value, {Endian? endian}) {\n    assert(!_isDone);\n    _eightBytes.setInt32(0, value, endian ?? Endian.host);\n    _addAll(_eightBytesAsList, 0, 4);\n  }\n\n  /// Write an Int64 into the buffer.\n  void putInt64(int value, {Endian? endian}) {\n    assert(!_isDone);\n    _eightBytes.setInt64(0, value, endian ?? Endian.host);\n    _addAll(_eightBytesAsList, 0, 8);\n  }\n\n  /// Write an Float64 into the buffer.\n  void putFloat64(double value, {Endian? endian}) {\n    assert(!_isDone);\n    _alignTo(8);\n    _eightBytes.setFloat64(0, value, endian ?? Endian.host);\n    _addAll(_eightBytesAsList);\n  }\n\n  /// Write all the values from a [Uint8List] into the buffer.\n  void putUint8List(Uint8List list) {\n    assert(!_isDone);\n    _append(list);\n  }\n\n  /// Write all the values from an [Int32List] into the buffer.\n  void putInt32List(Int32List list) {\n    assert(!_isDone);\n    _alignTo(4);\n    _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));\n  }\n\n  /// Write all the values from an [Int64List] into the buffer.\n  void putInt64List(Int64List list) {\n    assert(!_isDone);\n    _alignTo(8);\n    _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));\n  }\n\n  /// Write all the values from a [Float32List] into the buffer.\n  void putFloat32List(Float32List list) {\n    assert(!_isDone);\n    _alignTo(4);\n    _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));\n  }\n\n  /// Write all the values from a [Float64List] into the buffer.\n  void putFloat64List(Float64List list) {\n    assert(!_isDone);\n    _alignTo(8);\n    _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));\n  }\n\n  void _alignTo(int alignment) {\n    assert(!_isDone);\n    final int mod = _currentSize % alignment;\n    if (mod != 0) {\n      _addAll(_zeroBuffer, 0, alignment - mod);\n    }\n  }\n\n  /// Finalize and return the written [ByteData].\n  ByteData done() {\n    if (_isDone) {\n      throw StateError(\n          'done() must not be called more than once on the same $runtimeType.');\n    }\n    final ByteData result = _buffer.buffer.asByteData(0, _currentSize);\n    _buffer = Uint8List(0);\n    _isDone = true;\n    return result;\n  }\n}\n\n/// Read-only buffer for reading sequentially from a [ByteData] instance.\n///\n/// The byte order used is [Endian.host] throughout.\nclass ReadBuffer {\n  /// Creates a [ReadBuffer] for reading from the specified [data].\n  ReadBuffer(this.data);\n\n  /// The underlying data being read.\n  final ByteData data;\n\n  /// The position to read next.\n  int _position = 0;\n\n  /// Whether the buffer has data remaining to read.\n  bool get hasRemaining => _position < data.lengthInBytes;\n\n  /// Reads a Uint8 from the buffer.\n  int getUint8() {\n    return data.getUint8(_position++);\n  }\n\n  /// Reads a Uint16 from the buffer.\n  int getUint16({Endian? endian}) {\n    final int value = data.getUint16(_position, endian ?? Endian.host);\n    _position += 2;\n    return value;\n  }\n\n  /// Reads a Uint32 from the buffer.\n  int getUint32({Endian? endian}) {\n    final int value = data.getUint32(_position, endian ?? Endian.host);\n    _position += 4;\n    return value;\n  }\n\n  /// Reads an Int32 from the buffer.\n  int getInt32({Endian? endian}) {\n    final int value = data.getInt32(_position, endian ?? Endian.host);\n    _position += 4;\n    return value;\n  }\n\n  /// Reads an Int64 from the buffer.\n  int getInt64({Endian? endian}) {\n    final int value = data.getInt64(_position, endian ?? Endian.host);\n    _position += 8;\n    return value;\n  }\n\n  /// Reads a Float64 from the buffer.\n  double getFloat64({Endian? endian}) {\n    _alignTo(8);\n    final double value = data.getFloat64(_position, endian ?? Endian.host);\n    _position += 8;\n    return value;\n  }\n\n  /// Reads the given number of Uint8s from the buffer.\n  Uint8List getUint8List(int length) {\n    final Uint8List list =\n        data.buffer.asUint8List(data.offsetInBytes + _position, length);\n    _position += length;\n    return list;\n  }\n\n  /// Reads the given number of Int32s from the buffer.\n  Int32List getInt32List(int length) {\n    _alignTo(4);\n    final Int32List list =\n        data.buffer.asInt32List(data.offsetInBytes + _position, length);\n    _position += 4 * length;\n    return list;\n  }\n\n  /// Reads the given number of Int64s from the buffer.\n  Int64List getInt64List(int length) {\n    _alignTo(8);\n    final Int64List list =\n        data.buffer.asInt64List(data.offsetInBytes + _position, length);\n    _position += 8 * length;\n    return list;\n  }\n\n  /// Reads the given number of Float32s from the buffer\n  Float32List getFloat32List(int length) {\n    _alignTo(4);\n    final Float32List list =\n        data.buffer.asFloat32List(data.offsetInBytes + _position, length);\n    _position += 4 * length;\n    return list;\n  }\n\n  /// Reads the given number of Float64s from the buffer.\n  Float64List getFloat64List(int length) {\n    _alignTo(8);\n    final Float64List list =\n        data.buffer.asFloat64List(data.offsetInBytes + _position, length);\n    _position += 8 * length;\n    return list;\n  }\n\n  void _alignTo(int alignment) {\n    final int mod = _position % alignment;\n    if (mod != 0) {\n      _position += alignment - mod;\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_core/packages/tars_dart/pubspec.yaml",
    "content": "name: tars_dart\ndescription: Dart Support Library For Tars RPC framework\nversion: 0.1.0\nhomepage: \"https://github.com/brooklet/TarsFlutter\"\n\nenvironment: \n  sdk: '>=3.0.5 <4.0.0'\n\ndependencies:\n  dio: ^5.7.0\n  logger: ^2.5.0\n\ndev_dependencies: \n  lints: ^6.0.0\n  test: ^1.21.0\n"
  },
  {
    "path": "simple_live_core/pubspec.yaml",
    "content": "name: simple_live_core\nversion: 1.0.4\ndescription: \"聚合直播核心库\"\nrepository: https://github.com/xiaoyaocz/dart_simple_live\npublish_to: \"none\"\nenvironment: \n  sdk: '>=3.0.5 <4.0.0'\n\ndependencies:\n  flutter:\n    sdk: flutter\n  dio: ^5.5.0+1\n  logger: ^2.4.0\n  web_socket_channel: ^3.0.3\n  html_unescape: ^2.0.0\n  protobuf: ^6.0.0\n  crypto: ^3.0.7\n  brotli: ^0.6.0\n  tars_dart:\n    path: ./packages/tars_dart\n  fixnum: ^1.1.1\n  flutter_qjs:\n    git:\n      url: https://github.com/wgh136/flutter_qjs.git\n      branch: master\n  dart_sm: ^0.1.5\n\ndev_dependencies: \n  lints: ^6.0.0\n  test: ^1.29.0\n\nflutter:\n  assets:\n    - assets/js/douyin-webmssdk.js\n"
  },
  {
    "path": "simple_live_core/test/douyu_sc.json",
    "content": "{\n  \"danmuShowSwitch\": 1,\n  \"mtype\": 2,\n  \"totalNum\": 0,\n  \"type\": \"voice_trlt\",\n  \"isShow\": 1,\n  \"list\": [\n    {\n      \"vrId\": 2013689846161235968,\n      \"vocUrl\": [\n        \"https:\",\n        \"sta-op.douyucdn.cn/voice-synthesis/2026/01/21/b60a87c6e63c6cc62f693a737c06af96.mp3\"\n      ],\n      \"uat\": [\n        \"https:\",\n        \"apic.douyucdn.cn/upload/avatar_v3/202210/e9729aa3d86347ddb294e4231f67356f_big.jpg\"\n      ],\n      \"stime\": 120,\n      \"etimeV2\": 1768936192,\n      \"content\": \"天天玩个马尔斯拿矛清兵poke，每次开大矛都没有，技能全是乱的，经常一波全送了\",\n      \"vocNickUrl\": [\n        \"https:\",\n        \"sta-op.douyucdn.cn/voice-synthesis/2026/01/21/c540975c0880655ebadb767622b6395b.mp3\"\n      ],\n      \"uid\": 464434107,\n      \"price\": 5000,\n      \"etime\": 1768936192,\n      \"acptime\": 1768936072,\n      \"un\": \"cej35\",\n      \"mf\": 0,\n      \"isVoc\": 1,\n      \"realPrice\": 5000\n    }\n  ]\n}"
  },
  {
    "path": "simple_live_core/test/simple_live_core_test.dart",
    "content": "\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:test/test.dart';\n\nvoid testSite(LiveSite site) async {\n  var rooms = <LiveRoomItem>[];\n  test('getRecommendRooms', () async {\n    if (site is TwitchSite) {\n      return;\n    }\n    final result = await site.getRecommendRooms();\n    expect(result, isNotNull);\n    expect(result.items, isNotEmpty);\n    rooms = result.items;\n    for (var item in rooms) {\n      expect(item.roomId, isNotEmpty);\n      expect(item.title, isNotEmpty);\n      expect(item.cover, isNotEmpty);\n      expect(item.userName, isNotEmpty);\n      print(item);\n    }\n  });\n\n  var categores = <LiveCategory>[];\n  test('getCategores', () async {\n    if (site is TwitchSite) {\n      return;\n    }\n    categores = await site.getCategores();\n    expect(categores, isNotEmpty);\n    for (var item in categores) {\n      expect(item.name, isNotEmpty);\n      for (var subItem in item.children) {\n        expect(subItem.name, isNotEmpty);\n        expect(subItem.id, isNotEmpty);\n        expect(subItem.parentId, isNotEmpty);\n      }\n      print('${item.name}\\n${item.children}');\n    }\n  });\n\n  test('getCategoryRooms', () async {\n    if (site is TwitchSite) {\n      return;\n    }\n    var result = await site.getCategoryRooms(categores.first.children.first);\n    expect(result, isNotNull);\n    expect(result.items, isNotEmpty);\n    for (var item in result.items) {\n      expect(item.roomId, isNotEmpty);\n      expect(item.title, isNotEmpty);\n      expect(item.cover, isNotEmpty);\n      expect(item.userName, isNotEmpty);\n      print(item);\n    }\n  });\n\n  test('searchRooms', () async {\n    if (site is TwitchSite) {\n      return;\n    }\n    var result = await site.searchRooms('LOL');\n    expect(result, isNotNull);\n    expect(result.items, isNotEmpty);\n    for (var item in result.items) {\n      expect(item.roomId, isNotEmpty);\n      expect(item.title, isNotEmpty);\n      expect(item.cover, isNotEmpty);\n      expect(item.userName, isNotEmpty);\n      print(item);\n    }\n  });\n\n  test('searchAnchors', () async {\n    // 跳过抖音测试此项\n    if (site is DouyinSite) {\n      return;\n    }\n    if (site is TwitchSite) {\n      return;\n    }\n    var result = await site.searchAnchors('联盟');\n    expect(result, isNotNull);\n    expect(result.items, isNotEmpty);\n    for (var item in result.items) {\n      expect(item.roomId, isNotEmpty);\n      expect(item.userName, isNotEmpty);\n      print(item);\n    }\n  });\n\n  LiveRoomDetail? roomDetail;\n  test('getRoomDetail', () async {\n    roomDetail = await site.getRoomDetail(roomId: \"222523\");\n    expect(roomDetail, isNotNull);\n    expect(roomDetail?.roomId, isNotEmpty);\n    // expect(roomDetail?.danmakuData, isNotNull);\n    print(roomDetail);\n  });\n\n  List<LivePlayQuality> playQualities = [];\n  test('getPlayQuality', () async {\n    playQualities = await site.getPlayQualites(detail: roomDetail!);\n    expect(playQualities, isNotEmpty);\n    for (var item in playQualities) {\n      expect(item.quality, isNotEmpty);\n      expect(item.data, isNotNull);\n      print(item);\n    }\n  });\n\n  test('getPlayUrls', () async {\n    var url = await site.getPlayUrls(\n        detail: roomDetail!, quality: playQualities.first);\n    expect(url, isNotNull);\n    expect(url.urls, isNotEmpty);\n    print(url.urls.join('\\n\\n'));\n  });\n\n  test('getDanmaku', () async {\n    if (site is TwitchSite) {\n      return;\n    }\n    var danmaku = site.getDanmaku();\n    expect(danmaku, isNotNull);\n    expect(danmaku, isA<LiveDanmaku>());\n    var closed = false;\n    var ready = false;\n    danmaku.onReady = () {\n      print('ready');\n      ready = true;\n    };\n    danmaku.onClose = (msg) {\n      print('onClose $msg');\n      closed = true;\n    };\n    var msgCount = 0;\n    danmaku.onMessage = (LiveMessage msg) {\n      print('onMessage ${msg.type} ${msg.message}');\n      msgCount++;\n    };\n    await danmaku.start(roomDetail!.danmakuData);\n    // 接收30秒的弹幕\n    await Future.delayed(const Duration(seconds: 30));\n    expect(ready, isTrue);\n    expect(closed, isFalse);\n    expect(msgCount, greaterThan(0));\n    await danmaku.stop();\n  }, timeout: const Timeout(Duration(seconds: 40)));\n}\n\nvoid main() {\n  CoreLog.requestLogType = RequestLogType.short;\n\n  group('huya tests', () {\n    testSite(HuyaSite());\n  });\n}\n\n//\n"
  },
  {
    "path": "simple_live_tv_app/.fvmrc",
    "content": "{\n  \"flutter\": \"3.35.7\"\n}"
  },
  {
    "path": "simple_live_tv_app/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\nmigrate_working_dir/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\n\n# Android Studio will place build artifacts here\n/android/app/debug\n/android/app/profile\n/android/app/release\n\n# FVM Version Cache\n.fvm/"
  },
  {
    "path": "simple_live_tv_app/.metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: \"d693b4b9dbac2acd4477aea4555ca6dcbea44ba2\"\n  channel: \"stable\"\n\nproject_type: app\n\n# Tracks metadata for the flutter migrate command\nmigration:\n  platforms:\n    - platform: root\n      create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2\n      base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2\n    - platform: android\n      create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2\n      base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2\n\n  # User provided section\n\n  # List of Local paths (relative to this file) that should be\n  # ignored by the migrate tool.\n  #\n  # Files that are not part of the templates will be ignored by default.\n  unmanaged_files:\n    - 'lib/main.dart'\n    - 'ios/Runner.xcodeproj/project.pbxproj'\n"
  },
  {
    "path": "simple_live_tv_app/README.md",
    "content": "# simple_live_tv_app\n\nSimple Live Android TV APP\n\n"
  },
  {
    "path": "simple_live_tv_app/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\ninclude: package:flutter_lints/flutter.yaml\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at https://dart.dev/lints.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "simple_live_tv_app/android/.gitignore",
    "content": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n.cxx/\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/to/reference-keystore\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "simple_live_tv_app/android/app/build.gradle.kts",
    "content": "import java.util.Properties\nimport java.io.FileInputStream\n\nplugins {\n    id(\"com.android.application\")\n    id(\"kotlin-android\")\n    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.\n    id(\"dev.flutter.flutter-gradle-plugin\")\n}\n\nval keystoreProperties = Properties()\nval keystorePropertiesFile = rootProject.file(\"key.properties\")\nif (keystorePropertiesFile.exists()) {\n    keystoreProperties.load(FileInputStream(keystorePropertiesFile))\n}\n\nandroid {\n    namespace = \"com.xycz.simple_live_tv\"\n    compileSdk = flutter.compileSdkVersion\n    ndkVersion = flutter.ndkVersion\n\n    compileOptions {\n        sourceCompatibility = JavaVersion.VERSION_11\n        targetCompatibility = JavaVersion.VERSION_11\n    }\n\n    kotlinOptions {\n        jvmTarget = JavaVersion.VERSION_11.toString()\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId = \"com.xycz.simple_live_tv\"\n        // You can update the following values to match your application needs.\n        // For more information, see: https://flutter.dev/to/review-gradle-config.\n        minSdk = flutter.minSdkVersion\n        targetSdk = flutter.targetSdkVersion\n        versionCode = flutter.versionCode\n        versionName = flutter.versionName\n    }\n\n    signingConfigs {\n        create(\"release\") {\n            keyAlias = keystoreProperties[\"keyAlias\"] as String\n            keyPassword = keystoreProperties[\"keyPassword\"] as String\n            storeFile = keystoreProperties[\"storeFile\"]?.let { file(it) }\n            storePassword = keystoreProperties[\"storePassword\"] as String\n            isV1SigningEnabled = true\n            isV2SigningEnabled = true\n        }\n    }\n\n    buildTypes {\n        release {\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig = signingConfigs.getByName(\"release\")\n            isMinifyEnabled = true\n            isShrinkResources = true\n            proguardFiles(\n                // Default file with automatically generated optimization rules.\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n        }\n    }\n}\n\nflutter {\n    source = \"../..\"\n}\n"
  },
  {
    "path": "simple_live_tv_app/android/app/proguard-rules.pro",
    "content": "#Flutter Wrapper\n-keep class io.flutter.app.** { *; }\n-keep class io.flutter.plugin.**  { *; }\n-keep class io.flutter.util.**  { *; }\n-keep class io.flutter.view.**  { *; }\n-keep class io.flutter.**  { *; }\n-keep class io.flutter.plugins.**  { *; }\n-keep class de.prosiebensat1digital.** { *; }\n-dontwarn io.flutter.embedding.**\n-ignorewarnings"
  },
  {
    "path": "simple_live_tv_app/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.xycz.simple_live_tv\">\n   <uses-permission android:name=\"android.permission.INTERNET\" />\n   <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n   <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n   <uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\" />\n    <application\n        android:label=\"Simple Live TV\"\n        android:name=\"${applicationName}\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:banner=\"@mipmap/ic_banner\"\n        android:networkSecurityConfig=\"@xml/network_security_config\"\n        android:usesCleartextTraffic=\"true\">\n        <activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTop\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\"\n            android:banner=\"@mipmap/ic_banner\"\n            android:screenOrientation=\"landscape\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/java/com/bgylde/live/MainActivity.java",
    "content": "package com.bgylde.live;\n\nimport io.flutter.embedding.android.FlutterActivity;\n\npublic class MainActivity extends FlutterActivity {\n}\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/kotlin/com/xycz/simple_live_tv/MainActivity.kt",
    "content": "package com.xycz.simple_live_tv\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {\n}\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n    <item>\n        <shape android:shape=\"rectangle\">\n            <gradient\n                android:type=\"linear\"\n                android:startColor=\"#141e30\"\n                android:centerColor=\"#243b55\"\n                android:endColor=\"#141e30\"\n                android:angle=\"135\" />\n        </shape>\n    </item>\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n     <item>\n        <shape android:shape=\"rectangle\">\n            <gradient\n                android:type=\"linear\"\n                android:startColor=\"#141e30\"\n                android:centerColor=\"#243b55\"\n                android:endColor=\"#141e30\"\n                android:angle=\"135\" />\n        </shape>\n    </item>\n</layer-list>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_banner_background\"/>\n    <foreground android:drawable=\"@mipmap/ic_banner_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/values/ic_banner_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_banner_background\">#FFFFFF</color>\n</resources>"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n        <!-- Disable the greenish yellow focus border that shows up when using physical or emulated peripherals -->\n        <item name=\"android:defaultFocusHighlightEnabled\">false</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n        <!-- Disable the greenish yellow focus border that shows up when using physical or emulated peripherals -->\n        <item name=\"android:defaultFocusHighlightEnabled\">false</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             the Flutter engine draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n        <!-- Disable the greenish yellow focus border that shows up when using physical or emulated peripherals -->\n        <item name=\"android:defaultFocusHighlightEnabled\">false</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n\n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n        <!-- Disable the greenish yellow focus border that shows up when using physical or emulated peripherals -->\n        <item name=\"android:defaultFocusHighlightEnabled\">false</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/main/res/xml/network_security_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<network-security-config>\n    <base-config cleartextTrafficPermitted=\"true\" />\n</network-security-config>\n"
  },
  {
    "path": "simple_live_tv_app/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- The INTERNET permission is required for development. Specifically,\n         the Flutter tool needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "simple_live_tv_app/android/build.gradle.kts",
    "content": "allprojects {\n    repositories {\n        google()\n        mavenCentral()\n        \n    }\n}\n\nval newBuildDir: Directory =\n    rootProject.layout.buildDirectory\n        .dir(\"../../build\")\n        .get()\nrootProject.layout.buildDirectory.value(newBuildDir)\n\nsubprojects {\n    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)\n    project.layout.buildDirectory.value(newSubprojectBuildDir)\n}\nsubprojects {\n    project.evaluationDependsOn(\":app\")\n}\n\ntasks.register<Delete>(\"clean\") {\n    delete(rootProject.layout.buildDirectory)\n}\n"
  },
  {
    "path": "simple_live_tv_app/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.12-all.zip\n"
  },
  {
    "path": "simple_live_tv_app/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "simple_live_tv_app/android/settings.gradle.kts",
    "content": "pluginManagement {\n    val flutterSdkPath =\n        run {\n            val properties = java.util.Properties()\n            file(\"local.properties\").inputStream().use { properties.load(it) }\n            val flutterSdkPath = properties.getProperty(\"flutter.sdk\")\n            require(flutterSdkPath != null) { \"flutter.sdk not set in local.properties\" }\n            flutterSdkPath\n        }\n\n    includeBuild(\"$flutterSdkPath/packages/flutter_tools/gradle\")\n\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\n\nplugins {\n    id(\"dev.flutter.flutter-plugin-loader\") version \"1.0.0\"\n    id(\"com.android.application\") version \"8.9.1\" apply false\n    id(\"org.jetbrains.kotlin.android\") version \"2.1.0\" apply false\n}\n\ninclude(\":app\")\n"
  },
  {
    "path": "simple_live_tv_app/assets/lotties/empty.json",
    "content": "{\"v\":\"4.7.0\",\"fr\":25,\"ip\":0,\"op\":50,\"w\":120,\"h\":120,\"nm\":\"Comp 1\",\"ddd\":0,\"assets\":[],\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"ruoi\",\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.967]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p967_0p167_0p033\"],\"t\":35,\"s\":[100],\"e\":[0]},{\"t\":49}]},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0,\"y\":0},\"n\":\"0p833_0p833_0_0\",\"t\":0,\"s\":[57.361,61.016,0],\"e\":[57.699,41.796,0],\"to\":[-4.67500305175781,-4.12800598144531,0],\"ti\":[-13.9099960327148,5.27300262451172,0]},{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0.167,\"y\":0.167},\"n\":\"0p833_0p833_0p167_0p167\",\"t\":10.219,\"s\":[57.699,41.796,0],\"e\":[79.084,33.982,0],\"to\":[12.8159942626953,-4.85800170898438,0],\"ti\":[-4.54498291015625,3.73400115966797,0]},{\"i\":{\"x\":0.833,\"y\":0.833},\"o\":{\"x\":0.167,\"y\":0.167},\"n\":\"0p833_0p833_0p167_0p167\",\"t\":19.445,\"s\":[79.084,33.982,0],\"e\":[59.691,9.121,0],\"to\":[6.61601257324219,-5.43799591064453,0],\"ti\":[20.0290069580078,1.20700073242188,0]},{\"t\":35}]},\"a\":{\"a\":0,\"k\":[60.531,10.945,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-0.994,0],[0,-0.994],[0.995,0],[0,0.994]],\"o\":[[0.995,0],[0,0.994],[-0.994,0],[0,-0.994]],\"v\":[[-0.001,-1.801],[1.801,-0.001],[-0.001,1.801],[-1.801,-0.001]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[62.4,13.144],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 1\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-1.422,0],[0,-1.422],[1.421,0],[0,1.422]],\"o\":[[1.421,0],[0,1.422],[-1.422,0],[0,-1.422]],\"v\":[[0.001,-2.574],[2.574,0],[0.001,2.574],[-2.574,0]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":0.7},\"lc\":1,\"lj\":1,\"ml\":10,\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[1,1,1,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[64.145,9.606],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 2\",\"np\":3,\"cix\":2,\"ix\":2,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[-1.996,0],[0,-1.996],[1.996,0],[0,1.996]],\"o\":[[1.996,0],[0,1.996],[-1.996,0],[0,-1.996]],\"v\":[[0,-3.614],[3.614,0],[0,3.614],[-3.614,0]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":0.7},\"lc\":1,\"lj\":1,\"ml\":10,\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[1,1,1,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[57.957,10.552],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 3\",\"np\":3,\"cix\":2,\"ix\":3,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60.531,10.941],\"ix\":2},\"a\":{\"a\":0,\"k\":[60.531,10.941],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"ruoi\",\"np\":3,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Shape Layer 2\",\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.967]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p967_0p167_0p033\"],\"t\":35,\"s\":[100],\"e\":[0]},{\"t\":49}]},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":0,\"k\":[-0.75,-0.75,0]},\"a\":{\"a\":0,\"k\":[0,0,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[-13.91,5.273],[-4.545,3.734],[20.029,1.207]],\"o\":[[-4.675,-4.128],[12.816,-4.858],[6.616,-5.438],[0,0]],\"v\":[[-7.383,24.76],[-7.046,5.54],[14.34,-2.273],[-3.178,-24.76]],\"c\":false}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.34901960784313724,0.3686274509803922,0.4,1]},\"o\":{\"a\":0,\"k\":100},\"w\":{\"a\":0,\"k\":1},\"lc\":2,\"lj\":2,\"d\":[{\"n\":\"d\",\"nm\":\"dash\",\"v\":{\"a\":0,\"k\":2.028}},{\"n\":\"g\",\"nm\":\"gap\",\"v\":{\"a\":0,\"k\":2.028}},{\"n\":\"o\",\"nm\":\"offset\",\"v\":{\"a\":0,\"k\":0}}],\"nm\":\"Stroke 1\",\"mn\":\"ADBE Vector Graphic - Stroke\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[67.87,37.631],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 6\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tm\",\"s\":{\"a\":0,\"k\":0,\"ix\":1},\"e\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.833],\"y\":[0.953]},\"o\":{\"x\":[0.167],\"y\":[0.033]},\"n\":[\"0p833_0p953_0p167_0p033\"],\"t\":0,\"s\":[0],\"e\":[100]},{\"t\":35}],\"ix\":2},\"o\":{\"a\":0,\"k\":0,\"ix\":3},\"m\":1,\"ix\":2,\"nm\":\"Trim Paths 1\",\"mn\":\"ADBE Vector Filter - Trim\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"im_emptyBox Outlines\",\"ks\":{\"o\":{\"a\":0,\"k\":100},\"r\":{\"a\":0,\"k\":0},\"p\":{\"a\":0,\"k\":[60,60,0]},\"a\":{\"a\":0,\"k\":[60,60,0]},\"s\":{\"a\":0,\"k\":[100,100,100]}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[-0.001,-16.607],[-32.143,-0.002],[-0.001,16.607],[32.144,-0.002]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.8,0.82,0.851,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,55.75],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 7\",\"np\":2,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[12.856,-23.249],[0,-16.605],[-12.857,-23.249],[-45,-6.641],[-32.144,0.001],[-45,6.645],[-12.857,23.249],[0,16.609],[12.856,23.249],[45,6.645],[32.143,0.001],[45,-6.641]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9372549019607843,0.9372549019607843,0.9372549019607843,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,55.748],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 8\",\"np\":2,\"cix\":2,\"ix\":2,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[-16.072,24.171],[16.072,11.312],[16.072,-24.171],[-16.072,-24.171]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9529411764705882,0.9529411764705882,0.9529411764705882,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[76.072,83.33],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 9\",\"np\":2,\"cix\":2,\"ix\":3,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[-32.143,-24.171],[-32.143,11.311],[-0.001,24.171],[32.144,11.311],[32.144,-24.171]],\"c\":true}},\"nm\":\"Path 1\",\"mn\":\"ADBE Vector Shape - Group\"},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.8,0.82,0.851,1]},\"o\":{\"a\":0,\"k\":100},\"r\":1,\"nm\":\"Fill 1\",\"mn\":\"ADBE Vector Graphic - Fill\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,83.33],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"Group 10\",\"np\":2,\"cix\":2,\"ix\":4,\"mn\":\"ADBE Vector Group\"},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[60,60.186],\"ix\":2},\"a\":{\"a\":0,\"k\":[60,60.186],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transform\"}],\"nm\":\"box\",\"np\":4,\"cix\":2,\"ix\":1,\"mn\":\"ADBE Vector Group\"}],\"ip\":0,\"op\":50,\"st\":0,\"bm\":0,\"sr\":1}]}"
  },
  {
    "path": "simple_live_tv_app/assets/lotties/error.json",
    "content": "{\"v\":\"5.8.1\",\"fr\":29.9700012207031,\"ip\":0,\"op\":301.000012259981,\"w\":1080,\"h\":900,\"nm\":\"Composition 1\",\"ddd\":0,\"assets\":[{\"id\":\"comp_0\",\"nm\":\"Nuage\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 11\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[54,54],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-22,-239],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 12\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[544.675,315.475,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-54.5,-226.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[80,80,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[31,31],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-54.5,-226.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[31,31],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-54.5,-226.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[100,20],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":20,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-26,-216],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_1\",\"nm\":\"éolienne\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":0,\"nm\":\"Hélices\",\"refId\":\"comp_2\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.137],\"y\":[1]},\"o\":{\"x\":[0.567],\"y\":[0]},\"t\":1,\"s\":[0]},{\"t\":300.00001221925,\"s\":[1440]}],\"ix\":10},\"p\":{\"a\":0,\"k\":[800,440,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[800,440,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Socle eolienne\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[264.75,-95],[257,-95],[242,252],[288,251]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_2\",\"nm\":\"Hélices\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 11\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":-239.6,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":-122.747,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[803,442,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[263,-98,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0],[0,0]],\"v\":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[800.5,439.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[266.5,-94.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[27,27],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[266.5,-94.5],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_3\",\"nm\":\"plot base\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[541,387.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[1,-152.5,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[13,-223],[-13,-223],[-52,-82],[54,-82]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,502,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,-38,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[58,-56],[-59,-56],[-70,-20],[70,-20]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 5\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[539.75,606.25,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-0.25,66.25,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[256.5,28.5],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.7647058823529411,0.3215686274509804,0.23137254901960785,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-0.25,66.25],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 6\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,572,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,32,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0],[0,0],[0,0]],\"o\":[[0,0],[0,0],[0,0],[0,0]],\"v\":[[78,3],[-76,3],[-93,60],[93,61]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_4\",\"nm\":\"Tree\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 10\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-171.5,-79.5],[-152.5,-45]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980451995,0.84313731474,0.84313731474,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":7,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 9\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-154.5,-23.5],[-137.5,-48.5]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980451995,0.84313731474,0.84313731474,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":7,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[386,620,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-154,80,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0,0],[0,0]],\"o\":[[0,0],[0,0]],\"v\":[[-154,256],[-154,-96]],\"c\":false},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"st\",\"c\":{\"a\":0,\"k\":[0.850980392157,0.844306078144,0.844306078144,1],\"ix\":3},\"o\":{\"a\":0,\"k\":100,\"ix\":4},\"w\":{\"a\":0,\"k\":10,\"ix\":5},\"lc\":1,\"lj\":1,\"ml\":4,\"bm\":0,\"nm\":\"Contour 1\",\"mn\":\"ADBE Vector Graphic - Stroke\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 8\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[384,475,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-156,-65,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[96,222],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":62,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.949019667682,0.949019667682,0.949019667682,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-156,-65],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]},{\"id\":\"comp_5\",\"nm\":\"ground\",\"fr\":29.9700012207031,\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":4,\"nm\":\"Calque de forme 2\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[515,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[662,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[817,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[78,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":4,\"nm\":\"Calque de forme 3\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[752,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[89,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":4,\"nm\":\"Calque de forme 1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[270,795.5,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[-273.5,78,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[102,317,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[59,2],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":2371,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.133333333333,0.145098039216,0.235294132607,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-273.5,78],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}]}],\"layers\":[{\"ddd\":0,\"ind\":1,\"ty\":0,\"nm\":\"Nuage\",\"refId\":\"comp_0\",\"sr\":1,\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.833],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":51,\"s\":[100]},{\"i\":{\"x\":[0.833],\"y\":[1]},\"o\":{\"x\":[0.167],\"y\":[0]},\"t\":234,\"s\":[100]},{\"t\":299.00001217852,\"s\":[0]}],\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.284,\"y\":1},\"o\":{\"x\":0.387,\"y\":0},\"t\":0,\"s\":[704,380,0],\"to\":[-36.667,0,0],\"ti\":[36.667,0,0]},{\"t\":299.00001217852,\"s\":[484,380,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[514,308,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":2,\"ty\":4,\"nm\":\"Calque de forme 7\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],\"o\":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],\"v\":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.83137254902,0.821591725069,0.821591725069,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":3,\"ty\":0,\"nm\":\"éolienne\",\"refId\":\"comp_1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[804,796,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[804,796,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":4,\"ty\":0,\"nm\":\"plot base\",\"refId\":\"comp_3\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":7.368,\"s\":[6]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":14.736,\"s\":[-5]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":22.264,\"s\":[4]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":29.633,\"s\":[-2]},{\"t\":37.0000015070409,\"s\":[0]}],\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":0,\"s\":[540,792,0],\"to\":[0,-2.667,0],\"ti\":[0,2,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":7.368,\"s\":[540,776,0],\"to\":[0,-2,0],\"ti\":[0,-1.333,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":14.736,\"s\":[540,780,0],\"to\":[0,1.333,0],\"ti\":[0,-1.333,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":22.264,\"s\":[540,784,0],\"to\":[0,1.333,0],\"ti\":[0,-2,0]},{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":29.633,\"s\":[540,788,0],\"to\":[0,2,0],\"ti\":[0,-1.333,0]},{\"t\":37.0000015070409,\"s\":[540,796,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,616,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":5,\"ty\":0,\"nm\":\"éolienne\",\"refId\":\"comp_1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[670,796,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[804,796,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[63,63,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":6,\"ty\":0,\"nm\":\"Tree\",\"refId\":\"comp_4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[280,790,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[384,790,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[82,82,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":7,\"ty\":0,\"nm\":\"Tree\",\"refId\":\"comp_4\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":8,\"ty\":4,\"nm\":\"Arbuste\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[68,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ind\":0,\"ty\":\"sh\",\"ix\":1,\"ks\":{\"a\":0,\"k\":{\"i\":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],\"o\":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],\"v\":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],\"c\":true},\"ix\":2},\"nm\":\"Tracé 1\",\"mn\":\"ADBE Vector Shape - Group\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.901960784314,0.901960784314,0.901960784314,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[0,0],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Forme 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":9,\"ty\":0,\"nm\":\"ground\",\"refId\":\"comp_5\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":10,\"ty\":0,\"nm\":\"Nuage\",\"refId\":\"comp_0\",\"sr\":1,\"ks\":{\"o\":{\"a\":1,\"k\":[{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":0,\"s\":[0]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":51,\"s\":[100]},{\"i\":{\"x\":[0.667],\"y\":[1]},\"o\":{\"x\":[0.333],\"y\":[0]},\"t\":234,\"s\":[100]},{\"t\":299.00001217852,\"s\":[0]}],\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":1,\"k\":[{\"i\":{\"x\":0.667,\"y\":1},\"o\":{\"x\":0.333,\"y\":0},\"t\":0,\"s\":[193,606,0],\"to\":[56.5,0,0],\"ti\":[-56.5,0,0]},{\"t\":299.00001217852,\"s\":[532,606,0]}],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[514,308,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[60,60,100],\"ix\":6,\"l\":2}},\"ao\":0,\"w\":1080,\"h\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":11,\"ty\":4,\"nm\":\"Calque de forme 6\",\"td\":1,\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[572,712,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"ty\":\"rc\",\"d\":1,\"s\":{\"a\":0,\"k\":[784,628],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":4},\"nm\":\"Tracé rectangulaire 1\",\"mn\":\"ADBE Vector Shape - Rect\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.909803921569,0.909803921569,0.909803921569,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[-36,-234],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Rectangle 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":12,\"ty\":4,\"nm\":\"Calque de forme 5\",\"tt\":1,\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,716,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[0,0,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"shapes\":[{\"ty\":\"gr\",\"it\":[{\"d\":1,\"ty\":\"el\",\"s\":{\"a\":0,\"k\":[728,728],\"ix\":2},\"p\":{\"a\":0,\"k\":[0,0],\"ix\":3},\"nm\":\"Tracé d'ellipse 1\",\"mn\":\"ADBE Vector Shape - Ellipse\",\"hd\":false},{\"ty\":\"fl\",\"c\":{\"a\":0,\"k\":[0.976470588235,0.976470588235,0.976470588235,1],\"ix\":4},\"o\":{\"a\":0,\"k\":100,\"ix\":5},\"r\":1,\"bm\":0,\"nm\":\"Fond 1\",\"mn\":\"ADBE Vector Graphic - Fill\",\"hd\":false},{\"ty\":\"tr\",\"p\":{\"a\":0,\"k\":[8,-140],\"ix\":2},\"a\":{\"a\":0,\"k\":[0,0],\"ix\":1},\"s\":{\"a\":0,\"k\":[100,100],\"ix\":3},\"r\":{\"a\":0,\"k\":0,\"ix\":6},\"o\":{\"a\":0,\"k\":100,\"ix\":7},\"sk\":{\"a\":0,\"k\":0,\"ix\":4},\"sa\":{\"a\":0,\"k\":0,\"ix\":5},\"nm\":\"Transformer \"}],\"nm\":\"Ellipse 1\",\"np\":3,\"cix\":2,\"bm\":0,\"ix\":1,\"mn\":\"ADBE Vector Group\",\"hd\":false}],\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0},{\"ddd\":0,\"ind\":14,\"ty\":1,\"nm\":\"Blanc uni 1\",\"sr\":1,\"ks\":{\"o\":{\"a\":0,\"k\":100,\"ix\":11},\"r\":{\"a\":0,\"k\":0,\"ix\":10},\"p\":{\"a\":0,\"k\":[540,540,0],\"ix\":2,\"l\":2},\"a\":{\"a\":0,\"k\":[540,540,0],\"ix\":1,\"l\":2},\"s\":{\"a\":0,\"k\":[100,100,100],\"ix\":6,\"l\":2}},\"ao\":0,\"sw\":1080,\"sh\":900,\"ip\":0,\"op\":630.000025660426,\"st\":0,\"bm\":0}],\"markers\":[]}"
  },
  {
    "path": "simple_live_tv_app/assets/lotties/loadding.json",
    "content": "{\n    \"v\": \"5.5.8\",\n    \"fr\": 50,\n    \"ip\": 0,\n    \"op\": 147,\n    \"w\": 800,\n    \"h\": 600,\n    \"nm\": \"Paperplane\",\n    \"ddd\": 0,\n    \"assets\": [\n        {\n            \"id\": \"comp_0\",\n            \"layers\": [\n                {\n                    \"ddd\": 0,\n                    \"ind\": 1,\n                    \"ty\": 4,\n                    \"nm\": \"planete Outlines - Group 4\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 38,\n                                    \"s\": [\n                                        50\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.833\n                                        ],\n                                        \"y\": [\n                                            0.833\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.167\n                                        ],\n                                        \"y\": [\n                                            0.167\n                                        ]\n                                    },\n                                    \"t\": 88,\n                                    \"s\": [\n                                        50\n                                    ]\n                                },\n                                {\n                                    \"t\": 120,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 0,\n                            \"k\": 0,\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.833,\n                                        \"y\": 0.833\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.167,\n                                        \"y\": 0.167\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        468.336,\n                                        323.378,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        -29,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        29,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 102,\n                                    \"s\": [\n                                        294.336,\n                                        323.378,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                453.672,\n                                304.756,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                50,\n                                50,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [\n                                                    6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0.741,\n                                                    -0.14\n                                                ],\n                                                [\n                                                    0,\n                                                    0.074\n                                                ],\n                                                [\n                                                    13.484,\n                                                    0\n                                                ],\n                                                [\n                                                    1.669,\n                                                    -0.361\n                                                ],\n                                                [\n                                                    19.79,\n                                                    0\n                                                ],\n                                                [\n                                                    3.317,\n                                                    -19.082\n                                                ],\n                                                [\n                                                    2.691,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -0.048,\n                                                    -0.629\n                                                ],\n                                                [\n                                                    2.405,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.742\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.743\n                                                ]\n                                            ],\n                                            \"o\": [\n                                                [\n                                                    -0.781,\n                                                    0\n                                                ],\n                                                [\n                                                    0.001,\n                                                    -0.074\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -1.778,\n                                                    0\n                                                ],\n                                                [\n                                                    -3.594,\n                                                    -18.742\n                                                ],\n                                                [\n                                                    -20.03,\n                                                    0\n                                                ],\n                                                [\n                                                    -2.421,\n                                                    -0.804\n                                                ],\n                                                [\n                                                    -13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0.642\n                                                ],\n                                                [\n                                                    -1.89,\n                                                    -1.199\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.743\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.742\n                                                ]\n                                            ],\n                                            \"v\": [\n                                                [\n                                                    75.134,\n                                                    16.175\n                                                ],\n                                                [\n                                                    72.85,\n                                                    16.396\n                                                ],\n                                                [\n                                                    72.856,\n                                                    16.175\n                                                ],\n                                                [\n                                                    48.44,\n                                                    -8.241\n                                                ],\n                                                [\n                                                    43.262,\n                                                    -7.685\n                                                ],\n                                                [\n                                                    3.406,\n                                                    -40.591\n                                                ],\n                                                [\n                                                    -36.571,\n                                                    -6.995\n                                                ],\n                                                [\n                                                    -44.269,\n                                                    -8.241\n                                                ],\n                                                [\n                                                    -68.685,\n                                                    16.175\n                                                ],\n                                                [\n                                                    -68.604,\n                                                    18.079\n                                                ],\n                                                [\n                                                    -75.133,\n                                                    16.175\n                                                ],\n                                                [\n                                                    -87.341,\n                                                    28.383\n                                                ],\n                                                [\n                                                    -75.133,\n                                                    40.592\n                                                ],\n                                                [\n                                                    75.134,\n                                                    40.592\n                                                ],\n                                                [\n                                                    87.342,\n                                                    28.383\n                                                ]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.815686334348,\n                                            0.823529471603,\n                                            0.827451040231,\n                                            1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 5\n                                    },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            453.672,\n                                            304.756\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0,\n                                            0\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            100,\n                                            100\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 4\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 2,\n                    \"ty\": 4,\n                    \"nm\": \"Merged Shape Layer\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 0,\n                            \"k\": 100,\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.547\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.845\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 77,\n                                    \"s\": [\n                                        35\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        390.319,\n                                        298.2,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        -2.583,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 44,\n                                    \"s\": [\n                                        390.319,\n                                        282.7,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": 0.667,\n                                        \"y\": 1\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.333,\n                                        \"y\": 0\n                                    },\n                                    \"t\": 110,\n                                    \"s\": [\n                                        390.319,\n                                        319.25,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        0,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        0,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        390.319,\n                                        298.2,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                664.319,\n                                256.2,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                100,\n                                100,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            18.967,\n                                                            -3.189\n                                                        ],\n                                                        [\n                                                            -18.967,\n                                                            19.935\n                                                        ],\n                                                        [\n                                                            -0.949,\n                                                            -19.935\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.223528981209,\n                                                    0.192156970501,\n                                                    0.674510002136,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    236.879,\n                                                    292.737\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 1\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            633.939,\n                                            275.369\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            236.879,\n                                            292.737\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 1\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        },\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            -98.335,\n                                                            64.79\n                                                        ],\n                                                        [\n                                                            -105.619,\n                                                            4.984\n                                                        ],\n                                                        [\n                                                            105.619,\n                                                            -64.79\n                                                        ],\n                                                        [\n                                                            -80.316,\n                                                            24.919\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.278430998325,\n                                                    0.294117987156,\n                                                    0.847059011459,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    316.247,\n                                                    247.882\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 2\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            673.623,\n                                            252.941\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            316.247,\n                                            247.882\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 2\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 2,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        },\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"o\": [\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ],\n                                                        [\n                                                            0,\n                                                            0\n                                                        ]\n                                                    ],\n                                                    \"v\": [\n                                                        [\n                                                            -133.812,\n                                                            -42.171\n                                                        ],\n                                                        [\n                                                            133.812,\n                                                            -75.141\n                                                        ],\n                                                        [\n                                                            5.765,\n                                                            75.141\n                                                        ],\n                                                        [\n                                                            -61.708,\n                                                            18.402\n                                                        ],\n                                                        [\n                                                            124.227,\n                                                            -71.307\n                                                        ],\n                                                        [\n                                                            -87.011,\n                                                            -1.534\n                                                        ]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.365000009537,\n                                                    0.407999992371,\n                                                    0.976000010967,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 5\n                                            },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    297.638,\n                                                    254.4\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0,\n                                                    0\n                                                ],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    100,\n                                                    100\n                                                ],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 6\n                                            },\n                                            \"o\": {\n                                                \"a\": 0,\n                                                \"k\": 100,\n                                                \"ix\": 7\n                                            },\n                                            \"sk\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 4\n                                            },\n                                            \"sa\": {\n                                                \"a\": 0,\n                                                \"k\": 0,\n                                                \"ix\": 5\n                                            },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 3\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            664.319,\n                                            256.2\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            297.638,\n                                            254.4\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            50,\n                                            50\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"planete Outlines - Group 3\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 3,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 3,\n                    \"ty\": 4,\n                    \"nm\": \"planete Outlines - Group 5\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 45,\n                                    \"s\": [\n                                        100\n                                    ]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [\n                                            0.667\n                                        ],\n                                        \"y\": [\n                                            1\n                                        ]\n                                    },\n                                    \"o\": {\n                                        \"x\": [\n                                            0.333\n                                        ],\n                                        \"y\": [\n                                            0\n                                        ]\n                                    },\n                                    \"t\": 102,\n                                    \"s\": [\n                                        100\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 0,\n                            \"k\": 0,\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": 0.833,\n                                        \"y\": 0.833\n                                    },\n                                    \"o\": {\n                                        \"x\": 0.167,\n                                        \"y\": 0.167\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [\n                                        327.38,\n                                        267.583,\n                                        0\n                                    ],\n                                    \"to\": [\n                                        25.833,\n                                        0,\n                                        0\n                                    ],\n                                    \"ti\": [\n                                        -25.833,\n                                        0,\n                                        0\n                                    ]\n                                },\n                                {\n                                    \"t\": 150,\n                                    \"s\": [\n                                        482.38,\n                                        267.583,\n                                        0\n                                    ]\n                                }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": {\n                            \"a\": 0,\n                            \"k\": [\n                                171.76,\n                                193.166,\n                                0\n                            ],\n                            \"ix\": 1\n                        },\n                        \"s\": {\n                            \"a\": 0,\n                            \"k\": [\n                                50,\n                                50,\n                                100\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [\n                                                    13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    4.38,\n                                                    -4.171\n                                                ],\n                                                [\n                                                    21.913,\n                                                    0\n                                                ],\n                                                [\n                                                    3.575,\n                                                    -18.765\n                                                ],\n                                                [\n                                                    1.851,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ],\n                                                [\n                                                    -0.011,\n                                                    -0.291\n                                                ],\n                                                [\n                                                    1.599,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -6.743\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    13.485\n                                                ]\n                                            ],\n                                            \"o\": [\n                                                [\n                                                    -6.526,\n                                                    0\n                                                ],\n                                                [\n                                                    -0.793,\n                                                    -21.719\n                                                ],\n                                                [\n                                                    -19.806,\n                                                    0\n                                                ],\n                                                [\n                                                    -1.734,\n                                                    -0.391\n                                                ],\n                                                [\n                                                    -13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    0.293\n                                                ],\n                                                [\n                                                    -1.4,\n                                                    -0.559\n                                                ],\n                                                [\n                                                    -6.742,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    6.742\n                                                ],\n                                                [\n                                                    0,\n                                                    0\n                                                ],\n                                                [\n                                                    13.485,\n                                                    0\n                                                ],\n                                                [\n                                                    0,\n                                                    -13.484\n                                                ]\n                                            ],\n                                            \"v\": [\n                                                [\n                                                    59.669,\n                                                    -8.242\n                                                ],\n                                                [\n                                                    42.84,\n                                                    -1.506\n                                                ],\n                                                [\n                                                    2.287,\n                                                    -40.592\n                                                ],\n                                                [\n                                                    -37.576,\n                                                    -7.638\n                                                ],\n                                                [\n                                                    -42.962,\n                                                    -8.242\n                                                ],\n                                                [\n                                                    -67.378,\n                                                    16.174\n                                                ],\n                                                [\n                                                    -67.356,\n                                                    17.049\n                                                ],\n                                                [\n                                                    -71.878,\n                                                    16.174\n                                                ],\n                                                [\n                                                    -84.086,\n                                                    28.383\n                                                ],\n                                                [\n                                                    -71.878,\n                                                    40.591\n                                                ],\n                                                [\n                                                    59.669,\n                                                    40.591\n                                                ],\n                                                [\n                                                    84.086,\n                                                    16.174\n                                                ]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.816000007181,\n                                            0.823999980852,\n                                            0.827000038297,\n                                            1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 5\n                                    },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            171.76,\n                                            193.166\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"a\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0,\n                                            0\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            100,\n                                            100\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"r\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 6\n                                    },\n                                    \"o\": {\n                                        \"a\": 0,\n                                        \"k\": 100,\n                                        \"ix\": 7\n                                    },\n                                    \"sk\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 4\n                                    },\n                                    \"sa\": {\n                                        \"a\": 0,\n                                        \"k\": 0,\n                                        \"ix\": 5\n                                    },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 5\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 151,\n                    \"st\": 0,\n                    \"bm\": 0\n                }\n            ]\n        }\n    ],\n    \"layers\": [\n        {\n            \"ddd\": 0,\n            \"ind\": 1,\n            \"ty\": 0,\n            \"nm\": \"Pre-comp 1\",\n            \"refId\": \"comp_0\",\n            \"sr\": 1,\n            \"ks\": {\n                \"o\": {\n                    \"a\": 0,\n                    \"k\": 100,\n                    \"ix\": 11\n                },\n                \"r\": {\n                    \"a\": 0,\n                    \"k\": 0,\n                    \"ix\": 10\n                },\n                \"p\": {\n                    \"a\": 0,\n                    \"k\": [\n                        406,\n                        306,\n                        0\n                    ],\n                    \"ix\": 2\n                },\n                \"a\": {\n                    \"a\": 0,\n                    \"k\": [\n                        400,\n                        300,\n                        0\n                    ],\n                    \"ix\": 1\n                },\n                \"s\": {\n                    \"a\": 0,\n                    \"k\": [\n                        179,\n                        179,\n                        100\n                    ],\n                    \"ix\": 6\n                }\n            },\n            \"ao\": 0,\n            \"w\": 800,\n            \"h\": 600,\n            \"ip\": 0,\n            \"op\": 147,\n            \"st\": 0,\n            \"bm\": 0\n        }\n    ],\n    \"markers\": []\n}"
  },
  {
    "path": "simple_live_tv_app/assets/statement.txt",
    "content": "在使用本软件之前，请您仔细阅读以下内容，并确保您充分理解并同意以下条款：\n1、本软件为开源软件，您可以免费获取并使用该软件。\n2、本软件完全基于您个人意愿使用，您应该对自己的使用行为和所有结果承担全部责任。\n3、本软件仅供学习交流、科研等非商业性质的用途，严禁将本软件用于商业目的。如有任何商业行为，均与本软件无关。\n4、本软件并不保证与所有操作系统或硬件设备兼容。本软件作者或贡献者不对因使用本软件而产生的任何技术或安全问题承担责任。\n5、本软件作者或贡献者不承担因使用本软件而造成的任何直接、间接、特殊或后果性的损失或损害的责任，包括但不限于财产损失、商业利润损失、信息或数据丢失或损坏等。\n6、本软件使用者应遵守国家相关法律法规和使用规范，不得利用本软件从事任何违法违规行为。如因使用本软件而导致的违法行为，使用者应承担相应的法律责任。\n7、本软件不会收集、存储、使用任何用户的个人信息，包括但不限于姓名、地址、电子邮件地址、电话号码等。在使用本软件过程中，不会进行任何形式的个人信息采集。如用户提供任何个人信息，将被视为用户已自愿提供，并且用户将自行承担由此产生的所有法律责任。\n8、本软件作者或贡献者保留随时修改、增加、删除本免责声明中的内容而不另行通知的权利。\n9、如果本软件存在侵犯您的合法权益的情况，请及时与作者联系，作者将会及时删除有关内容。\n如您不同意本免责声明中的任何内容，请勿使用本软件。使用本软件即代表您已完全理解并同意上述内容。"
  },
  {
    "path": "simple_live_tv_app/lib/app/app_error.dart",
    "content": "class AppError extends Error {\n  /// 错误码\n  final int code;\n\n  /// 错误信息\n  final String message;\n\n  /// 是否是Http请求错误\n  final bool isHttpError;\n\n  final bool notLogin;\n\n  AppError(\n    this.message, {\n    this.code = 0,\n    this.isHttpError = false,\n    this.notLogin = false,\n  });\n  @override\n  String toString() {\n    return message;\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/app_focus_node.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';\n\n/// 拓展FoucsNode\nclass AppFocusNode extends FocusNode {\n  var isFoucsed = false.obs;\n  AppFocusNode() {\n    isFoucsed.value = hasFocus;\n    addListener(updateFoucs);\n  }\n\n  void updateFoucs() {\n    isFoucsed.value = hasFocus;\n  }\n\n  @override\n  void dispose() {\n    removeListener(updateFoucs);\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/app_style.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\n\nclass AppColors {\n  static ColorScheme lightColorScheme = ColorScheme.fromSwatch(\n    primarySwatch: Colors.pink,\n    brightness: Brightness.dark,\n    //primaryColorDark: const Color(0xfff06595),\n    accentColor: const Color(0xfff06595),\n  );\n}\n\nclass AppStyle {\n  static ThemeData lightTheme = ThemeData(\n    colorScheme: AppColors.lightColorScheme,\n    appBarTheme: const AppBarTheme(\n      elevation: 0,\n      centerTitle: true,\n    ),\n    scaffoldBackgroundColor: const Color(0xfffafafa),\n    radioTheme: RadioThemeData(\n      fillColor: WidgetStateProperty.all(AppColors.lightColorScheme.primary),\n    ),\n    checkboxTheme: CheckboxThemeData(\n      fillColor: WidgetStateProperty.all(AppColors.lightColorScheme.primary),\n    ),\n    fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null,\n  );\n\n  static SizedBox get vGap4 => SizedBox(\n        height: 4.w,\n      );\n  static SizedBox get vGap8 => SizedBox(\n        height: 8.w,\n      );\n  static SizedBox get vGap12 => SizedBox(\n        height: 12.w,\n      );\n  static SizedBox get vGap16 => SizedBox(\n        height: 16.w,\n      );\n  static SizedBox get vGap24 => SizedBox(\n        height: 24.w,\n      );\n  static SizedBox get vGap32 => SizedBox(\n        height: 32.w,\n      );\n  static SizedBox get vGap40 => SizedBox(\n        height: 40.w,\n      );\n  static SizedBox get vGap48 => SizedBox(\n        height: 48.w,\n      );\n  static SizedBox get hGap4 => SizedBox(\n        width: 4.w,\n      );\n  static SizedBox get hGap8 => SizedBox(\n        width: 8.w,\n      );\n  static SizedBox get hGap12 => SizedBox(\n        width: 12.w,\n      );\n  static SizedBox get hGap16 => SizedBox(\n        width: 16.w,\n      );\n  static SizedBox get hGap20 => SizedBox(\n        width: 20.w,\n      );\n  static SizedBox get hGap24 => SizedBox(\n        width: 24.w,\n      );\n  static SizedBox get hGap32 => SizedBox(\n        width: 32.w,\n      );\n  static SizedBox get hGap40 => SizedBox(\n        width: 40.w,\n      );\n  static SizedBox get hGap48 => SizedBox(\n        width: 48.w,\n      );\n\n  static EdgeInsets get edgeInsetsH4 => EdgeInsets.symmetric(horizontal: 4.w);\n  static EdgeInsets get edgeInsetsH8 => EdgeInsets.symmetric(horizontal: 8.w);\n  static EdgeInsets get edgeInsetsH12 => EdgeInsets.symmetric(horizontal: 12.w);\n  static EdgeInsets get edgeInsetsH16 => EdgeInsets.symmetric(horizontal: 16.w);\n  static EdgeInsets get edgeInsetsH20 => EdgeInsets.symmetric(horizontal: 20.w);\n  static EdgeInsets get edgeInsetsH24 => EdgeInsets.symmetric(horizontal: 24.w);\n  static EdgeInsets get edgeInsetsH32 => EdgeInsets.symmetric(horizontal: 32.w);\n  static EdgeInsets get edgeInsetsH40 => EdgeInsets.symmetric(horizontal: 40.w);\n  static EdgeInsets get edgeInsetsH48 => EdgeInsets.symmetric(horizontal: 48.w);\n\n  static EdgeInsets get edgeInsetsV4 => EdgeInsets.symmetric(vertical: 4.w);\n  static EdgeInsets get edgeInsetsV8 => EdgeInsets.symmetric(vertical: 8.w);\n  static EdgeInsets get edgeInsetsV12 => EdgeInsets.symmetric(vertical: 12.w);\n  static EdgeInsets get edgeInsetsV24 => EdgeInsets.symmetric(vertical: 24.w);\n  static EdgeInsets get edgeInsetsV32 => EdgeInsets.symmetric(vertical: 32.w);\n  static EdgeInsets get edgeInsetsV40 => EdgeInsets.symmetric(vertical: 40.w);\n  static EdgeInsets get edgeInsetsV48 => EdgeInsets.symmetric(vertical: 48.w);\n\n  static EdgeInsets get edgeInsetsA4 => EdgeInsets.all(4.w);\n  static EdgeInsets get edgeInsetsA8 => EdgeInsets.all(8.w);\n  static EdgeInsets get edgeInsetsA12 => EdgeInsets.all(12.w);\n  static EdgeInsets get edgeInsetsA16 => EdgeInsets.all(16.w);\n  static EdgeInsets get edgeInsetsA20 => EdgeInsets.all(20.w);\n  static EdgeInsets get edgeInsetsA24 => EdgeInsets.all(24.w);\n  static EdgeInsets get edgeInsetsA32 => EdgeInsets.all(32.w);\n  static EdgeInsets get edgeInsetsA40 => EdgeInsets.all(40.w);\n  static EdgeInsets get edgeInsetsA48 => EdgeInsets.all(48.w);\n\n  static EdgeInsets get edgeInsetsR4 => EdgeInsets.only(right: 4.w);\n  static EdgeInsets get edgeInsetsR8 => EdgeInsets.only(right: 8.w);\n  static EdgeInsets get edgeInsetsR12 => EdgeInsets.only(right: 12.w);\n  static EdgeInsets get edgeInsetsR16 => EdgeInsets.only(right: 16.w);\n  static EdgeInsets get edgeInsetsR20 => EdgeInsets.only(right: 20.w);\n  static EdgeInsets get edgeInsetsR24 => EdgeInsets.only(right: 24.w);\n\n  static EdgeInsets get edgeInsetsL4 => EdgeInsets.only(left: 4.w);\n  static EdgeInsets get edgeInsetsL8 => EdgeInsets.only(left: 8.w);\n  static EdgeInsets get edgeInsetsL12 => EdgeInsets.only(left: 12.w);\n  static EdgeInsets get edgeInsetsL16 => EdgeInsets.only(left: 16.w);\n  static EdgeInsets get edgeInsetsL20 => EdgeInsets.only(left: 20.w);\n  static EdgeInsets get edgeInsetsL24 => EdgeInsets.only(left: 24.w);\n\n  static EdgeInsets get edgeInsetsT4 => EdgeInsets.only(top: 4.w);\n  static EdgeInsets get edgeInsetsT8 => EdgeInsets.only(top: 8.w);\n  static EdgeInsets get edgeInsetsT12 => EdgeInsets.only(top: 12.w);\n  static EdgeInsets get edgeInsetsT24 => EdgeInsets.only(top: 24.w);\n\n  static EdgeInsets get edgeInsetsB4 => EdgeInsets.only(bottom: 4.w);\n  static EdgeInsets get edgeInsetsB8 => EdgeInsets.only(bottom: 8.w);\n  static EdgeInsets get edgeInsetsB12 => EdgeInsets.only(bottom: 12.w);\n  static EdgeInsets get edgeInsetsB24 => EdgeInsets.only(bottom: 24.w);\n\n  static BorderRadius get radius4 => BorderRadius.circular(4.w);\n  static BorderRadius get radius8 => BorderRadius.circular(8.w);\n  static BorderRadius get radius12 => BorderRadius.circular(12.w);\n  static BorderRadius get radius16 => BorderRadius.circular(16.w);\n  static BorderRadius get radius24 => BorderRadius.circular(24.w);\n  static BorderRadius get radius32 => BorderRadius.circular(32.w);\n  static BorderRadius get radius48 => BorderRadius.circular(48.w);\n\n  static const colorBlack33 = Color(0xff333333);\n\n  /// 顶部状态栏的高度\n  static double get statusBarHeight => MediaQuery.of(Get.context!).padding.top;\n\n  /// 底部导航条的高度\n  static double get bottomBarHeight =>\n      MediaQuery.of(Get.context!).padding.bottom;\n\n  static TextStyle get titleStyleWhite => TextStyle(\n        color: Colors.white,\n        fontSize: 40.w,\n      );\n  static TextStyle get titleStyleBlack => TextStyle(\n        color: colorBlack33,\n        fontSize: 40.w,\n      );\n  static TextStyle get textStyleWhite => TextStyle(\n        color: Colors.white,\n        fontSize: 32.w,\n      );\n  static TextStyle get textStyleBlack => TextStyle(\n        color: colorBlack33,\n        fontSize: 32.w,\n      );\n  static TextStyle get subTextStyleWhite => TextStyle(\n        color: Colors.white54,\n        fontSize: 24.w,\n        height: 1.0,\n      );\n  static TextStyle get subTextStyleBlack => TextStyle(\n        color: Colors.black54,\n        fontSize: 24.w,\n        height: 1.0,\n      );\n\n  static List<BoxShadow> get highlightShadow => [\n        BoxShadow(\n          blurRadius: 6.w,\n          spreadRadius: 2.w,\n          color: Colors.pink.shade400,\n          //color: Color.fromARGB(255, 255, 120, 167),\n        )\n      ];\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/base_focus_model.dart",
    "content": "import 'package:simple_live_tv_app/app/app_focus_node.dart';\n\nclass BaseFocusModel {\n  final AppFocusNode focusNode = AppFocusNode();\n  bool get isFoucsed => focusNode.isFoucsed.value;\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/constant.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass Constant {\n  static const String kUpdateFollow = \"UpdateFollow\";\n  static const String kUpdateHistory = \"UpdateHistory\";\n\n  static const String kBiliBili = \"bilibili\";\n  static const String kDouyu = \"douyu\";\n  static const String kHuya = \"huya\";\n  static const String kDouyin = \"douyin\";\n}\n\nclass HomePageItem {\n  final IconData iconData;\n  final String title;\n  final int index;\n  HomePageItem({\n    required this.iconData,\n    required this.title,\n    required this.index,\n  });\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/controller/app_settings_controller.dart",
    "content": "import 'package:simple_live_tv_app/services/local_storage_service.dart';\n\nimport 'package:get/get.dart';\n\nclass AppSettingsController extends GetxController {\n  static AppSettingsController get instance =>\n      Get.find<AppSettingsController>();\n\n  /// 缩放模式\n  var scaleMode = 0.obs;\n\n  var firstRun = false;\n\n  @override\n  void onInit() {\n    firstRun = LocalStorageService.instance\n        .getValue(LocalStorageService.kFirstRun, true);\n    danmuSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuSize, 40.0);\n    danmuOpacity.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuOpacity, 1.0);\n    danmuArea.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuArea, 0.25);\n    danmuSpeed.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuSpeed, 10.0);\n    danmuEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuEnable, true);\n    danmuStrokeWidth.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuStrokeWidth, 4.0);\n    danmuTopMargin.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuTopMargin, 0.0);\n    danmuBottomMargin.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kDanmuBottomMargin, 0.0);\n\n    hardwareDecode.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kHardwareDecode, true);\n    chatTextSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kChatTextSize, 14.0);\n\n    chatTextGap.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kChatTextGap, 4.0);\n\n    chatBubbleStyle.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kChatBubbleStyle,\n      false,\n    );\n\n    qualityLevel.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kQualityLevel, 1);\n    qualityLevelCellular.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kQualityLevelCellular, 1);\n\n    autoExitEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoExitEnable, false);\n\n    autoExitDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoExitDuration, 60);\n\n    roomAutoExitDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kRoomAutoExitDuration, 60);\n\n    playerCompatMode.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerCompatMode, true);\n\n    playerAutoPause.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerAutoPause, false);\n\n    autoFullScreen.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoFullScreen, false);\n\n    // ignore: invalid_use_of_protected_member\n    shieldList.value = LocalStorageService.instance.shieldBox.values.toSet();\n\n    scaleMode.value = LocalStorageService.instance.getValue(\n      LocalStorageService.kPlayerScaleMode,\n      0,\n    );\n\n    pipHideDanmu.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPIPHideDanmu, true);\n\n    styleColor.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kStyleColor, 0xff3498db);\n\n    isDynamic.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kIsDynamic, false);\n\n    bilibiliLoginTip.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kBilibiliLoginTip, true);\n\n    playerBufferSize.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kPlayerBufferSize, 32);\n\n    autoUpdateFollowEnable.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kAutoUpdateFollowEnable, true);\n\n    autoUpdateFollowDuration.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kUpdateFollowDuration, 10);\n\n    updateFollowThreadCount.value = LocalStorageService.instance\n        .getValue(LocalStorageService.kUpdateFollowThreadCount, 4);\n\n    super.onInit();\n  }\n\n  void setNoFirstRun() {\n    LocalStorageService.instance.setValue(LocalStorageService.kFirstRun, false);\n  }\n\n  var hardwareDecode = true.obs;\n  void setHardwareDecode(bool e) {\n    hardwareDecode.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kHardwareDecode, e);\n  }\n\n  var chatTextSize = 14.0.obs;\n  void setChatTextSize(double e) {\n    chatTextSize.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kChatTextSize, e);\n  }\n\n  var chatTextGap = 4.0.obs;\n  void setChatTextGap(double e) {\n    chatTextGap.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kChatTextGap, e);\n  }\n\n  var chatBubbleStyle = false.obs;\n  void setChatBubbleStyle(bool e) {\n    chatBubbleStyle.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kChatBubbleStyle, e);\n  }\n\n  var danmuSize = 40.0.obs;\n  void setDanmuSize(double e) {\n    danmuSize.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuSize, e);\n  }\n\n  var danmuSpeed = 10.0.obs;\n  void setDanmuSpeed(double e) {\n    danmuSpeed.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuSpeed, e);\n  }\n\n  var danmuArea = 0.25.obs;\n  void setDanmuArea(double e) {\n    danmuArea.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuArea, e);\n  }\n\n  var danmuOpacity = 1.0.obs;\n  void setDanmuOpacity(double e) {\n    danmuOpacity.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuOpacity, e);\n  }\n\n  var danmuEnable = true.obs;\n  void setDanmuEnable(bool e) {\n    danmuEnable.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kDanmuEnable, e);\n  }\n\n  var danmuStrokeWidth = 4.0.obs;\n  void setDanmuStrokeWidth(double e) {\n    danmuStrokeWidth.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuStrokeWidth, e);\n  }\n\n  var qualityLevel = 1.obs;\n  void setQualityLevel(int level) {\n    qualityLevel.value = level;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kQualityLevel, level);\n  }\n\n  var qualityLevelCellular = 1.obs;\n  void setQualityLevelCellular(int level) {\n    qualityLevelCellular.value = level;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kQualityLevelCellular, level);\n  }\n\n  var autoExitEnable = false.obs;\n  void setAutoExitEnable(bool e) {\n    autoExitEnable.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoExitEnable, e);\n  }\n\n  var autoExitDuration = 60.obs;\n  void setAutoExitDuration(int e) {\n    autoExitDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoExitDuration, e);\n  }\n\n  var roomAutoExitDuration = 60.obs;\n  void setRoomAutoExitDuration(int e) {\n    roomAutoExitDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kRoomAutoExitDuration, e);\n  }\n\n  var playerCompatMode = false.obs;\n  void setPlayerCompatMode(bool e) {\n    playerCompatMode.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerCompatMode, e);\n  }\n\n  var playerBufferSize = 32.obs;\n  void setPlayerBufferSize(int e) {\n    playerBufferSize.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerBufferSize, e);\n  }\n\n  var playerAutoPause = false.obs;\n  void setPlayerAutoPause(bool e) {\n    playerAutoPause.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kPlayerAutoPause, e);\n  }\n\n  var autoFullScreen = false.obs;\n  void setAutoFullScreen(bool e) {\n    autoFullScreen.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoFullScreen, e);\n  }\n\n  RxSet<String> shieldList = <String>{}.obs;\n  void addShieldList(String e) {\n    shieldList.add(e);\n    LocalStorageService.instance.shieldBox.put(e, e);\n  }\n\n  void removeShieldList(String e) {\n    shieldList.remove(e);\n    LocalStorageService.instance.shieldBox.delete(e);\n  }\n\n  Future clearShieldList() async {\n    shieldList.clear();\n    await LocalStorageService.instance.shieldBox.clear();\n  }\n\n  void setScaleMode(int value) {\n    scaleMode.value = value;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kPlayerScaleMode,\n      value,\n    );\n  }\n\n  RxList<String> siteSort = RxList<String>();\n  void setSiteSort(List<String> e) {\n    siteSort.value = e;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kSiteSort,\n      siteSort.join(\",\"),\n    );\n  }\n\n  RxList<String> homeSort = RxList<String>();\n  void setHomeSort(List<String> e) {\n    homeSort.value = e;\n    LocalStorageService.instance.setValue(\n      LocalStorageService.kHomeSort,\n      homeSort.join(\",\"),\n    );\n  }\n\n  var pipHideDanmu = true.obs;\n  void setPIPHideDanmu(bool e) {\n    pipHideDanmu.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kPIPHideDanmu, e);\n  }\n\n  var styleColor = 0xff3498db.obs;\n  void setStyleColor(int e) {\n    styleColor.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kStyleColor, e);\n  }\n\n  var isDynamic = false.obs;\n  void setIsDynamic(bool e) {\n    isDynamic.value = e;\n    LocalStorageService.instance.setValue(LocalStorageService.kIsDynamic, e);\n  }\n\n  var danmuTopMargin = 0.0.obs;\n  void setDanmuTopMargin(double e) {\n    danmuTopMargin.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuTopMargin, e);\n  }\n\n  var danmuBottomMargin = 0.0.obs;\n  void setDanmuBottomMargin(double e) {\n    danmuBottomMargin.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kDanmuBottomMargin, e);\n  }\n\n  var bilibiliLoginTip = true.obs;\n  void setBiliBiliLoginTip(bool e) {\n    bilibiliLoginTip.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliLoginTip, e);\n  }\n\n  var autoUpdateFollowEnable = false.obs;\n  void setAutoUpdateFollowEnable(bool e) {\n    autoUpdateFollowEnable.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kAutoUpdateFollowEnable, e);\n  }\n\n  var autoUpdateFollowDuration = 10.obs;\n  void setAutoUpdateFollowDuration(int e) {\n    autoUpdateFollowDuration.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kUpdateFollowDuration, e);\n  }\n\n  var updateFollowThreadCount = 4.obs;\n  void setUpdateFollowThreadCount(int e) {\n    updateFollowThreadCount.value = e;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kUpdateFollowThreadCount, e);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/controller/base_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/widgets.dart';\nimport 'package:simple_live_tv_app/app/app_error.dart';\n\nimport 'package:flutter_easyrefresh/easy_refresh.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\n\nclass BaseController extends GetxController {\n  /// 加载中，更新页面\n  var pageLoadding = false.obs;\n\n  /// 加载中\n  var loadding = false.obs;\n\n  /// 空白页面\n  var pageEmpty = false.obs;\n\n  /// 页面错误\n  var pageError = false.obs;\n\n  /// 未登录\n  var notLogin = false.obs;\n\n  /// 错误信息\n  var errorMsg = \"\".obs;\n\n  /// 显示错误\n  /// * [msg] 错误信息\n  /// * [showPageError] 显示页面错误\n  /// * 只在第一页加载错误时showPageError=true，后续页加载错误时使用Toast弹出通知\n  void handleError(Object exception, {bool showPageError = false}) {\n    var msg = exceptionToString(exception);\n    if (exception is AppError && exception.notLogin) {\n      notLogin.value = true;\n      pageError.value = false;\n      return;\n    }\n    if (showPageError) {\n      pageError.value = true;\n      errorMsg.value = msg;\n    } else {\n      SmartDialog.showToast(exceptionToString(msg));\n    }\n  }\n\n  String exceptionToString(Object exception) {\n    if (exception is AppError) {\n      return exception.toString();\n    }\n    return exception.toString().replaceAll(\"Exception:\", \"\");\n  }\n\n  void onLogin() {}\n  void onLogout() {}\n}\n\nclass BasePageController<T> extends BaseController {\n  final ScrollController scrollController = ScrollController();\n  final EasyRefreshController easyRefreshController = EasyRefreshController();\n  int currentPage = 1;\n  int count = 0;\n  int maxPage = 0;\n  int pageSize = 24;\n  var canLoadMore = false.obs;\n  var list = <T>[].obs;\n\n  Future refreshData() async {\n    currentPage = 1;\n    list.value = [];\n    await loadData();\n  }\n\n  Future loadData() async {\n    try {\n      if (loadding.value) return;\n      loadding.value = true;\n      pageError.value = false;\n      pageEmpty.value = false;\n      notLogin.value = false;\n      pageLoadding.value = currentPage == 1;\n\n      var result = await getData(currentPage, pageSize);\n      //是否可以加载更多\n      if (result.isNotEmpty) {\n        currentPage++;\n        canLoadMore.value = true;\n        pageEmpty.value = false;\n      } else {\n        canLoadMore.value = false;\n        if (currentPage == 1) {\n          pageEmpty.value = true;\n        }\n      }\n      // 赋值数据\n      if (currentPage == 1) {\n        list.value = result;\n      } else {\n        list.addAll(result);\n      }\n    } catch (e) {\n      handleError(e, showPageError: currentPage == 1);\n    } finally {\n      loadding.value = false;\n      pageLoadding.value = false;\n    }\n  }\n\n  Future<List<T>> getData(int page, int pageSize) async {\n    return [];\n  }\n\n  void scrollToTopOrRefresh() {\n    if (scrollController.offset > 0) {\n      scrollController.animateTo(\n        0,\n        duration: const Duration(milliseconds: 200),\n        curve: Curves.linear,\n      );\n    } else {\n      easyRefreshController.callRefresh();\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/event_bus.dart",
    "content": "import 'dart:async';\n\nimport 'package:simple_live_tv_app/app/log.dart';\n\n/// 全局事件\nclass EventBus {\n  static EventBus? _instance;\n\n  static EventBus get instance {\n    _instance ??= EventBus();\n    return _instance!;\n  }\n\n  final Map<String, StreamController> _streams = {};\n\n  /// 触发事件\n  void emit<T>(String name, T data) {\n    if (!_streams.containsKey(name)) {\n      _streams.addAll({name: StreamController.broadcast()});\n    }\n    Log.d(\"Emit Event：$name\\r\\n$data\");\n\n    _streams[name]!.add(data);\n  }\n\n  /// 监听事件\n  StreamSubscription<dynamic> listen(String name, Function(dynamic)? onData) {\n    if (!_streams.containsKey(name)) {\n      _streams.addAll({name: StreamController.broadcast()});\n    }\n    return _streams[name]!.stream.listen(onData);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/log.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:logger/logger.dart';\n\nclass Log {\n  static RxList<DebugLogModel> debugLogs = <DebugLogModel>[].obs;\n\n  static Logger logger = Logger(\n    printer: PrettyPrinter(\n      methodCount: 0,\n      errorMethodCount: 8,\n      lineLength: 120,\n      colors: true,\n      printEmojis: true,\n      dateTimeFormat: DateTimeFormat.none,\n    ),\n  );\n\n  static void d(String message) {\n    logger.d(\"${DateTime.now().toString()}\\n$message\");\n  }\n\n  static void i(String message) {\n    logger.i(\"${DateTime.now().toString()}\\n$message\");\n  }\n\n  static void e(String message, StackTrace stackTrace) {\n    logger.e(\"${DateTime.now().toString()}\\n$message\", stackTrace: stackTrace);\n  }\n\n  static void w(String message) {\n    logger.w(\"${DateTime.now().toString()}\\n$message\");\n  }\n\n  static void logPrint(dynamic obj) {\n    //logger.e(obj.toString(), obj, obj?.stackTrace);\n    if (kDebugMode) {\n      print(obj);\n    }\n  }\n}\n\nclass DebugLogModel {\n  final String content;\n  final DateTime datetime;\n  final Color? color;\n  DebugLogModel(this.datetime, this.content, {this.color});\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/sites.dart",
    "content": "import 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\n\nclass Sites {\n  static final Map<String, Site> allSites = {\n    \"bilibili\": Site(\n      id: \"bilibili\",\n      logo: \"assets/images/bilibili_2.png\",\n      name: \"哔哩哔哩\",\n      liveSite: BiliBiliSite(),\n      index: 0,\n    ),\n    \"douyu\": Site(\n      id: \"douyu\",\n      logo: \"assets/images/douyu.png\",\n      name: \"斗鱼直播\",\n      liveSite: DouyuSite(),\n      index: 1,\n    ),\n    \"huya\": Site(\n      id: \"huya\",\n      logo: \"assets/images/huya.png\",\n      name: \"虎牙直播\",\n      liveSite: HuyaSite(),\n      index: 2,\n    ),\n    \"douyin\": Site(\n      id: \"douyin\",\n      logo: \"assets/images/douyin.png\",\n      name: \"抖音直播\",\n      liveSite: DouyinSite(),\n      index: 3,\n    ),\n  };\n\n  static List<Site> get supportSites {\n    return allSites.values.toList();\n  }\n}\n\nclass Site {\n  final String id;\n  final String name;\n  final String logo;\n  final LiveSite liveSite;\n  final int index;\n  AppFocusNode appFocusNode = AppFocusNode();\n  Site({\n    required this.id,\n    required this.liveSite,\n    required this.logo,\n    required this.name,\n    required this.index,\n  });\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/app/utils.dart",
    "content": "import 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:intl/intl.dart';\nimport 'package:package_info_plus/package_info_plus.dart';\n\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/requests/common_request.dart';\n\nclass Utils {\n  static late PackageInfo packageInfo;\n  static DateFormat dateFormat = DateFormat(\"MM-dd HH:mm\");\n  static DateFormat dateFormatWithYear = DateFormat(\"yyyy-MM-dd HH:mm\");\n\n  /// 处理时间\n  static String parseTime(DateTime? dt) {\n    if (dt == null) {\n      return \"\";\n    }\n\n    var dtNow = DateTime.now();\n    if (dt.year == dtNow.year &&\n        dt.month == dtNow.month &&\n        dt.day == dtNow.day) {\n      return \"${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}\";\n    }\n\n    if (dt.year == dtNow.year) {\n      return dateFormat.format(dt);\n    }\n\n    return dateFormatWithYear.format(dt);\n  }\n\n  /// 提示弹窗\n  /// - `content` 内容\n  /// - `title` 弹窗标题\n  /// - `confirm` 确认按钮内容，留空为确定\n  /// - `cancel` 取消按钮内容，留空为取消\n  static Future<bool> showAlertDialog(\n    String content, {\n    String title = '',\n    String confirm = '',\n    String cancel = '',\n    bool selectable = false,\n    List<Widget>? actions,\n  }) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        shape: RoundedRectangleBorder(\n          borderRadius: AppStyle.radius16,\n        ),\n        titlePadding: AppStyle.edgeInsetsA24.copyWith(left: 48.w, right: 48.w),\n        contentPadding:\n            AppStyle.edgeInsetsA24.copyWith(left: 48.w, right: 48.w),\n        insetPadding: AppStyle.edgeInsetsA16,\n        actionsPadding: AppStyle.edgeInsetsA16,\n        surfaceTintColor: Colors.transparent,\n        backgroundColor: Get.theme.cardColor,\n        title: Text(\n          title,\n          style: AppStyle.titleStyleWhite,\n        ),\n        content: Padding(\n          padding: AppStyle.edgeInsetsV12,\n          child: selectable\n              ? SelectableText(\n                  content,\n                  style: AppStyle.textStyleWhite,\n                )\n              : Text(\n                  content,\n                  style: AppStyle.textStyleWhite,\n                ),\n        ),\n        actions: [\n          TextButton(\n            onPressed: (() => Get.back(result: false)),\n            child: Text(\n              cancel.isEmpty ? \"取消\" : cancel,\n              style: AppStyle.textStyleWhite,\n            ),\n          ),\n          TextButton(\n            autofocus: true,\n            onPressed: (() => Get.back(result: true)),\n            child: Text(\n              confirm.isEmpty ? \"确定\" : confirm,\n              style: AppStyle.textStyleWhite,\n            ),\n          ),\n          ...?actions,\n        ],\n      ),\n    );\n    return result ?? false;\n  }\n\n  /// 提示弹窗\n  /// - `content` 内容\n  /// - `title` 弹窗标题\n  /// - `confirm` 确认按钮内容，留空为确定\n  static Future<bool> showMessageDialog(String content,\n      {String title = '', String confirm = '', bool selectable = false}) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: Padding(\n          padding: AppStyle.edgeInsetsV12,\n          child: selectable ? SelectableText(content) : Text(content),\n        ),\n        actions: [\n          TextButton(\n            onPressed: (() => Get.back(result: true)),\n            child: Text(confirm.isEmpty ? \"确定\" : confirm),\n          ),\n        ],\n      ),\n    );\n    return result ?? false;\n  }\n\n  static Future<T?> showOptionDialog<T>(\n    List<T> contents,\n    T value, {\n    String title = '',\n  }) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: RadioGroup(\n          onChanged: (e) => Get.back(result: e),\n          groupValue: value,\n          child: Column(\n            children: contents\n                .map(\n                  (e) => RadioListTile<T>(title: Text(e.toString()), value: e),\n                )\n                .toList(),\n          ),\n        ),\n      ),\n    );\n    return result;\n  }\n\n  static Future<T?> showMapOptionDialog<T>(\n    Map<T, String> contents,\n    T value, {\n    String title = '',\n  }) async {\n    var result = await Get.dialog(\n      AlertDialog(\n        title: Text(title),\n        content: RadioGroup(\n          onChanged: (e) => Get.back(result: e),\n          groupValue: value,\n          child: Column(\n            children: contents.keys\n                .map(\n                  (e) => RadioListTile<T>(\n                    title: Text((contents[e] ?? '-').tr),\n                    value: e,\n                  ),\n                )\n                .toList(),\n          ),\n        ),\n      ),\n    );\n    return result;\n  }\n\n  static bool isRegexFormat(String keyword) {\n    return keyword.startsWith('/') &&\n        keyword.endsWith('/') &&\n        keyword.length > 2;\n  }\n\n  static String removeRegexFormat(String keyword) {\n    return keyword.substring(1, keyword.length - 1);\n  }\n\n  static void showRightDialog({\n    Function()? onDismiss,\n    required Widget child,\n    double width = 320,\n    bool useSystem = false,\n  }) {\n    SmartDialog.show(\n      alignment: Alignment.topRight,\n      animationBuilder: (controller, child, animationParam) {\n        //从右到左\n        return SlideTransition(\n          position: Tween<Offset>(\n            begin: const Offset(1, 0),\n            end: Offset.zero,\n          ).animate(controller.view),\n          child: child,\n        );\n      },\n      useSystem: useSystem,\n      maskColor: Colors.transparent,\n      animationTime: const Duration(milliseconds: 200),\n      builder: (context) => Container(\n        width: width,\n        decoration: BoxDecoration(\n          color: Get.theme.cardColor,\n        ),\n        child: child,\n      ),\n    );\n  }\n\n  static Future<void> showSystemRightDialog({\n    Function()? onDismiss,\n    required Widget child,\n    double width = 320,\n  }) {\n    return Get.dialog(\n      Dialog(\n        insetPadding: EdgeInsets.zero,\n        backgroundColor: Colors.transparent,\n        child: Align(\n          alignment: Alignment.topRight,\n          child: Container(\n            width: width,\n            decoration: BoxDecoration(\n              color: Get.theme.cardColor,\n            ),\n            child: child,\n          ),\n        ),\n      ),\n    );\n  }\n\n  static void hideRightDialog() {\n    SmartDialog.dismiss(status: SmartStatus.allCustom);\n  }\n\n  static void checkUpdate({bool showMsg = false}) async {\n    try {\n      int currentVer = Utils.parseVersion(packageInfo.version);\n      CommonRequest request = CommonRequest();\n      var versionInfo = await request.checkUpdate();\n      if (versionInfo.versionNum > currentVer) {\n        await showAlertDialog(\n          \"${versionInfo.versionDesc}\\n\\n请前往项目主页手动下载新版本\",\n          title: \"发现新版本 ${versionInfo.version}\",\n          confirm: \"知道了\",\n          cancel: \"关闭\",\n        );\n      } else {\n        if (showMsg) {\n          SmartDialog.showToast(\"当前已经是最新版本了\");\n        }\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      if (showMsg) {\n        SmartDialog.showToast(\"检查更新失败\");\n      }\n    }\n  }\n\n  static int parseVersion(String version) {\n    var sp = version.split('.');\n    var num = \"\";\n    for (var item in sp) {\n      num = num + item.padLeft(2, '0');\n    }\n    return int.parse(num);\n  }\n\n  static String onlineToString(int num) {\n    if (num >= 10000) {\n      return \"${(num / 10000.0).toStringAsFixed(1)}万\";\n    }\n    return num.toString();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/main.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:hive_flutter/hive_flutter.dart';\nimport 'package:logger/logger.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:package_info_plus/package_info_plus.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\nimport 'package:simple_live_tv_app/models/db/history.dart';\nimport 'package:simple_live_tv_app/routes/app_pages.dart';\nimport 'package:simple_live_tv_app/routes/route_path.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\nimport 'package:simple_live_tv_app/services/local_storage_service.dart';\nimport 'package:simple_live_tv_app/services/sync_service.dart';\n\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  MediaKit.ensureInitialized();\n  await Hive.initFlutter();\n  //初始化服务\n  await initServices();\n  // 强制横屏\n  SystemChrome.setPreferredOrientations([\n    DeviceOrientation.landscapeRight,\n    DeviceOrientation.landscapeLeft,\n  ]);\n  // 全屏\n  SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);\n  runApp(const MyApp());\n}\n\nFuture initServices() async {\n  //日志信息\n  CoreLog.enableLog = !kReleaseMode;\n  CoreLog.requestLogType = RequestLogType.short;\n  CoreLog.onPrintLog = (level, msg) {\n    switch (level) {\n      case Level.debug:\n        Log.d(msg);\n        break;\n      case Level.error:\n        Log.e(msg, StackTrace.current);\n        break;\n      case Level.info:\n        Log.i(msg);\n        break;\n      case Level.warning:\n        Log.w(msg);\n        break;\n      default:\n        Log.logPrint(msg);\n    }\n  };\n\n  Hive.registerAdapter(FollowUserAdapter());\n  Hive.registerAdapter(HistoryAdapter());\n\n  //包信息\n  Utils.packageInfo = await PackageInfo.fromPlatform();\n  //本地存储\n  Log.d(\"Init LocalStorage Service\");\n  await Get.put(LocalStorageService()).init();\n  await Get.put(DBService()).init();\n  //初始化设置控制器\n  Get.put(AppSettingsController());\n\n  Get.put(BiliBiliAccountService());\n\n  Get.put(SyncService());\n\n  Get.put(FollowUserService());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return ScreenUtilInit(\n      designSize: const Size(1920, 1080),\n      minTextAdapt: true,\n      splitScreenMode: true,\n      builder: (context, child) {\n        return GetMaterialApp(\n          title: 'Simple Live TV',\n          theme: AppStyle.lightTheme,\n          initialRoute: AppSettingsController.instance.firstRun\n              ? RoutePath.kAgreement\n              : RoutePath.kHome,\n          getPages: AppPages.routes,\n          debugShowCheckedModeBanner: false,\n          builder: FlutterSmartDialog.init(\n            loadingBuilder: (msg) => Center(\n              child: SizedBox(\n                width: 64.w,\n                height: 64.w,\n                child: CircularProgressIndicator(\n                  strokeWidth: 8.w,\n                  color: Colors.white,\n                ),\n              ),\n            ),\n            //字体大小不跟随系统变化\n            builder: (context, child) => MediaQuery(\n              data: MediaQuery.of(context).copyWith(\n                textScaler: const TextScaler.linear(1.0),\n              ),\n              child: child!,\n            ),\n          ),\n        );\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/account/bilibili_user_info_page.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass BiliBiliUserInfoModel {\n  BiliBiliUserInfoModel({\n    this.mid,\n    this.uname,\n    this.userid,\n    this.sign,\n    this.birthday,\n    this.sex,\n    this.nickFree,\n    this.rank,\n  });\n\n  factory BiliBiliUserInfoModel.fromJson(Map<String, dynamic> json) =>\n      BiliBiliUserInfoModel(\n        mid: asT<int?>(json['mid']),\n        uname: asT<String?>(json['uname']),\n        userid: asT<String?>(json['userid']),\n        sign: asT<String?>(json['sign']),\n        birthday: asT<String?>(json['birthday']),\n        sex: asT<String?>(json['sex']),\n        nickFree: asT<bool?>(json['nick_free']),\n        rank: asT<String?>(json['rank']),\n      );\n\n  int? mid;\n  String? uname;\n  String? userid;\n  String? sign;\n  String? birthday;\n  String? sex;\n  bool? nickFree;\n  String? rank;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'mid': mid,\n        'uname': uname,\n        'userid': userid,\n        'sign': sign,\n        'birthday': birthday,\n        'sex': sex,\n        'nick_free': nickFree,\n        'rank': rank,\n      };\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/db/follow_user.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:hive/hive.dart';\n\npart 'follow_user.g.dart';\n\n@HiveType(typeId: 1)\nclass FollowUser {\n  FollowUser({\n    required this.id,\n    required this.roomId,\n    required this.siteId,\n    required this.userName,\n    required this.face,\n    required this.addTime,\n  });\n\n  ///id=siteId_roomId\n  @HiveField(0)\n  String id;\n\n  @HiveField(1)\n  String roomId;\n\n  @HiveField(2)\n  String siteId;\n\n  @HiveField(3)\n  String userName;\n\n  @HiveField(4)\n  String face;\n\n  @HiveField(5)\n  DateTime addTime;\n\n  /// 直播状态\n  /// 0=未知(加载中) 1=未开播 2=直播中\n  Rx<int> liveStatus = 0.obs;\n\n  factory FollowUser.fromJson(Map<String, dynamic> json) => FollowUser(\n        id: json['id'],\n        roomId: json['roomId'],\n        siteId: json['siteId'],\n        userName: json['userName'],\n        face: json['face'],\n        addTime: DateTime.parse(json['addTime']),\n      );\n\n  Map<String, dynamic> toJson() => {\n        'id': id,\n        'roomId': roomId,\n        'siteId': siteId,\n        'userName': userName,\n        'face': face,\n        'addTime': addTime.toString(),\n      };\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/db/follow_user.g.dart",
    "content": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'follow_user.dart';\n\n// **************************************************************************\n// TypeAdapterGenerator\n// **************************************************************************\n\nclass FollowUserAdapter extends TypeAdapter<FollowUser> {\n  @override\n  final int typeId = 1;\n\n  @override\n  FollowUser read(BinaryReader reader) {\n    final numOfFields = reader.readByte();\n    final fields = <int, dynamic>{\n      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),\n    };\n    return FollowUser(\n      id: fields[0] as String,\n      roomId: fields[1] as String,\n      siteId: fields[2] as String,\n      userName: fields[3] as String,\n      face: fields[4] as String,\n      addTime: fields[5] as DateTime,\n    );\n  }\n\n  @override\n  void write(BinaryWriter writer, FollowUser obj) {\n    writer\n      ..writeByte(6)\n      ..writeByte(0)\n      ..write(obj.id)\n      ..writeByte(1)\n      ..write(obj.roomId)\n      ..writeByte(2)\n      ..write(obj.siteId)\n      ..writeByte(3)\n      ..write(obj.userName)\n      ..writeByte(4)\n      ..write(obj.face)\n      ..writeByte(5)\n      ..write(obj.addTime);\n  }\n\n  @override\n  int get hashCode => typeId.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      other is FollowUserAdapter &&\n          runtimeType == other.runtimeType &&\n          typeId == other.typeId;\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/db/history.dart",
    "content": "import 'package:hive/hive.dart';\n\npart 'history.g.dart';\n\n@HiveType(typeId: 2)\nclass History {\n  History({\n    required this.id,\n    required this.roomId,\n    required this.siteId,\n    required this.userName,\n    required this.face,\n    required this.updateTime,\n  });\n\n  ///id=siteId_roomId\n  @HiveField(0)\n  String id;\n\n  @HiveField(1)\n  String roomId;\n\n  @HiveField(2)\n  String siteId;\n\n  @HiveField(3)\n  String userName;\n\n  @HiveField(4)\n  String face;\n\n  @HiveField(5)\n  DateTime updateTime;\n\n  factory History.fromJson(Map<String, dynamic> json) => History(\n        id: json[\"id\"],\n        roomId: json[\"roomId\"],\n        siteId: json[\"siteId\"],\n        userName: json[\"userName\"],\n        face: json[\"face\"],\n        updateTime: DateTime.parse(json[\"updateTime\"]),\n      );\n\n  Map<String, dynamic> toJson() => {\n        \"id\": id,\n        \"roomId\": roomId,\n        \"siteId\": siteId,\n        \"userName\": userName,\n        \"face\": face,\n        \"updateTime\": updateTime.toString(),\n      };\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/db/history.g.dart",
    "content": "// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'history.dart';\n\n// **************************************************************************\n// TypeAdapterGenerator\n// **************************************************************************\n\nclass HistoryAdapter extends TypeAdapter<History> {\n  @override\n  final int typeId = 2;\n\n  @override\n  History read(BinaryReader reader) {\n    final numOfFields = reader.readByte();\n    final fields = <int, dynamic>{\n      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),\n    };\n    return History(\n      id: fields[0] as String,\n      roomId: fields[1] as String,\n      siteId: fields[2] as String,\n      userName: fields[3] as String,\n      face: fields[4] as String,\n      updateTime: fields[5] as DateTime,\n    );\n  }\n\n  @override\n  void write(BinaryWriter writer, History obj) {\n    writer\n      ..writeByte(6)\n      ..writeByte(0)\n      ..write(obj.id)\n      ..writeByte(1)\n      ..write(obj.roomId)\n      ..writeByte(2)\n      ..write(obj.siteId)\n      ..writeByte(3)\n      ..write(obj.userName)\n      ..writeByte(4)\n      ..write(obj.face)\n      ..writeByte(5)\n      ..write(obj.updateTime);\n  }\n\n  @override\n  int get hashCode => typeId.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      other is HistoryAdapter &&\n          runtimeType == other.runtimeType &&\n          typeId == other.typeId;\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/follow_user_item.dart",
    "content": "\n"
  },
  {
    "path": "simple_live_tv_app/lib/models/version_model.dart",
    "content": "import 'dart:convert';\n\nT? asT<T>(dynamic value) {\n  if (value is T) {\n    return value;\n  }\n  return null;\n}\n\nclass VersionModel {\n  VersionModel({\n    required this.version,\n    required this.versionNum,\n    required this.versionDesc,\n    required this.downloadUrl,\n  });\n\n  factory VersionModel.fromJson(Map<String, dynamic> json) => VersionModel(\n        version: asT<String>(json['version'])!,\n        versionNum: asT<int>(json['version_num'])!,\n        versionDesc: asT<String>(json['version_desc'])!,\n        downloadUrl: asT<String>(json['download_url'])!,\n      );\n\n  String version;\n  int versionNum;\n  String versionDesc;\n  String downloadUrl;\n\n  @override\n  String toString() {\n    return jsonEncode(this);\n  }\n\n  Map<String, dynamic> toJson() => <String, dynamic>{\n        'version': version,\n        'version_num': versionNum,\n        'version_desc': versionDesc,\n        'download_url': downloadUrl,\n      };\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/account/bilibili/qr_login_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/requests/http_client.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\n\nenum QRStatus {\n  loading,\n  unscanned,\n  scanned,\n  expired,\n  failed,\n}\n\nclass BiliBiliQRLoginController extends GetxController {\n  @override\n  void onInit() {\n    loadQRCode();\n    super.onInit();\n  }\n\n  Timer? timer;\n\n  var qrcodeUrl = \"\".obs;\n  var qrcodeKey = \"\";\n\n  /// 二维码状态\n  /// - [0] 加载中\n  /// - [1] 未扫描\n  /// - [2] 已扫描，待确认\n  /// - [3] 二维码已经失效\n  /// - [4] 登录失败\n  Rx<QRStatus> qrStatus = QRStatus.loading.obs;\n\n  void loadQRCode() async {\n    try {\n      qrStatus.value = QRStatus.loading;\n\n      var result = await HttpClient.instance.getJson(\n        \"https://passport.bilibili.com/x/passport-login/web/qrcode/generate\",\n      );\n      if (result[\"code\"] != 0) {\n        throw result[\"message\"];\n      }\n      qrcodeKey = result[\"data\"][\"qrcode_key\"];\n      qrcodeUrl.value = result[\"data\"][\"url\"];\n      qrStatus.value = QRStatus.unscanned;\n      startPoll();\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(e.toString());\n      qrStatus.value = QRStatus.failed;\n    }\n  }\n\n  void startPoll() {\n    timer = Timer.periodic(\n      const Duration(seconds: 3),\n      (timer) {\n        pollQRStatus();\n      },\n    );\n  }\n\n  void pollQRStatus() async {\n    try {\n      var response = await HttpClient.instance.get(\n        \"https://passport.bilibili.com/x/passport-login/web/qrcode/poll\",\n        queryParameters: {\n          \"qrcode_key\": qrcodeKey,\n        },\n      );\n      if (response.data[\"code\"] != 0) {\n        throw response.data[\"message\"];\n      }\n      var data = response.data[\"data\"];\n      var code = data[\"code\"];\n      if (code == 0) {\n        var cookies = <String>[];\n        response.headers[\"set-cookie\"]?.forEach((element) {\n          var cookie = element.split(\";\")[0];\n          cookies.add(cookie);\n        });\n        if (cookies.isNotEmpty) {\n          var cookieStr = cookies.join(\";\");\n          Log.i(cookieStr);\n          BiliBiliAccountService.instance.setCookie(cookieStr);\n          await BiliBiliAccountService.instance.loadUserInfo();\n          Get.back();\n        }\n      } else if (code == 86038) {\n        qrStatus.value = QRStatus.expired;\n        qrcodeKey = \"\";\n        timer?.cancel();\n      } else if (code == 86090) {\n        qrStatus.value = QRStatus.scanned;\n      }\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(e.toString());\n    }\n  }\n\n  @override\n  void onClose() {\n    timer?.cancel();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/account/bilibili/qr_login_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_flutter/qr_flutter.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/modules/account/bilibili/qr_login_controller.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\n\nclass BiliBiliQRLoginPage extends GetView<BiliBiliQRLoginController> {\n  const BiliBiliQRLoginPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"登录哔哩哔哩\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n            ],\n          ),\n          AppStyle.vGap48,\n          Expanded(\n            child: Column(\n              crossAxisAlignment: CrossAxisAlignment.stretch,\n              mainAxisAlignment: MainAxisAlignment.center,\n              children: [\n                Center(\n                  child: Obx(\n                    () {\n                      if (controller.qrStatus.value == QRStatus.loading) {\n                        return SizedBox(\n                          width: 64.w,\n                          height: 64.w,\n                          child: CircularProgressIndicator(\n                            strokeWidth: 8.w,\n                            color: Colors.white,\n                          ),\n                        );\n                      }\n                      if (controller.qrStatus.value == QRStatus.failed) {\n                        return Column(\n                          mainAxisSize: MainAxisSize.min,\n                          children: [\n                            Text(\n                              \"二维码加载失败\",\n                              style: AppStyle.textStyleWhite,\n                            ),\n                            HighlightButton(\n                              focusNode: AppFocusNode(),\n                              iconData: Icons.refresh,\n                              text: \"重试\",\n                              onTap: controller.loadQRCode,\n                            ),\n                          ],\n                        );\n                      }\n                      if (controller.qrStatus.value == QRStatus.failed) {\n                        return Column(\n                          mainAxisSize: MainAxisSize.min,\n                          children: [\n                            Text(\n                              \"二维码已失效\",\n                              style: AppStyle.textStyleWhite,\n                            ),\n                            HighlightButton(\n                              focusNode: AppFocusNode(),\n                              iconData: Icons.refresh,\n                              text: \"刷新\",\n                              onTap: controller.loadQRCode,\n                            ),\n                          ],\n                        );\n                      }\n                      return Column(\n                        children: [\n                          ClipRRect(\n                            borderRadius: AppStyle.radius12,\n                            child: QrImageView(\n                              data: controller.qrcodeUrl.value,\n                              version: QrVersions.auto,\n                              backgroundColor: Colors.white,\n                              size: 360.w,\n                              padding: AppStyle.edgeInsetsA12,\n                            ),\n                          ),\n                          AppStyle.vGap8,\n                          Visibility(\n                            visible:\n                                controller.qrStatus.value == QRStatus.scanned,\n                            child: Text(\n                              \"已扫描，请在手机上确认登录\",\n                              style: AppStyle.textStyleWhite,\n                            ),\n                          ),\n                        ],\n                      );\n                    },\n                  ),\n                ),\n                Padding(\n                  padding: AppStyle.edgeInsetsA24,\n                  child: Text(\n                    \"请使用哔哩哔哩手机客户端扫描二维码登录\\n必须登录后才能观看哔哩哔哩直播\",\n                    textAlign: TextAlign.center,\n                    style: TextStyle(fontSize: 32.w),\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/agreement/agreement_page.dart",
    "content": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/routes/route_path.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\n\nclass AgreementPage extends StatelessWidget {\n  const AgreementPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Center(\n        child: SizedBox(\n          width: 1000.w,\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            crossAxisAlignment: CrossAxisAlignment.stretch,\n            children: [\n              Text(\n                \"使用须知\",\n                textAlign: TextAlign.center,\n                style: AppStyle.titleStyleWhite,\n              ),\n              AppStyle.vGap24,\n              Text(\n                \"欢迎使用Simple Live TV，请在使用前仔细阅读以下内容：\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap12,\n              Text(\n                \"1. 本软件为开源软件，仅供学习交流使用，禁止用于任何商业用途。\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap12,\n              Text(\n                \"2. 本软件不提供任何直播内容，所有直播内容均来自网络。\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap12,\n              Text(\n                \"3. 本软件完全基于您个人意愿使用，您应该对自己的使用行为和所有结果承担全部责任。\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap12,\n              Text(\n                \"4. 如果本软件存在侵犯您的合法权益的情况，请及时与作者联系，作者将会及时删除有关内容。\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap12,\n              Text(\n                \"如您继续使用本软件即代表您已完全理解并同意上述内容。\",\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap32,\n              Row(\n                mainAxisAlignment: MainAxisAlignment.center,\n                children: [\n                  HighlightButton(\n                    text: \"已阅读并同意\",\n                    autofocus: true,\n                    focusNode: AppFocusNode(),\n                    onTap: () {\n                      AppSettingsController.instance.setNoFirstRun();\n                      Get.offAllNamed(RoutePath.kHome);\n                    },\n                  ),\n                  AppStyle.hGap32,\n                  HighlightButton(\n                    text: \"退出应用\",\n                    focusNode: AppFocusNode(),\n                    onTap: () {\n                      //退出软件\n                      exit(0);\n                    },\n                  ),\n                ],\n              )\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/category/category_controller.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\n\nclass CategoryController extends BasePageController<AppLiveCategory> {\n  var siteId = Constant.kBiliBili.obs;\n  var site = Sites.allSites[Constant.kBiliBili]!;\n\n  @override\n  void onInit() {\n    refreshData();\n    super.onInit();\n  }\n\n  void setSite(String id) {\n    siteId.value = id;\n    site = Sites.allSites[id]!;\n    refreshData();\n  }\n\n  @override\n  Future<List<AppLiveCategory>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getCategores();\n\n    return result.map((e) => AppLiveCategory.fromLiveCategory(e)).toList();\n  }\n}\n\nclass AppLiveCategory extends LiveCategory {\n  var showAll = false.obs;\n  final List<LiveSubCategoryExt> childrenExt;\n  AppLiveCategory({\n    required super.id,\n    required super.name,\n    required super.children,\n  }) : childrenExt = children\n            .map((e) => LiveSubCategoryExt(\n                  id: e.id,\n                  name: e.name,\n                  parentId: e.parentId,\n                  pic: e.pic,\n                ))\n            .toList() {\n    showAll.value = children.length < 19;\n  }\n\n  List<LiveSubCategoryExt> get take15 => childrenExt.take(15).toList();\n\n  AppFocusNode moreFocusNode = AppFocusNode();\n\n  factory AppLiveCategory.fromLiveCategory(LiveCategory item) {\n    return AppLiveCategory(\n      children: item.children,\n      id: item.id,\n      name: item.name,\n    );\n  }\n}\n\nclass LiveSubCategoryExt extends LiveSubCategory {\n  LiveSubCategoryExt({\n    required super.id,\n    required super.name,\n    required super.parentId,\n    super.pic,\n  });\n\n  AppFocusNode focusNode = AppFocusNode();\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/category/category_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\nimport 'package:simple_live_tv_app/widgets/net_image.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/category/category_controller.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\n\nclass CategoryPage extends GetView<CategoryController> {\n  const CategoryPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"直播类目\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Visibility(\n                  visible: controller.loadding.value,\n                  child: SizedBox(\n                    width: 48.w,\n                    height: 48.w,\n                    child: CircularProgressIndicator(\n                      color: Colors.white,\n                      strokeWidth: 4.w,\n                    ),\n                  ),\n                ),\n              ),\n              //  AppStyle.hGap24,\n              // HighlightButton(\n              //   focusNode: AppFocusNode(),\n              //   iconData: Icons.refresh,\n              //   text: \"刷新\",\n              //   onTap: () {\n              //     controller.refreshData();\n              //   },\n              // ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap24,\n          Wrap(\n            alignment: WrapAlignment.center,\n            spacing: 36.w,\n            children: Sites.supportSites\n                .map(\n                  (e) => Obx(\n                    () => HighlightButton(\n                      icon: Image.asset(\n                        e.logo,\n                        width: 48.w,\n                        height: 48.w,\n                      ),\n                      text: e.name,\n                      selected: controller.siteId.value == e.id,\n                      focusNode: AppFocusNode(),\n                      onTap: () {\n                        controller.setSite(e.id);\n                      },\n                    ),\n                  ),\n                )\n                .toList(),\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Obx(\n              () => ListView.builder(\n                padding: AppStyle.edgeInsetsH48,\n                itemCount: controller.list.length,\n                controller: controller.scrollController,\n                itemBuilder: (_, i) {\n                  var item = controller.list[i];\n                  return Column(\n                    crossAxisAlignment: CrossAxisAlignment.stretch,\n                    children: [\n                      Padding(\n                        padding: AppStyle.edgeInsetsV32,\n                        child: Text(\n                          item.name,\n                          style: AppStyle.titleStyleWhite,\n                        ),\n                      ),\n                      Obx(\n                        () => GridView.count(\n                          shrinkWrap: true,\n                          padding: AppStyle.edgeInsetsV8,\n                          physics: const NeverScrollableScrollPhysics(),\n                          crossAxisCount: 8,\n                          crossAxisSpacing: 36.w,\n                          mainAxisSpacing: 36.w,\n                          children: item.showAll.value\n                              ? (item.childrenExt\n                                  .map(\n                                    (e) => buildSubCategory(e),\n                                  )\n                                  .toList())\n                              : (item.take15\n                                  .map(\n                                    (e) => buildSubCategory(e),\n                                  )\n                                  .toList()\n                                ..add(buildShowMore(item))),\n                        ),\n                      ),\n                    ],\n                  );\n                },\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildSubCategory(LiveSubCategoryExt item) {\n    return HighlightWidget(\n      focusNode: item.focusNode,\n      onTap: () {\n        AppNavigator.toCategoryDetail(site: controller.site, category: item);\n      },\n      color: Colors.white10,\n      borderRadius: AppStyle.radius16,\n      child: Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        children: [\n          (item.pic != null && item.pic!.isNotEmpty)\n              ? NetImage(\n                  item.pic ?? \"\",\n                  width: 64.w,\n                  height: 64.w,\n                  borderRadius: 16.w,\n                  cacheWidth: 100,\n                )\n              : Image.asset(\n                  \"assets/images/${controller.site.id}.png\",\n                  width: 64.w,\n                  height: 64.w,\n                ),\n          AppStyle.vGap12,\n          Text(\n            item.name,\n            maxLines: 1,\n            textAlign: TextAlign.center,\n            style: item.focusNode.isFoucsed.value\n                ? AppStyle.textStyleBlack\n                : AppStyle.textStyleWhite,\n          ),\n        ],\n      ),\n    );\n  }\n\n  Widget buildShowMore(AppLiveCategory item) {\n    return HighlightWidget(\n      focusNode: item.moreFocusNode,\n      onTap: () {\n        item.showAll.value = true;\n      },\n      color: Colors.white10,\n      borderRadius: AppStyle.radius16,\n      child: Center(\n        child: Text(\n          \"显示全部\",\n          maxLines: 1,\n          textAlign: TextAlign.center,\n          style: item.moreFocusNode.isFoucsed.value\n              ? AppStyle.textStyleBlack\n              : AppStyle.textStyleWhite,\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/category/detail/category_detail_controller.dart",
    "content": "import 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/category/category_controller.dart';\nimport 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart';\n\nclass CategoryDetailController extends BasePageController<LiveRoomItemExt> {\n  final Site site;\n  final LiveSubCategoryExt subCategory;\n  CategoryDetailController({\n    required this.site,\n    required this.subCategory,\n  });\n\n  @override\n  void onInit() {\n    scrollController.addListener(scrollListener);\n    refreshData();\n    super.onInit();\n  }\n\n  void scrollListener() {\n    if (scrollController.position.pixels >=\n        (scrollController.position.maxScrollExtent - 100.w)) {\n      loadData();\n    }\n  }\n\n  @override\n  Future<List<LiveRoomItemExt>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getCategoryRooms(subCategory, page: page);\n    return result.items\n        .map(\n          (e) => LiveRoomItemExt(\n            roomId: e.roomId,\n            title: e.title,\n            cover: e.cover,\n            userName: e.userName,\n            online: e.online,\n          ),\n        )\n        .toList();\n  }\n\n  @override\n  void onClose() {\n    scrollController.removeListener(scrollListener);\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/category/detail/category_detail_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/modules/category/detail/category_detail_controller.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/live_room_card.dart';\n\nclass CategoryDetailPage extends GetView<CategoryDetailController> {\n  const CategoryDetailPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                controller.subCategory.name,\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Visibility(\n                  visible: controller.loadding.value,\n                  child: SizedBox(\n                    width: 48.w,\n                    height: 48.w,\n                    child: CircularProgressIndicator(\n                      color: Colors.white,\n                      strokeWidth: 4.w,\n                    ),\n                  ),\n                ),\n              ),\n              //AppStyle.hGap24,\n              // HighlightButton(\n              //   focusNode: AppFocusNode(),\n              //   iconData: Icons.refresh,\n              //   text: \"刷新\",\n              //   onTap: () {\n              //     controller.refreshData();\n              //   },\n              // ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Obx(\n              () => MasonryGridView.count(\n                padding: AppStyle.edgeInsetsA48,\n                itemCount: controller.list.length,\n                crossAxisCount: 5,\n                crossAxisSpacing: 48.w,\n                mainAxisSpacing: 40.w,\n                controller: controller.scrollController,\n                itemBuilder: (_, i) {\n                  var item = controller.list[i];\n\n                  if (i == 0) {\n                    Future.delayed(Duration.zero, () {\n                      if (controller.currentPage == 2) {\n                        item.focusNode.requestFocus();\n                      }\n                    });\n                  }\n                  return LiveRoomCard(\n                    cover: item.cover,\n                    anchor: item.userName,\n                    title: item.title,\n                    focusNode: item.focusNode,\n                    roomId: item.roomId,\n                    online: item.online,\n                    onTap: () {\n                      AppNavigator.toLiveRoomDetail(\n                        site: controller.site,\n                        roomId: item.roomId,\n                      );\n                    },\n                  );\n                },\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/follow_user/follow_user_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/anchor_card.dart';\n\nclass FollowUserPage extends StatelessWidget {\n  const FollowUserPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"我的关注\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.refresh,\n                text: \"刷新\",\n                onTap: () {\n                  FollowUserService.instance.refreshData();\n                },\n              ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap48,\n          Expanded(\n            child: Obx(\n              () => MasonryGridView.count(\n                padding: AppStyle.edgeInsetsH48,\n                itemCount: FollowUserService.instance.list.length,\n                crossAxisCount: 3,\n                crossAxisSpacing: 48.w,\n                mainAxisSpacing: 40.w,\n                shrinkWrap: true,\n                physics: const NeverScrollableScrollPhysics(),\n                itemBuilder: (_, i) {\n                  var item = FollowUserService.instance.list[i];\n                  return AnchorCard(\n                    face: item.face,\n                    name: item.userName,\n                    siteId: item.siteId,\n                    liveStatus: item.liveStatus.value,\n                    roomId: item.roomId,\n                  );\n                },\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/history/history_controller.dart",
    "content": "import 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/models/db/history.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\n\nclass HistoryController extends BasePageController<History> {\n  @override\n  void onInit() {\n    refreshData();\n    super.onInit();\n  }\n\n  @override\n  Future<List<History>> getData(int page, int pageSize) {\n    if (page > 1) {\n      return Future.value([]);\n    }\n    return Future.value(DBService.instance.getHistores());\n  }\n\n  void clean() async {\n    var result = await Utils.showAlertDialog(\"确定要清空观看记录吗?\", title: \"清空观看记录\");\n    if (!result) {\n      return;\n    }\n    await DBService.instance.historyBox.clear();\n    refreshData();\n  }\n\n  void removeItem(History item) async {\n    var result = await Utils.showAlertDialog(\"确定要删除此记录吗?\", title: \"删除记录\");\n    if (!result) {\n      return;\n    }\n    await DBService.instance.historyBox.delete(item.id);\n    refreshData();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/history/history_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/modules/history/history_controller.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/anchor_card.dart';\n\nclass HistoryPage extends GetView<HistoryController> {\n  const HistoryPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"观看记录\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.delete_outline_rounded,\n                text: \"清空\",\n                onTap: () {\n                  controller.clean();\n                },\n              ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap48,\n          Expanded(\n            child: Obx(\n              () => MasonryGridView.count(\n                padding: AppStyle.edgeInsetsH48,\n                itemCount: controller.list.length,\n                crossAxisCount: 3,\n                crossAxisSpacing: 48.w,\n                mainAxisSpacing: 40.w,\n                shrinkWrap: true,\n                physics: const NeverScrollableScrollPhysics(),\n                itemBuilder: (_, i) {\n                  var item = controller.list[i];\n                  return AnchorCard(\n                    face: item.face,\n                    name: item.userName,\n                    siteId: item.siteId,\n                    liveStatus: 0,\n                    roomId: item.roomId,\n                  );\n                },\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/home/home_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:get/get.dart';\n\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\n\nimport 'package:simple_live_tv_app/routes/route_path.dart';\n\nclass HomeController extends BaseController {\n  var datetime = \"00:00\".obs;\n\n  @override\n  void onInit() {\n    initTimer();\n    Utils.checkUpdate();\n    super.onInit();\n  }\n\n  void initTimer() {\n    Timer.periodic(const Duration(seconds: 1), (timer) {\n      var now = DateTime.now();\n      datetime.value =\n          \"${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}\";\n    });\n  }\n\n  void toSync() {\n    Get.toNamed(RoutePath.kSync);\n  }\n\n  void toFollow() {\n    Get.toNamed(RoutePath.kFollow);\n  }\n\n  void toSettings() {\n    Get.toNamed(RoutePath.kSettings);\n  }\n\n  void toHistory() {\n    Get.toNamed(RoutePath.kHistory);\n  }\n\n  void toHotLive() {\n    Get.toNamed(RoutePath.kHotLive);\n  }\n\n  void toSearchRoom(String keyword) {\n    Get.toNamed(RoutePath.kSearchRoom, arguments: keyword);\n  }\n\n  void toSearchAnchor(String keyword) {\n    Get.toNamed(RoutePath.kSearchAnchor, arguments: keyword);\n  }\n\n  void toCategory() {\n    Get.toNamed(RoutePath.kCategory);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/home/home_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:lottie/lottie.dart';\nimport 'package:remixicon/remixicon.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/modules/home/home_controller.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_list_tile.dart';\nimport 'package:simple_live_tv_app/widgets/card/anchor_card.dart';\nimport 'package:simple_live_tv_app/widgets/button/home_big_button.dart';\nimport 'package:simple_live_tv_app/widgets/net_image.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart';\n\nclass HomePage extends GetView<HomeController> {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              Text(\n                \"Simple Live TV\",\n                style: AppStyle.titleStyleWhite,\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Text(\n                  controller.datetime.value,\n                  style: AppStyle.titleStyleWhite.copyWith(fontSize: 36.w),\n                ),\n              ),\n              AppStyle.hGap32,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.settings,\n                text: \"设置\",\n                onTap: () {\n                  controller.toSettings();\n                },\n              ),\n              AppStyle.hGap48,\n            ],\n          ),\n          Expanded(\n            child: ListView(\n              padding: AppStyle.edgeInsetsV32,\n              children: [\n                Padding(\n                  padding: AppStyle.edgeInsetsH48,\n                  child: Row(\n                    crossAxisAlignment: CrossAxisAlignment.center,\n                    children: [\n                      Expanded(\n                        child: HomeBigButton(\n                          autofocus: true,\n                          focusNode: AppFocusNode(),\n                          text: \"热门直播\",\n                          iconData: Remix.fire_line,\n                          onTap: controller.toHotLive,\n                        ),\n                      ),\n                      AppStyle.hGap48,\n                      Expanded(\n                        child: HomeBigButton(\n                          autofocus: true,\n                          focusNode: AppFocusNode(),\n                          text: \"直播类目\",\n                          iconData: Remix.apps_line,\n                          onTap: controller.toCategory,\n                        ),\n                      ),\n                      AppStyle.hGap48,\n                      Expanded(\n                        child: HomeBigButton(\n                          autofocus: true,\n                          focusNode: AppFocusNode(),\n                          text: \"搜索直播\",\n                          iconData: Remix.search_2_line,\n                          onTap: showSearchDialog,\n                        ),\n                      ),\n                      // AppStyle.hGap40,\n                      // Expanded(\n                      //   child: HomeBigButton(\n                      //     focusNode: AppFocusNode(),\n                      //     text: \"我的关注\",\n                      //     iconData: Icons.favorite_border,\n                      //     onTap: controller.toFollow,\n                      //   ),\n                      // ),\n                      AppStyle.hGap48,\n                      Expanded(\n                        child: HomeBigButton(\n                          focusNode: AppFocusNode(),\n                          text: \"观看记录\",\n                          iconData: Icons.history,\n                          onTap: controller.toHistory,\n                        ),\n                      ),\n                      AppStyle.hGap48,\n                      Expanded(\n                        child: HomeBigButton(\n                          focusNode: AppFocusNode(),\n                          text: \"数据同步\",\n                          iconData: Icons.devices,\n                          onTap: controller.toSync,\n                        ),\n                      ),\n                    ],\n                  ),\n                ),\n                AppStyle.vGap32,\n                Padding(\n                  padding: AppStyle.edgeInsetsH48,\n                  child: Row(\n                    crossAxisAlignment: CrossAxisAlignment.center,\n                    children: [\n                      SizedBox(\n                        width: 64.w,\n                        height: 64.w,\n                        child: Center(\n                          child: Icon(\n                            Icons.favorite_border,\n                            color: Colors.white,\n                            size: 56.w,\n                          ),\n                        ),\n                      ),\n                      AppStyle.hGap24,\n                      Expanded(\n                        child: Text(\n                          \"我的关注\",\n                          style: AppStyle.titleStyleWhite,\n                        ),\n                      ),\n                      Obx(\n                        () => Visibility(\n                          visible: FollowUserService.instance.updating.value,\n                          child: Row(\n                            children: [\n                              SizedBox(\n                                width: 48.w,\n                                height: 48.w,\n                                child: CircularProgressIndicator(\n                                  color: Colors.white,\n                                  strokeWidth: 4.w,\n                                ),\n                              ),\n                              AppStyle.hGap16,\n                              Text(\n                                \"更新状态中...\",\n                                style: AppStyle.textStyleWhite,\n                              ),\n                            ],\n                          ),\n                        ),\n                      ),\n                      AppStyle.hGap16,\n                      HighlightButton(\n                        focusNode: AppFocusNode(),\n                        iconData: Icons.settings,\n                        text: \"管理\",\n                        onTap: showManageDialog,\n                      ),\n                      AppStyle.hGap32,\n                      HighlightButton(\n                        focusNode: AppFocusNode(),\n                        iconData: Icons.refresh,\n                        text: \"刷新\",\n                        onTap: () {\n                          FollowUserService.instance.refreshData();\n                        },\n                      ),\n                    ],\n                  ),\n                ),\n                AppStyle.vGap32,\n                Obx(\n                  () => MasonryGridView.count(\n                    padding: AppStyle.edgeInsetsH48,\n                    itemCount: FollowUserService.instance.list.length,\n                    crossAxisCount: 3,\n                    crossAxisSpacing: 48.w,\n                    mainAxisSpacing: 48.w,\n                    shrinkWrap: true,\n                    physics: const NeverScrollableScrollPhysics(),\n                    itemBuilder: (_, i) {\n                      var item = FollowUserService.instance.list[i];\n                      return Obx(\n                        () => AnchorCard(\n                          face: item.face,\n                          name: item.userName,\n                          siteId: item.siteId,\n                          liveStatus: item.liveStatus.value,\n                          roomId: item.roomId,\n                        ),\n                      );\n                    },\n                  ),\n                ),\n                Obx(\n                  () => Visibility(\n                    visible: FollowUserService.instance.list.isEmpty,\n                    child: Column(\n                      children: [\n                        AppStyle.vGap24,\n                        LottieBuilder.asset(\n                          'assets/lotties/empty.json',\n                          width: 160.w,\n                          height: 160.w,\n                          repeat: false,\n                        ),\n                        AppStyle.vGap24,\n                        Text(\n                          \"暂无任何关注\\n您可以从其他端同步数据到此处\",\n                          textAlign: TextAlign.center,\n                          style: AppStyle.textStyleWhite,\n                        ),\n                        AppStyle.vGap16,\n                        HighlightButton(\n                          focusNode: AppFocusNode(),\n                          iconData: Icons.devices,\n                          text: \"同步数据\",\n                          onTap: () {\n                            controller.toSync();\n                          },\n                        ),\n                      ],\n                    ),\n                  ),\n                )\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void showManageDialog() {\n    Utils.showSystemRightDialog(\n      //useSystem: true,\n      width: 700.w,\n      child: Column(\n        children: [\n          AppStyle.vGap24,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                onTap: () {\n                  //Utils.hideRightDialog();\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"关注管理\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n            ],\n          ),\n          Expanded(\n            child: Stack(\n              children: [\n                Obx(\n                  () => ListView.separated(\n                    itemCount: FollowUserService.instance.list.length,\n                    separatorBuilder: (_, __) => AppStyle.vGap24,\n                    padding: AppStyle.edgeInsetsA40,\n                    itemBuilder: (_, i) {\n                      var item = FollowUserService.instance.list[i];\n                      var foucsNode = AppFocusNode();\n                      return HighlightListTile(\n                        autofocus: i == 0,\n                        leading: NetImage(\n                          item.face,\n                          width: 64.w,\n                          height: 64.w,\n                          borderRadius: 64.w,\n                        ),\n                        title: item.userName,\n                        focusNode: foucsNode,\n                        trailing: Obx(\n                          () => Icon(\n                            Icons.delete_outline_outlined,\n                            size: 40.w,\n                            color: foucsNode.isFoucsed.value\n                                ? Colors.black\n                                : Colors.white,\n                          ),\n                        ),\n                        onTap: () {\n                          FollowUserService.instance\n                              .removeItem(item, refresh: false);\n                        },\n                      );\n                    },\n                  ),\n                ),\n                Obx(\n                  () => Visibility(\n                    visible: FollowUserService.instance.list.isEmpty,\n                    child: const AppEmptyWidget(\n                      text: \"关注列表为空，快去关注一些主播吧\",\n                    ),\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n\n  void showSearchDialog() {\n    var textController = TextEditingController();\n    var mode = 0.obs;\n    var roomFocusNode = AppFocusNode()..isFoucsed.value = true;\n    var anchorFocusNode = AppFocusNode();\n    showDialog(\n      context: Get.context!,\n      builder: (_) => AlertDialog(\n        backgroundColor: Get.theme.cardColor,\n        surfaceTintColor: Colors.transparent,\n        shape: RoundedRectangleBorder(\n          borderRadius: AppStyle.radius16,\n        ),\n        contentPadding: AppStyle.edgeInsetsA48,\n        content: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            Row(\n              mainAxisAlignment: MainAxisAlignment.start,\n              children: [\n                Obx(\n                  () => HighlightButton(\n                    text: \"直播间\",\n                    iconData: Icons.live_tv,\n                    selected: mode.value == 0,\n                    focusNode: roomFocusNode,\n                    autofocus: roomFocusNode.isFoucsed.value,\n                    onTap: () {\n                      mode.value = 0;\n                    },\n                  ),\n                ),\n                AppStyle.hGap40,\n                Obx(\n                  () => HighlightButton(\n                    text: \"主播\",\n                    selected: mode.value == 1,\n                    iconData: Icons.person,\n                    focusNode: anchorFocusNode,\n                    autofocus: anchorFocusNode.isFoucsed.value,\n                    onTap: () {\n                      mode.value = 1;\n                    },\n                  ),\n                ),\n              ],\n            ),\n            AppStyle.vGap48,\n            SizedBox(\n              width: 700.w,\n              child: TextField(\n                controller: textController,\n                style: AppStyle.textStyleWhite,\n                textInputAction: TextInputAction.search,\n                onSubmitted: (e) {\n                  Get.back();\n                  if (e.isEmpty) {\n                    return;\n                  }\n                  if (mode.value == 0) {\n                    controller.toSearchRoom(textController.text);\n                  } else {\n                    controller.toSearchAnchor(textController.text);\n                  }\n                },\n                decoration: InputDecoration(\n                  hintText: mode.value == 0 ? \"点击输入关键字搜索\" : \"点击主播昵称搜索\",\n                  hintStyle: AppStyle.textStyleWhite,\n                  border: OutlineInputBorder(\n                    borderRadius: AppStyle.radius16,\n                    borderSide: BorderSide(width: 4.w),\n                  ),\n                  filled: true,\n                  isDense: true,\n                  fillColor: Get.theme.primaryColor,\n                  contentPadding: AppStyle.edgeInsetsA32,\n                ),\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/hot_live/hot_live_controller.dart",
    "content": "import 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\n\nclass HotliveController extends BasePageController<LiveRoomItemExt> {\n  var siteId = Constant.kBiliBili.obs;\n  var site = Sites.allSites[Constant.kBiliBili]!;\n\n  @override\n  void onInit() {\n    scrollController.addListener(scrollListener);\n    refreshData();\n    super.onInit();\n  }\n\n  void scrollListener() {\n    if (scrollController.position.pixels >=\n        (scrollController.position.maxScrollExtent - 100.w)) {\n      loadData();\n    }\n  }\n\n  void setSite(String id) {\n    siteId.value = id;\n    site = Sites.allSites[id]!;\n    refreshData();\n  }\n\n  @override\n  Future<List<LiveRoomItemExt>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.getRecommendRooms(page: page);\n\n    return result.items\n        .map((e) => LiveRoomItemExt(\n              roomId: e.roomId,\n              title: e.title,\n              cover: e.cover,\n              userName: e.userName,\n              online: e.online,\n            ))\n        .toList();\n  }\n\n  @override\n  void onClose() {\n    scrollController.removeListener(scrollListener);\n    super.onClose();\n  }\n}\n\nclass LiveRoomItemExt extends LiveRoomItem {\n  LiveRoomItemExt({\n    required super.roomId,\n    required super.title,\n    required super.cover,\n    required super.userName,\n    super.online = 0,\n  });\n\n  AppFocusNode focusNode = AppFocusNode();\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/hot_live/hot_live_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/live_room_card.dart';\n\nclass HotLivePage extends GetView<HotliveController> {\n  const HotLivePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                //autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"热门直播\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Visibility(\n                  visible: controller.loadding.value,\n                  child: SizedBox(\n                    width: 48.w,\n                    height: 48.w,\n                    child: CircularProgressIndicator(\n                      color: Colors.white,\n                      strokeWidth: 4.w,\n                    ),\n                  ),\n                ),\n              ),\n              AppStyle.hGap24,\n              // HighlightButton(\n              //   focusNode: AppFocusNode(),\n              //   iconData: Icons.refresh,\n              //   text: \"刷新\",\n              //   onTap: () {\n              //     controller.refreshData();\n              //   },\n              // ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap24,\n          Wrap(\n            alignment: WrapAlignment.center,\n            spacing: 36.w,\n            children: Sites.supportSites\n                .map(\n                  (e) => Obx(\n                    () => HighlightButton(\n                      icon: Image.asset(\n                        e.logo,\n                        width: 48.w,\n                        height: 48.w,\n                      ),\n                      text: e.name,\n                      selected: controller.siteId.value == e.id,\n                      focusNode: AppFocusNode(),\n                      onTap: () {\n                        controller.setSite(e.id);\n                      },\n                    ),\n                  ),\n                )\n                .toList(),\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Obx(\n              () => MasonryGridView.count(\n                padding: AppStyle.edgeInsetsA48,\n                itemCount: controller.list.length,\n                crossAxisCount: 5,\n                crossAxisSpacing: 48.w,\n                mainAxisSpacing: 40.w,\n                controller: controller.scrollController,\n                itemBuilder: (_, i) {\n                  var item = controller.list[i];\n\n                  if (i == 0) {\n                    Future.delayed(Duration.zero, () {\n                      if (controller.currentPage == 2) {\n                        item.focusNode.requestFocus();\n                      }\n                    });\n                  }\n                  return LiveRoomCard(\n                    cover: item.cover,\n                    anchor: item.userName,\n                    title: item.title,\n                    focusNode: item.focusNode,\n                    roomId: item.roomId,\n                    online: item.online,\n                    onTap: () {\n                      AppNavigator.toLiveRoomDetail(\n                        site: controller.site,\n                        roomId: item.roomId,\n                      );\n                    },\n                  );\n                },\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/live_room/live_room_controller.dart",
    "content": "import 'dart:async';\n\nimport 'package:canvas_danmaku/models/danmaku_content_item.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/event_bus.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\nimport 'package:simple_live_tv_app/models/db/history.dart';\nimport 'package:simple_live_tv_app/modules/live_room/player/player_controller.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\n\nclass LiveRoomController extends PlayerController with WidgetsBindingObserver {\n  final Site pSite;\n  final String pRoomId;\n  late LiveDanmaku liveDanmaku;\n  LiveRoomController({\n    required this.pSite,\n    required this.pRoomId,\n  }) {\n    rxSite = pSite.obs;\n    rxRoomId = pRoomId.obs;\n    liveDanmaku = site.liveSite.getDanmaku();\n  }\n  final FocusNode focusNode = FocusNode();\n  late Rx<Site> rxSite;\n  Site get site => rxSite.value;\n  late Rx<String> rxRoomId;\n  String get roomId => rxRoomId.value;\n\n  Rx<LiveRoomDetail?> detail = Rx<LiveRoomDetail?>(null);\n  var online = 0.obs;\n  var followed = false.obs;\n  var liveStatus = false.obs;\n\n  /// 清晰度数据\n  RxList<LivePlayQuality> qualites = RxList<LivePlayQuality>();\n\n  /// 当前清晰度\n  var currentQuality = -1;\n  var currentQualityInfo = \"\".obs;\n\n  /// 线路数据\n  RxList<String> playUrls = RxList<String>();\n\n  Map<String, String>? playHeaders;\n\n  /// 当前线路\n  var currentLineIndex = -1;\n  var currentLineInfo = \"\".obs;\n\n  /// 是否处于后台\n  var isBackground = false;\n\n  var datetime = \"00:00\".obs;\n\n  void initTimer() {\n    Timer.periodic(const Duration(seconds: 1), (timer) {\n      var now = DateTime.now();\n      datetime.value =\n          \"${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}\";\n    });\n  }\n\n  /// 双击退出Flag\n  bool doubleClickExit = false;\n\n  /// 双击退出Timer\n  Timer? doubleClickTimer;\n\n  @override\n  void onInit() {\n    initTimer();\n    showDanmakuState.value = AppSettingsController.instance.danmuEnable.value;\n    followed.value = DBService.instance.getFollowExist(\"${site.id}_$roomId\");\n\n    loadData();\n\n    super.onInit();\n  }\n\n  void refreshRoom() {\n    //messages.clear();\n\n    liveDanmaku.stop();\n\n    loadData();\n  }\n\n  /// 初始化弹幕接收事件\n  void initDanmau() {\n    liveDanmaku.onMessage = onWSMessage;\n  }\n\n  /// 接收到WebSocket信息\n  void onWSMessage(LiveMessage msg) {\n    if (msg.type == LiveMessageType.chat) {\n      // 关键词屏蔽检查\n      for (var keyword in AppSettingsController.instance.shieldList) {\n        Pattern? pattern;\n        if (Utils.isRegexFormat(keyword)) {\n          String removedSlash = Utils.removeRegexFormat(keyword);\n          try {\n            pattern = RegExp(removedSlash);\n          } catch (e) {\n            // should avoid this during add keyword\n            Log.d(\"关键词：$keyword 正则格式错误\");\n          }\n        } else {\n          pattern = keyword;\n        }\n        if (pattern != null && msg.message.contains(pattern)) {\n          Log.d(\"关键词：$keyword\\n已屏蔽消息内容：${msg.message}\");\n          return;\n        }\n      }\n\n      if (!liveStatus.value || isBackground) {\n        return;\n      }\n\n      addDanmaku([\n        DanmakuContentItem(\n          msg.message,\n          color: Color.fromARGB(255, msg.color.r, msg.color.g, msg.color.b),\n        ),\n      ]);\n    } else if (msg.type == LiveMessageType.online) {\n      online.value = msg.data;\n    } else if (msg.type == LiveMessageType.superChat) {\n      //superChats.add(msg.data);\n    }\n  }\n\n  /// 加载直播间信息\n  void loadData() async {\n    try {\n      SmartDialog.showLoading(msg: \"\");\n      pageLoadding.value = true;\n      detail.value = await site.liveSite.getRoomDetail(roomId: roomId);\n\n      addHistory();\n      online.value = detail.value!.online;\n      liveStatus.value = detail.value!.status || detail.value!.isRecord;\n      if (liveStatus.value) {\n        getPlayQualites();\n      }\n      if (detail.value!.isRecord) {\n        SmartDialog.showToast(\"当前主播未开播，正在轮播录像\");\n      }\n\n      initDanmau();\n      liveDanmaku.start(detail.value?.danmakuData);\n    } catch (e) {\n      SmartDialog.showToast(e.toString());\n    } finally {\n      SmartDialog.dismiss(status: SmartStatus.loading);\n      pageLoadding.value = false;\n    }\n  }\n\n  /// 初始化播放器\n  void getPlayQualites() async {\n    qualites.clear();\n    currentQuality = -1;\n    try {\n      var playQualites =\n          await site.liveSite.getPlayQualites(detail: detail.value!);\n\n      if (playQualites.isEmpty) {\n        SmartDialog.showToast(\"无法读取播放清晰度\");\n        return;\n      }\n      qualites.value = playQualites;\n      var qualityLevel = AppSettingsController.instance.qualityLevel.value;\n      if (qualityLevel == 2) {\n        //最高\n        currentQuality = 0;\n      } else if (qualityLevel == 0) {\n        //最低\n        currentQuality = playQualites.length - 1;\n      } else {\n        //中间值\n        int middle = (playQualites.length / 2).floor();\n        currentQuality = middle;\n      }\n\n      getPlayUrl();\n    } catch (e) {\n      Log.logPrint(e);\n      SmartDialog.showToast(\"无法读取播放清晰度\");\n    }\n  }\n\n  void getPlayUrl() async {\n    playUrls.clear();\n    currentQualityInfo.value = qualites[currentQuality].quality;\n    currentLineInfo.value = \"\";\n    currentLineIndex = -1;\n    var playUrl = await site.liveSite\n        .getPlayUrls(detail: detail.value!, quality: qualites[currentQuality]);\n    if (playUrl.urls.isEmpty) {\n      SmartDialog.showToast(\"无法读取播放地址\");\n      return;\n    }\n    playUrls.value = playUrl.urls;\n    playHeaders = playUrl.headers;\n    currentLineIndex = 0;\n    currentLineInfo.value = \"线路${currentLineIndex + 1}\";\n    //重置错误次数\n    mediaErrorRetryCount = 0;\n    setPlayer();\n  }\n\n  void changePlayLine(int index) {\n    currentLineIndex = index;\n    //重置错误次数\n    mediaErrorRetryCount = 0;\n    setPlayer();\n  }\n\n  void setPlayer() async {\n    currentLineInfo.value = \"线路${currentLineIndex + 1}\";\n    errorMsg.value = \"\";\n\n    player.open(\n      Media(\n        playUrls[currentLineIndex],\n        httpHeaders: playHeaders,\n      ),\n    );\n\n    Log.d(\"播放链接\\r\\n：${playUrls[currentLineIndex]}\");\n  }\n\n  @override\n  void mediaEnd() async {\n    if (mediaErrorRetryCount < 2) {\n      Log.d(\"播放结束，尝试第${mediaErrorRetryCount + 1}次刷新\");\n      if (mediaErrorRetryCount == 1) {\n        //延迟一秒再刷新\n        await Future.delayed(const Duration(seconds: 1));\n      }\n      mediaErrorRetryCount += 1;\n      //刷新一次\n      setPlayer();\n      return;\n    }\n\n    Log.d(\"播放结束\");\n    // 遍历线路，如果全部链接都断开就是直播结束了\n    if (playUrls.length - 1 == currentLineIndex) {\n      liveStatus.value = false;\n    } else {\n      changePlayLine(currentLineIndex + 1);\n\n      //setPlayer();\n    }\n  }\n\n  int mediaErrorRetryCount = 0;\n  @override\n  void mediaError(String error) async {\n    if (mediaErrorRetryCount < 2) {\n      Log.d(\"播放失败，尝试第${mediaErrorRetryCount + 1}次刷新\");\n      if (mediaErrorRetryCount == 1) {\n        //延迟一秒再刷新\n        await Future.delayed(const Duration(seconds: 1));\n      }\n      mediaErrorRetryCount += 1;\n      //刷新一次\n      setPlayer();\n      return;\n    }\n\n    if (playUrls.length - 1 == currentLineIndex) {\n      errorMsg.value = \"播放失败\";\n      SmartDialog.showToast(\"播放失败:$error\");\n    } else {\n      //currentLineIndex += 1;\n      //setPlayer();\n      changePlayLine(currentLineIndex + 1);\n    }\n  }\n\n  /// 添加历史记录\n  void addHistory() {\n    if (detail.value == null) {\n      return;\n    }\n    var id = \"${site.id}_$roomId\";\n    var history = DBService.instance.getHistory(id);\n    if (history != null) {\n      history.updateTime = DateTime.now();\n    }\n    history ??= History(\n      id: id,\n      roomId: roomId,\n      siteId: site.id,\n      userName: detail.value?.userName ?? \"\",\n      face: detail.value?.userAvatar ?? \"\",\n      updateTime: DateTime.now(),\n    );\n\n    DBService.instance.addOrUpdateHistory(history);\n  }\n\n  /// 关注用户\n  void followUser() {\n    if (detail.value == null) {\n      return;\n    }\n    var id = \"${site.id}_$roomId\";\n    DBService.instance.addFollow(\n      FollowUser(\n        id: id,\n        roomId: roomId,\n        siteId: site.id,\n        userName: detail.value?.userName ?? \"\",\n        face: detail.value?.userAvatar ?? \"\",\n        addTime: DateTime.now(),\n      ),\n    );\n    followed.value = true;\n    EventBus.instance.emit(Constant.kUpdateFollow, id);\n    SmartDialog.showToast(\"已关注\");\n  }\n\n  /// 取消关注用户\n  void removeFollowUser() async {\n    if (detail.value == null) {\n      return;\n    }\n    // if (!await Utils.showAlertDialog(\"确定要取消关注该用户吗？\", title: \"取消关注\")) {\n    //   return;\n    // }\n\n    var id = \"${site.id}_$roomId\";\n    DBService.instance.deleteFollow(id);\n    followed.value = false;\n    EventBus.instance.emit(Constant.kUpdateFollow, id);\n    SmartDialog.showToast(\"已取消关注\");\n  }\n\n  void resetRoom(Site site, String roomId) async {\n    if (this.site == site && this.roomId == roomId) {\n      return;\n    }\n\n    rxSite.value = site;\n    rxRoomId.value = roomId;\n\n    // 清除全部消息\n    liveDanmaku.stop();\n\n    danmakuController?.clear();\n\n    // 重新设置LiveDanmaku\n    liveDanmaku = site.liveSite.getDanmaku();\n\n    // 停止播放\n    await player.stop();\n\n    // 刷新信息\n    loadData();\n  }\n\n  void nextChannel() {\n    //读取正在直播的频道\n    var liveChannels = FollowUserService.instance.livingList;\n    if (liveChannels.isEmpty) {\n      SmartDialog.showToast(\"没有正在直播的频道\");\n      return;\n    }\n    var index = liveChannels\n        .indexWhere((element) => element.id == \"${site.id}_$roomId\");\n    // if (index == -1) {\n    //   //当前频道不在列表中\n\n    //   return;\n    // }\n    index += 1;\n    if (index >= liveChannels.length) {\n      index = 0;\n    }\n    var nextChannel = liveChannels[index];\n\n    resetRoom(Sites.allSites[nextChannel.siteId]!, nextChannel.roomId);\n  }\n\n  void prevChannel() {\n    //读取正在直播的频道\n    var liveChannels = FollowUserService.instance.livingList;\n    if (liveChannels.isEmpty) {\n      SmartDialog.showToast(\"没有正在直播的频道\");\n      return;\n    }\n    var index = liveChannels\n        .indexWhere((element) => element.id == \"${site.id}_$roomId\");\n    // if (index == -1) {\n    //   //当前频道不在列表中\n\n    //   return;\n    // }\n    index -= 1;\n    if (index < 0) {\n      index = liveChannels.length - 1;\n    }\n    var nextChannel = liveChannels[index];\n\n    resetRoom(Sites.allSites[nextChannel.siteId]!, nextChannel.roomId);\n  }\n\n  @override\n  void didChangeAppLifecycleState(AppLifecycleState state) {\n    super.didChangeAppLifecycleState(state);\n\n    if (state == AppLifecycleState.paused) {\n      Log.d(\"进入后台\");\n      //进入后台，关闭弹幕\n      danmakuController?.clear();\n      isBackground = true;\n    } else\n    //返回前台\n    if (state == AppLifecycleState.resumed) {\n      Log.d(\"返回前台\");\n      isBackground = false;\n    }\n  }\n\n  @override\n  void onClose() {\n    liveDanmaku.stop();\n\n    danmakuController = null;\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/live_room/live_room_page.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_tv_app/modules/live_room/player/player_controls.dart';\n\nclass LiveRoomPage extends GetView<LiveRoomController> {\n  const          LiveRoomPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return PopScope(\n      canPop: false,\n      onPopInvokedWithResult: (didPop, result) {\n        if (!didPop) {\n          //双击返回键退出\n          if (controller.doubleClickExit) {\n            controller.doubleClickTimer?.cancel();\n            Get.back();\n            return;\n          }\n          controller.doubleClickExit = true;\n          SmartDialog.showToast(\"再按一次退出播放器\");\n          controller.doubleClickTimer = Timer(const Duration(seconds: 2), () {\n            controller.doubleClickExit = false;\n            controller.doubleClickTimer!.cancel();\n          });\n        }\n      },\n      child: KeyboardListener(\n        focusNode: controller.focusNode,\n        autofocus: true,\n        onKeyEvent: onKeyEvent,\n        child: Scaffold(\n          backgroundColor: Colors.black,\n          body: Obx(\n            () => buildMediaPlayer(),\n          ),\n        ),\n      ),\n    );\n  }\n\n  void onKeyEvent(KeyEvent key) {\n    if (key is KeyUpEvent) {\n      return;\n    }\n    Log.logPrint(key);\n\n    // if (key.logicalKey == LogicalKeyboardKey.escape ||\n    //     key.logicalKey == LogicalKeyboardKey.backspace ||\n    //     key.logicalKey == LogicalKeyboardKey.goBack) {\n    //   // Get.back();\n    //   return;\n    // }\n    // 点击OK、Enter、Select键时显示/隐藏控制器\n    if (key.logicalKey == LogicalKeyboardKey.select ||\n        key.logicalKey == LogicalKeyboardKey.enter ||\n        key.logicalKey == LogicalKeyboardKey.space) {\n      if (!controller.showControlsState.value) {\n        controller.showControls();\n      } else {\n        controller.hideControls();\n      }\n      return;\n    }\n\n    // 点击Menu打开/关闭设置\n    if (key.logicalKey == LogicalKeyboardKey.keyM ||\n        key.logicalKey == LogicalKeyboardKey.contextMenu ||\n        key.logicalKey == LogicalKeyboardKey.arrowRight) {\n      showPlayerSettings(controller);\n      return;\n    }\n\n    // 点击左键显示关注用户\n    if (key.logicalKey == LogicalKeyboardKey.arrowLeft) {\n      showFollowUser(controller);\n      return;\n    }\n\n    // // 点击右键关注/取消关注\n    // if (key.logicalKey == LogicalKeyboardKey.arrowRight) {\n    //   if (controller.followed.value) {\n    //     controller.removeFollowUser();\n    //   } else {\n    //     controller.followUser();\n    //   }\n\n    //   return;\n    // }\n\n    // 点击上键切换上一个直播\n    if (key.logicalKey == LogicalKeyboardKey.arrowUp) {\n      controller.prevChannel();\n      return;\n    }\n\n    // 点击下键切换下一个直播\n    if (key.logicalKey == LogicalKeyboardKey.arrowDown) {\n      controller.nextChannel();\n      return;\n    }\n  }\n\n  Widget buildMediaPlayer() {\n    var boxFit = BoxFit.contain;\n    double? aspectRatio;\n    if (AppSettingsController.instance.scaleMode.value == 0) {\n      boxFit = BoxFit.contain;\n    } else if (AppSettingsController.instance.scaleMode.value == 1) {\n      boxFit = BoxFit.fill;\n    } else if (AppSettingsController.instance.scaleMode.value == 2) {\n      boxFit = BoxFit.cover;\n    } else if (AppSettingsController.instance.scaleMode.value == 3) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 16 / 9;\n    } else if (AppSettingsController.instance.scaleMode.value == 4) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 4 / 3;\n    }\n    return Stack(\n      children: [\n        Video(\n          key: controller.globalPlayerKey,\n          controller: controller.videoController,\n          pauseUponEnteringBackgroundMode:\n              AppSettingsController.instance.playerAutoPause.value,\n          resumeUponEnteringForegroundMode:\n              AppSettingsController.instance.playerAutoPause.value,\n          controls: (state) {\n            return playerControls(state, controller);\n          },\n          aspectRatio: aspectRatio,\n          fit: boxFit,\n        ),\n        Obx(\n          () => Visibility(\n            visible:\n                !controller.liveStatus.value && !controller.pageLoadding.value,\n            child: Center(\n              child: Text(\n                \"未开播\",\n                style: AppStyle.textStyleWhite,\n              ),\n            ),\n          ),\n        ),\n      ],\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/live_room/player/player_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:io';\n\nimport 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:flutter/material.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit/media_kit.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:wakelock_plus/wakelock_plus.dart';\n\nmixin PlayerMixin {\n  GlobalKey<VideoState> globalPlayerKey = GlobalKey<VideoState>();\n  GlobalKey globalDanmuKey = GlobalKey();\n\n  /// 播放器实例\n  late final player = Player(\n    configuration: const PlayerConfiguration(\n      title: \"Simple Live Player\",\n      // bufferSize:\n      //     // media-kit #549\n      //     AppSettingsController.instance.playerBufferSize.value * 1024 * 1024,\n    ),\n  );\n\n  /// 视频控制器\n  late final videoController = VideoController(\n    player,\n    configuration: AppSettingsController.instance.playerCompatMode.value\n        ? const VideoControllerConfiguration(\n            vo: 'mediacodec_embed',\n            hwdec: 'mediacodec',\n          )\n        : VideoControllerConfiguration(\n            enableHardwareAcceleration:\n                AppSettingsController.instance.hardwareDecode.value,\n            androidAttachSurfaceAfterVideoParameters: false,\n          ),\n  );\n}\nmixin PlayerStateMixin on PlayerMixin {\n  /// 是否显示弹幕\n  RxBool showDanmakuState = false.obs;\n\n  /// 是否显示控制器\n  RxBool showControlsState = false.obs;\n\n  /// 是否显示设置窗口\n  RxBool showSettingState = false.obs;\n\n  /// 是否显示弹幕设置窗口\n  RxBool showDanmakuSettingState = false.obs;\n\n  /// 是否处于锁定控制器状态\n  RxBool lockControlsState = false.obs;\n\n  /// 是否处于全屏状态\n  RxBool fullScreenState = false.obs;\n\n  /// 显示手势Tip\n  RxBool showGestureTip = false.obs;\n\n  /// 手势Tip文本\n  RxString gestureTipText = \"\".obs;\n\n  /// 显示提示底部Tip\n  RxBool showBottomTip = false.obs;\n\n  /// 提示底部Tip文本\n  RxString bottomTipText = \"\".obs;\n\n  /// 自动隐藏控制器计时器\n  Timer? hideControlsTimer;\n\n  /// 自动隐藏提示计时器\n  Timer? hideSeekTipTimer;\n\n  Widget? danmakuView;\n\n  var showQualites = false.obs;\n  var showLines = false.obs;\n\n  /// 隐藏控制器\n  void hideControls() {\n    showControlsState.value = false;\n    hideControlsTimer?.cancel();\n  }\n\n  void setLockState() {\n    lockControlsState.value = !lockControlsState.value;\n    if (lockControlsState.value) {\n      showControlsState.value = false;\n    } else {\n      showControlsState.value = true;\n    }\n  }\n\n  /// 显示控制器\n  void showControls() {\n    showControlsState.value = true;\n    resetHideControlsTimer();\n  }\n\n  /// 开始隐藏控制器计时\n  /// - 当点击控制器上时功能时需要重新计时\n  void resetHideControlsTimer() {\n    hideControlsTimer?.cancel();\n\n    hideControlsTimer = Timer(\n      const Duration(\n        seconds: 5,\n      ),\n      hideControls,\n    );\n  }\n\n  void updateScaleMode() {\n    var boxFit = BoxFit.contain;\n    double? aspectRatio;\n    if (player.state.width != null && player.state.height != null) {\n      aspectRatio = player.state.width! / player.state.height!;\n    }\n\n    if (AppSettingsController.instance.scaleMode.value == 0) {\n      boxFit = BoxFit.contain;\n    } else if (AppSettingsController.instance.scaleMode.value == 1) {\n      boxFit = BoxFit.fill;\n    } else if (AppSettingsController.instance.scaleMode.value == 2) {\n      boxFit = BoxFit.cover;\n    } else if (AppSettingsController.instance.scaleMode.value == 3) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 16 / 9;\n    } else if (AppSettingsController.instance.scaleMode.value == 4) {\n      boxFit = BoxFit.contain;\n      aspectRatio = 4 / 3;\n    }\n    globalPlayerKey.currentState?.update(\n      aspectRatio: aspectRatio,\n      fit: boxFit,\n    );\n  }\n}\nmixin PlayerDanmakuMixin on PlayerStateMixin {\n  /// 弹幕控制器\n  DanmakuController? danmakuController;\n\n  void initDanmakuController(DanmakuController e) {\n    danmakuController = e;\n    // danmakuController?.updateOption(\n    //   DanmakuOption(\n    //     fontSize: AppSettingsController.instance.danmuSize.value.w,\n    //     area: AppSettingsController.instance.danmuArea.value,\n    //     duration: AppSettingsController.instance.danmuSpeed.value,\n    //     opacity: AppSettingsController.instance.danmuOpacity.value,\n    //     strokeWidth: AppSettingsController.instance.danmuStrokeWidth.value.w,\n    //   ),\n    // );\n  }\n\n  void updateDanmuOption(DanmakuOption? option) {\n    if (danmakuController == null || option == null) return;\n    danmakuController!.updateOption(option);\n  }\n\n  void disposeDanmakuController() {\n    danmakuController?.clear();\n  }\n\n  void addDanmaku(List<DanmakuContentItem> items) {\n    if (!showDanmakuState.value) {\n      return;\n    }\n    for (var item in items) {\n      danmakuController?.addDanmaku(item);\n    }\n  }\n}\nmixin PlayerSystemMixin on PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin {\n  final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n\n  /// 初始化一些系统状态\n  void initSystem() async {\n    // 屏幕常亮\n    WakelockPlus.enable();\n\n    // 开始隐藏计时\n    resetHideControlsTimer();\n  }\n\n  /// 释放一些系统状态\n  Future resetSystem() async {\n    await WakelockPlus.disable();\n  }\n\n  /// 是否是IOS16以下\n  Future<bool> beforeIOS16() async {\n    if (Platform.isIOS) {\n      var info = await deviceInfo.iosInfo;\n      var version = info.systemVersion;\n      var versionInt = int.tryParse(version.split('.').first) ?? 0;\n      return versionInt < 16;\n    } else {\n      return false;\n    }\n  }\n}\n\nclass PlayerController extends BaseController\n    with PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin, PlayerSystemMixin {\n  @override\n  void onInit() {\n    initSystem();\n    initStream();\n    super.onInit();\n  }\n\n  var width = 0.obs;\n  var height = 0.obs;\n\n  StreamSubscription<String>? _errorSubscription;\n  StreamSubscription? _completedSubscription;\n  StreamSubscription? _widthSubscription;\n  StreamSubscription? _heightSubscription;\n  StreamSubscription? _logSubscription;\n\n  void initStream() {\n    _errorSubscription = player.stream.error.listen((event) {\n      Log.d(\"播放器错误：$event\");\n      if (event.contains('no sound.')) {\n        return;\n      }\n      //SmartDialog.showToast(event);\n      mediaError(event);\n    });\n\n    _completedSubscription = player.stream.completed.listen((event) {\n      if (event) {\n        mediaEnd();\n      }\n    });\n    _logSubscription = player.stream.log.listen((event) {\n      Log.d(\"播放器日志：$event\");\n    });\n    _widthSubscription = player.stream.width.listen((event) {\n      Log.w(\n          'width:$event  W:${(player.state.width)}  H:${(player.state.height)}');\n      width.value = event ?? 0;\n      // isVertical.value =\n      //     (player.state.height ?? 9) > (player.state.width ?? 16);\n    });\n    _heightSubscription = player.stream.height.listen((event) {\n      Log.w(\n          'height:$event  W:${(player.state.width)}  H:${(player.state.height)}');\n      height.value = event ?? 0;\n      // isVertical.value =\n      //     (player.state.height ?? 9) > (player.state.width ?? 16);\n    });\n  }\n\n  void disposeStream() {\n    _errorSubscription?.cancel();\n    _completedSubscription?.cancel();\n    _widthSubscription?.cancel();\n    _heightSubscription?.cancel();\n    _logSubscription?.cancel();\n  }\n\n  void mediaEnd() {}\n\n  void mediaError(String error) {}\n\n  @override\n  void onClose() async {\n    Log.w(\"播放器关闭\");\n    disposeStream();\n    disposeDanmakuController();\n    await resetSystem();\n    await player.dispose();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/live_room/player/player_controls.dart",
    "content": "import 'package:canvas_danmaku/canvas_danmaku.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:media_kit_video/media_kit_video.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/anchor_card.dart';\nimport 'package:simple_live_tv_app/widgets/settings_item_widget.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart';\n\nWidget playerControls(VideoState videoState, LiveRoomController controller) {\n  return buildControls(videoState, controller);\n}\n\nWidget buildControls(VideoState videoState, LiveRoomController controller) {\n  return Stack(\n    children: [\n      Container(),\n      buildDanmuView(videoState, controller),\n      // 点击播放器打开设置\n      Positioned.fill(\n        child: GestureDetector(onTap: () => showPlayerSettings(controller)),\n      ),\n      Center(\n        child: // 中间\n            StreamBuilder(\n          stream: videoState.widget.controller.player.stream.buffering,\n          initialData: videoState.widget.controller.player.state.buffering,\n          builder: (_, s) => Visibility(\n            visible: s.data ?? false,\n            child: SizedBox(\n              width: 64.w,\n              height: 64.w,\n              child: CircularProgressIndicator(\n                strokeWidth: 8.w,\n                color: Colors.white,\n              ),\n            ),\n          ),\n        ),\n      ),\n\n      // 顶部\n      Obx(\n        () => AnimatedPositioned(\n          left: 0,\n          right: 0,\n          top: (controller.showControlsState.value &&\n                  !controller.lockControlsState.value)\n              ? 0\n              : -200.w,\n          duration: const Duration(milliseconds: 200),\n          child: Container(\n            padding: EdgeInsets.only(\n              left: 32.w,\n              right: 32.w,\n              top: 24.w,\n              bottom: 24.w,\n            ),\n            decoration: const BoxDecoration(\n              gradient: LinearGradient(\n                begin: Alignment.bottomCenter,\n                end: Alignment.topCenter,\n                colors: [Colors.transparent, Colors.black87],\n              ),\n            ),\n            child: Row(\n              crossAxisAlignment: CrossAxisAlignment.start,\n              children: [\n                Expanded(\n                  child: Column(\n                    crossAxisAlignment: CrossAxisAlignment.stretch,\n                    children: [\n                      Text(\n                        controller.detail.value?.title ?? '正在读取直播信息...',\n                        maxLines: 1,\n                        overflow: TextOverflow.ellipsis,\n                        style: AppStyle.textStyleWhite,\n                      ),\n                      Text(\n                        \"${controller.detail.value?.userName} · ${controller.followed.value ? \"已关注\" : \"未关注\"}\",\n                        maxLines: 1,\n                        overflow: TextOverflow.ellipsis,\n                        style: AppStyle.textStyleWhite.copyWith(fontSize: 24.w),\n                      ),\n                    ],\n                  ),\n                ),\n                Obx(\n                  () => Text(\n                    controller.datetime.value,\n                    style: AppStyle.titleStyleWhite,\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ),\n      ),\n      // 底部\n      Obx(\n        () => AnimatedPositioned(\n          left: 0,\n          right: 0,\n          bottom: (controller.showControlsState.value &&\n                  !controller.lockControlsState.value)\n              ? 0\n              : -300.w,\n          duration: const Duration(milliseconds: 200),\n          child: Container(\n            decoration: const BoxDecoration(\n              gradient: LinearGradient(\n                begin: Alignment.topCenter,\n                end: Alignment.bottomCenter,\n                colors: [Colors.transparent, Colors.black87],\n              ),\n            ),\n            padding: EdgeInsets.only(\n              left: 32.w,\n              right: 32.w,\n              bottom: 24.w,\n              top: 24.w,\n            ),\n            child: Column(\n              children: [\n                Row(\n                  children: [\n                    //清晰度\n                    Obx(\n                      () => Text(\n                        \"清晰度: ${controller.currentQualityInfo.value}\",\n                        style: AppStyle.textStyleWhite,\n                      ),\n                    ),\n                    //线路\n                    AppStyle.hGap32,\n                    Obx(\n                      () => Text(\n                        \"线路：${controller.currentLineInfo.value}\",\n                        style: AppStyle.textStyleWhite,\n                      ),\n                    ),\n                    //弹幕开关\n                    AppStyle.hGap32,\n                    Obx(\n                      () => Text(\n                        \"弹幕: ${controller.showDanmakuState.value ? \"开\" : \"关\"}\",\n                        style: AppStyle.textStyleWhite,\n                      ),\n                    ),\n                    //分辨率\n                    AppStyle.hGap32,\n                    Obx(\n                      () => Text(\n                        \"分辨率: ${controller.width.value}x${controller.height.value}\",\n                        style: AppStyle.textStyleWhite,\n                      ),\n                    ),\n                  ],\n                ),\n                AppStyle.vGap12,\n                Row(\n                  crossAxisAlignment: CrossAxisAlignment.center,\n                  children: [\n                    Icon(\n                      Icons.arrow_circle_up_rounded,\n                      color: Colors.white,\n                      size: 40.w,\n                    ),\n                    AppStyle.hGap16,\n                    Text(\"上一频道\", style: AppStyle.textStyleWhite),\n                    AppStyle.hGap32,\n                    Icon(\n                      Icons.arrow_circle_down_rounded,\n                      color: Colors.white,\n                      size: 40.w,\n                    ),\n                    AppStyle.hGap16,\n                    Text(\"下一频道\", style: AppStyle.textStyleWhite),\n                    AppStyle.hGap32,\n                    Icon(\n                      Icons.arrow_circle_left_outlined,\n                      color: Colors.white,\n                      size: 40.w,\n                    ),\n                    AppStyle.hGap16,\n                    Text(\"关注列表\", style: AppStyle.textStyleWhite),\n                    AppStyle.hGap32,\n                    Icon(\n                      Icons.arrow_circle_right_outlined,\n                      color: Colors.white,\n                      size: 40.w,\n                    ),\n                    AppStyle.hGap16,\n                    Icon(Icons.menu, color: Colors.white, size: 44.w),\n                    AppStyle.hGap16,\n                    Text(\"设置\", style: AppStyle.textStyleWhite),\n                  ],\n                ),\n              ],\n            ),\n          ),\n        ),\n      ),\n    ],\n  );\n}\n\nWidget buildDanmuView(VideoState videoState, LiveRoomController controller) {\n  var padding = MediaQuery.of(videoState.context).padding;\n  controller.danmakuView ??= DanmakuScreen(\n    key: controller.globalDanmuKey,\n    createdController: controller.initDanmakuController,\n    option: DanmakuOption(\n      fontSize: AppSettingsController.instance.danmuSize.value.w,\n      area: AppSettingsController.instance.danmuArea.value,\n      duration: AppSettingsController.instance.danmuSpeed.value.toInt(),\n      opacity: AppSettingsController.instance.danmuOpacity.value,\n    ),\n  );\n  return Positioned.fill(\n    top: padding.top,\n    bottom: padding.bottom,\n    child: Obx(\n      () => Offstage(\n        offstage: !controller.showDanmakuState.value,\n        child: Padding(\n          padding: controller.fullScreenState.value\n              ? EdgeInsets.only(\n                  top: AppSettingsController.instance.danmuTopMargin.value,\n                  bottom:\n                      AppSettingsController.instance.danmuBottomMargin.value,\n                )\n              : EdgeInsets.zero,\n          child: controller.danmakuView!,\n        ),\n      ),\n    ),\n  );\n}\n\n// void showLinesInfo(LiveRoomController controller) {\n//   Utils.showRightDialog(\n//     title: \"线路\",\n//     useSystem: true,\n//     child: ListView.builder(\n//       padding: EdgeInsets.zero,\n//       itemCount: controller.playUrls.length,\n//       itemBuilder: (_, i) {\n//         return ListTile(\n//           selected: controller.currentLineIndex == i,\n//           title: Text.rich(\n//             TextSpan(\n//               text: \"线路${i + 1}\",\n//               children: [\n//                 WidgetSpan(\n//                     child: Container(\n//                   decoration: BoxDecoration(\n//                     borderRadius: AppStyle.radius4,\n//                     border: Border.all(\n//                       color: Colors.grey,\n//                     ),\n//                   ),\n//                   padding: AppStyle.edgeInsetsH4,\n//                   margin: AppStyle.edgeInsetsL8,\n//                   child: Text(\n//                     controller.playUrls[i].contains(\".flv\") ? \"FLV\" : \"HLS\",\n//                     style: const TextStyle(\n//                       fontSize: 12,\n//                     ),\n//                   ),\n//                 )),\n//               ],\n//             ),\n//             style: const TextStyle(fontSize: 14),\n//           ),\n//           minLeadingWidth: 16,\n//           onTap: () {\n//             Utils.hideRightDialog();\n//             //controller.currentLineIndex = i;\n//             //controller.setPlayer();\n//             controller.changePlayLine(i);\n//           },\n//         );\n//       },\n//     ),\n//   );\n// }\n\n// void showQualitesInfo(LiveRoomController controller) {\n//   Utils.showRightDialog(\n//     title: \"清晰度\",\n//     useSystem: true,\n//     child: ListView.builder(\n//       padding: EdgeInsets.zero,\n//       itemCount: controller.qualites.length,\n//       itemBuilder: (_, i) {\n//         var item = controller.qualites[i];\n//         return ListTile(\n//           selected: controller.currentQuality == i,\n//           title: Text(\n//             item.quality,\n//             style: const TextStyle(fontSize: 14),\n//           ),\n//           minLeadingWidth: 16,\n//           onTap: () {\n//             Utils.hideRightDialog();\n//             controller.currentQuality = i;\n//             controller.getPlayUrl();\n//           },\n//         );\n//       },\n//     ),\n//   );\n// }\n\nvoid showPlayerSettings(LiveRoomController controller) {\n  // 移除焦点\n  controller.focusNode.unfocus();\n\n  var followFocusNode = AppFocusNode()..isFoucsed.value = true;\n  var qualityFoucsNode = AppFocusNode();\n  var lineFoucsNode = AppFocusNode();\n  var scaleFoucsNode = AppFocusNode();\n  var danmakuFoucsNode = AppFocusNode();\n  var danmakuSizeFoucsNode = AppFocusNode();\n  var danmakuSpeedFoucsNode = AppFocusNode();\n  var danmakuAreaFoucsNode = AppFocusNode();\n  var danmakuOpacityFoucsNode = AppFocusNode();\n  Utils.showSystemRightDialog(\n    width: 800.w,\n    child: Column(\n      children: [\n        AppStyle.vGap24,\n        Row(\n          crossAxisAlignment: CrossAxisAlignment.center,\n          children: [\n            AppStyle.hGap48,\n            HighlightButton(\n              focusNode: AppFocusNode(),\n              iconData: Icons.arrow_back,\n              text: \"返回\",\n              onTap: () {\n                //Utils.hideRightDialog();\n                Get.back();\n              },\n            ),\n            AppStyle.hGap32,\n            Text(\n              \"设置\",\n              style: AppStyle.titleStyleWhite.copyWith(\n                fontSize: 36.w,\n                fontWeight: FontWeight.bold,\n              ),\n            ),\n            AppStyle.hGap24,\n            const Spacer(),\n          ],\n        ),\n        Expanded(\n          child: ListView(\n            padding: AppStyle.edgeInsetsA48,\n            children: [\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: followFocusNode,\n                  autofocus: followFocusNode.isFoucsed.value,\n                  title: \"关注用户\",\n                  items: const {false: \"否\", true: \"是\"},\n                  value: controller.followed.value,\n                  onChanged: (e) {\n                    if (e) {\n                      controller.followUser();\n                    } else {\n                      controller.removeFollowUser();\n                    }\n                  },\n                ),\n              ),\n\n              Divider(color: Colors.grey.withAlpha(50), height: 36.w),\n              AppStyle.vGap24,\n              Padding(\n                padding: AppStyle.edgeInsetsH20,\n                child: Text(\n                  \"清晰度与线路\",\n                  style: AppStyle.textStyleWhite.copyWith(\n                    fontWeight: FontWeight.bold,\n                  ),\n                ),\n              ),\n              AppStyle.vGap24,\n\n              // 清晰度切换\n              Obx(\n                () => SettingsItemWidget(\n                  title: \"清晰度\",\n                  foucsNode: qualityFoucsNode,\n                  autofocus: qualityFoucsNode.isFoucsed.value,\n                  items: controller.qualites\n                      .asMap()\n                      .map((i, e) => MapEntry(i, e.quality))\n                      .cast<int, String>(),\n                  value: controller.currentQuality,\n                  onChanged: (e) {\n                    Get.back();\n                    controller.currentQuality = e;\n                    controller.getPlayUrl();\n                  },\n                ),\n              ),\n\n              AppStyle.vGap32,\n              // 线路切换\n              Obx(\n                () => SettingsItemWidget(\n                  title: \"线路\",\n                  foucsNode: lineFoucsNode,\n                  autofocus: lineFoucsNode.isFoucsed.value,\n                  items: controller.playUrls\n                      .asMap()\n                      .map((i, e) => MapEntry(i, \"线路${i + 1}\"))\n                      .cast<int, String>(),\n                  value: controller.currentLineIndex,\n                  onChanged: (e) {\n                    Get.back();\n                    controller.changePlayLine(e);\n                  },\n                ),\n              ),\n              Divider(\n                color: Colors.grey.withAlpha(50),\n                height: 36.w,\n              ),\n              Padding(\n                padding: AppStyle.edgeInsetsH20,\n                child: Text(\n                  \"播放器\",\n                  style: AppStyle.textStyleWhite.copyWith(\n                    fontWeight: FontWeight.bold,\n                  ),\n                ),\n              ),\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: scaleFoucsNode,\n                  autofocus: scaleFoucsNode.isFoucsed.value,\n                  title: \"画面比例\",\n                  items: const {0: \"适应\", 1: \"拉伸\", 2: \"铺满\", 3: \"16:9\", 4: \"4:3\"},\n                  value: AppSettingsController.instance.scaleMode.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setScaleMode(e);\n                    controller.updateScaleMode();\n                  },\n                ),\n              ),\n              Divider(color: Colors.grey.withAlpha(50), height: 36.w),\n              Padding(\n                padding: AppStyle.edgeInsetsH20,\n                child: Text(\n                  \"弹幕\",\n                  style: AppStyle.textStyleWhite.copyWith(\n                    fontWeight: FontWeight.bold,\n                  ),\n                ),\n              ),\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: danmakuFoucsNode,\n                  autofocus: danmakuFoucsNode.isFoucsed.value,\n                  title: \"弹幕开关\",\n                  items: const {0: \"关\", 1: \"开\"},\n                  value: controller.showDanmakuState.value ? 1 : 0,\n                  onChanged: (e) {\n                    controller.showDanmakuState.value = e == 1;\n                    AppSettingsController.instance.setDanmuEnable(e == 1);\n                  },\n                ),\n              ),\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: danmakuSizeFoucsNode,\n                  autofocus: danmakuSizeFoucsNode.isFoucsed.value,\n                  title: \"弹幕大小\",\n                  items: {\n                    24.0: \"24\",\n                    32.0: \"32\",\n                    40.0: \"40\",\n                    48.0: \"48\",\n                    56.0: \"56\",\n                    64.0: \"64\",\n                    72.0: \"72\",\n                  },\n                  value: AppSettingsController.instance.danmuSize.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuSize(e);\n                    controller.updateDanmuOption(\n                      controller.danmakuController?.option.copyWith(\n                        fontSize: (e as double).w,\n                      ),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: danmakuSpeedFoucsNode,\n                  autofocus: danmakuSpeedFoucsNode.isFoucsed.value,\n                  title: \"弹幕速度\",\n                  items: {\n                    18.0: \"很慢\",\n                    14.0: \"较慢\",\n                    12.0: \"慢\",\n                    10.0: \"正常\",\n                    8.0: \"快\",\n                    6.0: \"较快\",\n                    4.0: \"很快\",\n                  },\n                  value: AppSettingsController.instance.danmuSpeed.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuSpeed(e);\n                    controller.updateDanmuOption(\n                      controller.danmakuController?.option.copyWith(\n                        duration: (e as double).toInt(),\n                      ),\n                    );\n                  },\n                ),\n              ),\n\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: danmakuAreaFoucsNode,\n                  autofocus: danmakuAreaFoucsNode.isFoucsed.value,\n                  title: \"显示区域\",\n                  items: {0.25: \"1/4\", 0.5: \"1/2\", 0.75: \"3/4\", 1.0: \"全屏\"},\n                  value: AppSettingsController.instance.danmuArea.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuArea(e);\n                    controller.updateDanmuOption(\n                      controller.danmakuController?.option.copyWith(\n                        area: e as double,\n                      ),\n                    );\n                  },\n                ),\n              ),\n              AppStyle.vGap24,\n              Obx(\n                () => SettingsItemWidget(\n                  foucsNode: danmakuOpacityFoucsNode,\n                  autofocus: danmakuOpacityFoucsNode.isFoucsed.value,\n                  title: \"不透明度\",\n                  items: {\n                    0.1: \"10%\",\n                    0.2: \"20%\",\n                    0.3: \"30%\",\n                    0.4: \"40%\",\n                    0.5: \"50%\",\n                    0.6: \"60%\",\n                    0.7: \"70%\",\n                    0.8: \"80%\",\n                    0.9: \"90%\",\n                    1.0: \"100%\",\n                  },\n                  value: AppSettingsController.instance.danmuOpacity.value,\n                  onChanged: (e) {\n                    AppSettingsController.instance.setDanmuOpacity(e);\n                    controller.updateDanmuOption(\n                      controller.danmakuController?.option.copyWith(\n                        opacity: e as double,\n                      ),\n                    );\n                  },\n                ),\n              ),\n            ],\n          ),\n        ),\n      ],\n    ),\n  ).then((value) {\n    // 还原焦点\n    controller.focusNode.requestFocus();\n  });\n}\n\nvoid showFollowUser(LiveRoomController controller) {\n  var currentIndex = 0;\n  if (controller.followed.value) {\n    currentIndex = FollowUserService.instance.livingList.indexWhere(\n      (e) =>\n          e.id ==\n          \"${controller.rxSite.value.id}_${controller.detail.value?.roomId}\",\n    );\n    if (currentIndex == -1) {\n      currentIndex = 0;\n    }\n  }\n\n  Utils.showSystemRightDialog(\n    width: 800.w,\n    child: Column(\n      children: [\n        AppStyle.vGap24,\n        Row(\n          crossAxisAlignment: CrossAxisAlignment.center,\n          children: [\n            AppStyle.hGap48,\n            HighlightButton(\n              focusNode: AppFocusNode(),\n              iconData: Icons.arrow_back,\n              text: \"返回\",\n              autofocus: currentIndex == 0 &&\n                  FollowUserService.instance.livingList.isEmpty,\n              onTap: () {\n                // Utils.hideRightDialog();\n                Get.back();\n              },\n            ),\n            AppStyle.hGap32,\n            Text(\n              \"我的关注\",\n              style: AppStyle.titleStyleWhite.copyWith(\n                fontSize: 36.w,\n                fontWeight: FontWeight.bold,\n              ),\n            ),\n            AppStyle.hGap24,\n            const Spacer(),\n          ],\n        ),\n        Expanded(\n          child: Stack(\n            children: [\n              Obx(\n                () => ListView.separated(\n                  itemCount: FollowUserService.instance.livingList.length,\n                  separatorBuilder: (context, index) => AppStyle.vGap32,\n                  padding: AppStyle.edgeInsetsA40.copyWith(\n                    left: 48.w,\n                    right: 48.w,\n                  ),\n                  itemBuilder: (_, i) {\n                    var item = FollowUserService.instance.livingList[i];\n                    var site = Sites.allSites[item.siteId]!;\n                    return AnchorCard(\n                      face: item.face,\n                      name: item.userName,\n                      siteId: item.siteId,\n                      liveStatus: item.liveStatus.value,\n                      roomId: item.roomId,\n                      autofocus: i == currentIndex,\n                      onTap: () {\n                        controller.resetRoom(site, item.roomId);\n                        Get.back();\n                      },\n                    );\n                  },\n                ),\n              ),\n              Obx(\n                () => Visibility(\n                  visible: FollowUserService.instance.list.isEmpty,\n                  child: const AppEmptyWidget(text: \"关注列表为空，快去关注一些主播吧\"),\n                ),\n              ),\n            ],\n          ),\n        ),\n      ],\n    ),\n  ).then((value) {\n    // 还原焦点\n    controller.focusNode.requestFocus();\n  });\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/search/anchor/search_anchor_controller.dart",
    "content": "import 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get_rx/src/rx_types/rx_types.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\n\nclass SearchAnchorController extends BasePageController<LiveAnchorItemExt> {\n  final String keyword;\n  SearchAnchorController(this.keyword);\n  var siteId = Constant.kBiliBili.obs;\n  var site = Sites.allSites[Constant.kBiliBili]!;\n\n  @override\n  void onInit() {\n    scrollController.addListener(scrollListener);\n    refreshData();\n    super.onInit();\n  }\n\n  void scrollListener() {\n    if (scrollController.position.pixels >=\n        (scrollController.position.maxScrollExtent - 100.w)) {\n      loadData();\n    }\n  }\n\n  void setSite(String id) {\n    siteId.value = id;\n    site = Sites.allSites[id]!;\n    refreshData();\n  }\n\n  @override\n  Future<List<LiveAnchorItemExt>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.searchAnchors(keyword, page: page);\n\n    return result.items\n        .map((e) => LiveAnchorItemExt(\n              roomId: e.roomId,\n              avatar: e.avatar,\n              liveStatus: e.liveStatus,\n              userName: e.userName,\n            ))\n        .toList();\n  }\n\n  @override\n  void onClose() {\n    scrollController.removeListener(scrollListener);\n    super.onClose();\n  }\n}\n\nclass LiveAnchorItemExt extends LiveAnchorItem {\n  LiveAnchorItemExt({\n    required super.roomId,\n    required super.avatar,\n    required super.liveStatus,\n    required super.userName,\n  });\n\n  AppFocusNode focusNode = AppFocusNode();\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/search/anchor/search_anchor_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/search/anchor/search_anchor_controller.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/anchor_card.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_error_widget.dart';\n\nclass SearchAnchorPage extends GetView<SearchAnchorController> {\n  const SearchAnchorPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                //autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"搜索：${controller.keyword}\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Visibility(\n                  visible: controller.loadding.value,\n                  child: SizedBox(\n                    width: 48.w,\n                    height: 48.w,\n                    child: CircularProgressIndicator(\n                      color: Colors.white,\n                      strokeWidth: 4.w,\n                    ),\n                  ),\n                ),\n              ),\n              AppStyle.hGap24,\n              // HighlightButton(\n              //   focusNode: AppFocusNode(),\n              //   iconData: Icons.refresh,\n              //   text: \"刷新\",\n              //   onTap: () {\n              //     controller.refreshData();\n              //   },\n              // ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap24,\n          Wrap(\n            alignment: WrapAlignment.center,\n            spacing: 36.w,\n            children: Sites.supportSites\n                .map(\n                  (e) => Obx(\n                    () => HighlightButton(\n                      icon: Image.asset(\n                        e.logo,\n                        width: 48.w,\n                        height: 48.w,\n                      ),\n                      text: e.name,\n                      selected: controller.siteId.value == e.id,\n                      focusNode: AppFocusNode(),\n                      onTap: () {\n                        controller.setSite(e.id);\n                      },\n                    ),\n                  ),\n                )\n                .toList(),\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Obx(\n              () => Stack(\n                children: [\n                  MasonryGridView.count(\n                    padding: AppStyle.edgeInsetsA48,\n                    itemCount: controller.list.length,\n                    crossAxisCount: 3,\n                    crossAxisSpacing: 48.w,\n                    mainAxisSpacing: 40.w,\n                    controller: controller.scrollController,\n                    itemBuilder: (_, i) {\n                      var item = controller.list[i];\n\n                      if (i == 0) {\n                        Future.delayed(Duration.zero, () {\n                          if (controller.currentPage == 2) {\n                            item.focusNode.requestFocus();\n                          }\n                        });\n                      }\n                      return AnchorCard(\n                        siteId: controller.siteId.value,\n                        name: item.userName,\n                        liveStatus: item.liveStatus ? 2 : 0,\n                        face: item.avatar,\n                        roomId: item.roomId,\n                        focusNode: item.focusNode,\n                        onTap: () {\n                          AppNavigator.toLiveRoomDetail(\n                            site: controller.site,\n                            roomId: item.roomId,\n                          );\n                        },\n                      );\n                    },\n                  ),\n                  Obx(\n                    () => Visibility(\n                      visible: controller.list.isEmpty &&\n                          !controller.loadding.value &&\n                          !controller.pageError.value,\n                      child: AppEmptyWidget(\n                        onRefresh: () {\n                          controller.refreshData();\n                        },\n                      ),\n                    ),\n                  ),\n                  Obx(\n                    () => Visibility(\n                      visible: controller.pageError.value &&\n                          !controller.loadding.value,\n                      child: AppErrorWidget(\n                        errorMsg: controller.errorMsg.value,\n                      ),\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/search/room/search_room_controller.dart",
    "content": "import 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get_rx/src/rx_types/rx_types.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart';\n\nclass SearchRoomController extends BasePageController<LiveRoomItemExt> {\n  final String keyword;\n  SearchRoomController(this.keyword);\n  var siteId = Constant.kBiliBili.obs;\n  var site = Sites.allSites[Constant.kBiliBili]!;\n\n  @override\n  void onInit() {\n    scrollController.addListener(scrollListener);\n    refreshData();\n    super.onInit();\n  }\n\n  void scrollListener() {\n    if (scrollController.position.pixels >=\n        (scrollController.position.maxScrollExtent - 100.w)) {\n      loadData();\n    }\n  }\n\n  void setSite(String id) {\n    siteId.value = id;\n    site = Sites.allSites[id]!;\n    refreshData();\n  }\n\n  @override\n  Future<List<LiveRoomItemExt>> getData(int page, int pageSize) async {\n    var result = await site.liveSite.searchRooms(keyword, page: page);\n\n    return result.items\n        .map((e) => LiveRoomItemExt(\n              roomId: e.roomId,\n              title: e.title,\n              cover: e.cover,\n              userName: e.userName,\n              online: e.online,\n            ))\n        .toList();\n  }\n\n  @override\n  void onClose() {\n    scrollController.removeListener(scrollListener);\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/search/room/search_room_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/search/room/search_room_controller.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/card/live_room_card.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_error_widget.dart';\n\nclass SearchRoomPage extends GetView<SearchRoomController> {\n  const SearchRoomPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                //autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"搜索：${controller.keyword}\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n              Obx(\n                () => Visibility(\n                  visible: controller.loadding.value,\n                  child: SizedBox(\n                    width: 48.w,\n                    height: 48.w,\n                    child: CircularProgressIndicator(\n                      color: Colors.white,\n                      strokeWidth: 4.w,\n                    ),\n                  ),\n                ),\n              ),\n              AppStyle.hGap24,\n              // HighlightButton(\n              //   focusNode: AppFocusNode(),\n              //   iconData: Icons.refresh,\n              //   text: \"刷新\",\n              //   onTap: () {\n              //     controller.refreshData();\n              //   },\n              // ),\n              AppStyle.hGap48,\n            ],\n          ),\n          AppStyle.vGap24,\n          Wrap(\n            alignment: WrapAlignment.center,\n            spacing: 36.w,\n            children: Sites.supportSites\n                .map(\n                  (e) => Obx(\n                    () => HighlightButton(\n                      icon: Image.asset(\n                        e.logo,\n                        width: 48.w,\n                        height: 48.w,\n                      ),\n                      text: e.name,\n                      selected: controller.siteId.value == e.id,\n                      focusNode: AppFocusNode(),\n                      onTap: () {\n                        controller.setSite(e.id);\n                      },\n                    ),\n                  ),\n                )\n                .toList(),\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Obx(\n              () => Stack(\n                children: [\n                  MasonryGridView.count(\n                    padding: AppStyle.edgeInsetsA48,\n                    itemCount: controller.list.length,\n                    crossAxisCount: 5,\n                    crossAxisSpacing: 48.w,\n                    mainAxisSpacing: 40.w,\n                    controller: controller.scrollController,\n                    itemBuilder: (_, i) {\n                      var item = controller.list[i];\n\n                      if (i == 0) {\n                        Future.delayed(Duration.zero, () {\n                          if (controller.currentPage == 2) {\n                            item.focusNode.requestFocus();\n                          }\n                        });\n                      }\n                      return LiveRoomCard(\n                        cover: item.cover,\n                        anchor: item.userName,\n                        title: item.title,\n                        focusNode: item.focusNode,\n                        roomId: item.roomId,\n                        online: item.online,\n                        onTap: () {\n                          AppNavigator.toLiveRoomDetail(\n                            site: controller.site,\n                            roomId: item.roomId,\n                          );\n                        },\n                      );\n                    },\n                  ),\n                  Obx(\n                    () => Visibility(\n                      visible: controller.list.isEmpty &&\n                          !controller.loadding.value &&\n                          !controller.pageError.value,\n                      child: AppEmptyWidget(\n                        onRefresh: () {\n                          controller.refreshData();\n                        },\n                      ),\n                    ),\n                  ),\n                  Obx(\n                    () => Visibility(\n                      visible: controller.pageError.value &&\n                          !controller.loadding.value,\n                      child: AppErrorWidget(\n                        errorMsg: controller.errorMsg.value,\n                      ),\n                    ),\n                  ),\n                ],\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/settings/settings_controller.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\n\nclass SettingsController extends BaseController\n    with GetTickerProviderStateMixin {\n  late TabController tabController;\n  var tabIndex = 0.obs;\n\n  SettingsController() {\n    tabController = TabController(length: 5, vsync: this);\n    tabController.animation?.addListener(() {\n      var currentIndex = (tabController.animation?.value ?? 0).round();\n      if (tabIndex.value == currentIndex) {\n        return;\n      }\n      tabIndex.value = currentIndex;\n      if (tabIndex.value == 0) {\n        hardwareDecodeFocusNode.requestFocus();\n      }\n      if (tabIndex.value == 1) {\n        danmakuFoucsNode.requestFocus();\n      }\n      if (tabIndex.value == 2) {\n        autoUpdateFollowEnableFocusNode.requestFocus();\n      }\n      if (tabIndex.value == 3) {\n        bilibiliFoucsNode.requestFocus();\n      }\n      if (tabIndex.value == 4) {\n        versionFocusNode.requestFocus();\n      }\n    });\n  }\n  var hardwareDecodeFocusNode = AppFocusNode()..isFoucsed.value = true;\n  var compatibleModeFocusNode = AppFocusNode();\n  var scaleFoucsNode = AppFocusNode();\n  var defaultQualityFocusNode = AppFocusNode();\n  var danmakuFoucsNode = AppFocusNode();\n  var danmakuSizeFoucsNode = AppFocusNode();\n  var danmakuSpeedFoucsNode = AppFocusNode();\n  var danmakuAreaFoucsNode = AppFocusNode();\n  var danmakuOpacityFoucsNode = AppFocusNode();\n  var danmakuStorkeFoucsNode = AppFocusNode();\n\n  var autoUpdateFollowEnableFocusNode = AppFocusNode();\n  var autoUpdateFollowDurationFocusNode = AppFocusNode();\n  var updateFollowThreadFocusNode = AppFocusNode();\n\n  var bilibiliFoucsNode = AppFocusNode();\n  var versionFocusNode = AppFocusNode();\n  void bilibiliTap() async {\n    if (BiliBiliAccountService.instance.logined.value) {\n      var result = await Utils.showAlertDialog(\"确定要退出哔哩哔哩账号吗？\", title: \"退出登录\");\n      if (result) {\n        BiliBiliAccountService.instance.logout();\n      }\n    } else {\n      AppNavigator.toBiliBiliLogin();\n    }\n  }\n\n  void checkUpdate() {\n    SmartDialog.showToast(\"检查更新中...\");\n    Utils.checkUpdate(showMsg: true);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/settings/settings_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/modules/settings/settings_controller.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_tv_app/services/follow_user_service.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_list_tile.dart';\nimport 'package:simple_live_tv_app/widgets/settings_item_widget.dart';\n\nclass SettingsPage extends GetView<SettingsController> {\n  const SettingsPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap32,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"设置\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              AppStyle.hGap24,\n              const Spacer(),\n            ],\n          ),\n          AppStyle.vGap48,\n          Row(\n            mainAxisAlignment: MainAxisAlignment.center,\n            children: [\n              Obx(\n                () => HighlightButton(\n                  focusNode: AppFocusNode(),\n                  iconData: Icons.play_circle_outline,\n                  text: \"播放\",\n                  selected: controller.tabIndex.value == 0,\n                  onTap: () {\n                    controller.tabController.animateTo(0);\n                  },\n                ),\n              ),\n              AppStyle.hGap32,\n              Obx(\n                () => HighlightButton(\n                  focusNode: AppFocusNode(),\n                  iconData: Icons.subtitles_outlined,\n                  text: \"弹幕\",\n                  selected: controller.tabIndex.value == 1,\n                  onTap: () {\n                    controller.tabController.animateTo(1);\n                  },\n                ),\n              ),\n              AppStyle.hGap32,\n              Obx(\n                () => HighlightButton(\n                  focusNode: AppFocusNode(),\n                  iconData: Icons.favorite_border,\n                  text: \"关注\",\n                  selected: controller.tabIndex.value == 2,\n                  onTap: () {\n                    controller.tabController.animateTo(2);\n                  },\n                ),\n              ),\n              AppStyle.hGap32,\n              Obx(\n                () => HighlightButton(\n                  focusNode: AppFocusNode(),\n                  iconData: Icons.account_circle_outlined,\n                  selected: controller.tabIndex.value == 3,\n                  text: \"账号\",\n                  onTap: () {\n                    controller.tabController.animateTo(3);\n                  },\n                ),\n              ),\n              AppStyle.hGap32,\n              Obx(\n                () => HighlightButton(\n                  focusNode: AppFocusNode(),\n                  iconData: Icons.info_outline,\n                  selected: controller.tabIndex.value == 4,\n                  text: \"关于\",\n                  onTap: () {\n                    controller.tabController.animateTo(4);\n                  },\n                ),\n              ),\n            ],\n          ),\n          Expanded(\n              child: SizedBox(\n            width: 800.w,\n            child: TabBarView(\n              controller: controller.tabController,\n              children: [\n                buildPlayerSettings(),\n                buildDanmakuSettings(),\n                buildFollowSettings(),\n                buildAccountSettings(),\n                buildAbout(),\n              ],\n            ),\n          )),\n        ],\n      ),\n    );\n  }\n\n  Widget buildPlayerSettings() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA48,\n      children: [\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.hardwareDecodeFocusNode,\n            autofocus: controller.hardwareDecodeFocusNode.isFoucsed.value,\n            title: \"硬件解码\",\n            items: const {\n              0: \"关\",\n              1: \"开\",\n            },\n            value: AppSettingsController.instance.hardwareDecode.value ? 1 : 0,\n            onChanged: (e) {\n              AppSettingsController.instance\n                  .setHardwareDecode(e == 1 ? true : false);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.compatibleModeFocusNode,\n            autofocus: controller.compatibleModeFocusNode.isFoucsed.value,\n            title: \"兼容模式\",\n            items: const {\n              0: \"关\",\n              1: \"开\",\n            },\n            value:\n                AppSettingsController.instance.playerCompatMode.value ? 1 : 0,\n            onChanged: (e) {\n              AppSettingsController.instance\n                  .setPlayerCompatMode(e == 1 ? true : false);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.scaleFoucsNode,\n            autofocus: controller.scaleFoucsNode.isFoucsed.value,\n            title: \"画面比例\",\n            items: const {\n              0: \"适应\",\n              1: \"拉伸\",\n              2: \"铺满\",\n              3: \"16:9\",\n              4: \"4:3\",\n            },\n            value: AppSettingsController.instance.scaleMode.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setScaleMode(e);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.defaultQualityFocusNode,\n            autofocus: controller.defaultQualityFocusNode.isFoucsed.value,\n            title: \"默认清晰度\",\n            items: const {\n              0: \"最低画质\",\n              1: \"中等画质\",\n              2: \"最高画质\",\n            },\n            value: AppSettingsController.instance.qualityLevel.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setQualityLevel(e);\n            },\n          ),\n        ),\n      ],\n    );\n  }\n\n  Widget buildFollowSettings() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA48,\n      children: [\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.autoUpdateFollowEnableFocusNode,\n            autofocus:\n                controller.autoUpdateFollowEnableFocusNode.isFoucsed.value,\n            title: \"自动更新关注\",\n            items: const {\n              0: \"关\",\n              1: \"开\",\n            },\n            value: AppSettingsController.instance.autoUpdateFollowEnable.value\n                ? 1\n                : 0,\n            onChanged: (e) {\n              AppSettingsController.instance\n                  .setAutoUpdateFollowEnable(e == 1 ? true : false);\n              FollowUserService.instance.initTimer();\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.autoUpdateFollowDurationFocusNode,\n            autofocus:\n                controller.autoUpdateFollowDurationFocusNode.isFoucsed.value,\n            title: \"自动更新间隔\",\n            items: const {\n              5: \"5分钟\",\n              10: \"10分钟\",\n              15: \"15分钟\",\n              20: \"20分钟\",\n              25: \"25分钟\",\n              30: \"30分钟\",\n              60: \"1小时\",\n            },\n            value:\n                AppSettingsController.instance.autoUpdateFollowDuration.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setAutoUpdateFollowDuration(e);\n              FollowUserService.instance.initTimer();\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.updateFollowThreadFocusNode,\n            autofocus: controller.updateFollowThreadFocusNode.isFoucsed.value,\n            title: \"更新线程数\",\n            items: const {\n              1: \"1\",\n              2: \"2\",\n              3: \"3\",\n              4: \"4\",\n              6: \"6\",\n              8: \"8\",\n              10: \"10\",\n              12: \"12\",\n            },\n            value: AppSettingsController.instance.updateFollowThreadCount.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setUpdateFollowThreadCount(e);\n            },\n          ),\n        ),\n      ],\n    );\n  }\n\n  Widget buildDanmakuSettings() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA48,\n      children: [\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuFoucsNode,\n            autofocus: controller.danmakuFoucsNode.isFoucsed.value,\n            title: \"弹幕开关\",\n            items: const {\n              0: \"关\",\n              1: \"开\",\n            },\n            value: AppSettingsController.instance.danmuEnable.value ? 1 : 0,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuEnable(e == 1);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuSizeFoucsNode,\n            autofocus: controller.danmakuSizeFoucsNode.isFoucsed.value,\n            title: \"弹幕大小\",\n            items: {\n              24.0: \"24\",\n              32.0: \"32\",\n              40.0: \"40\",\n              48.0: \"48\",\n              56.0: \"56\",\n              64.0: \"64\",\n              72.0: \"72\",\n            },\n            value: AppSettingsController.instance.danmuSize.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuSize(e);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuSpeedFoucsNode,\n            autofocus: controller.danmakuSpeedFoucsNode.isFoucsed.value,\n            title: \"弹幕速度\",\n            items: {\n              18.0: \"很慢\",\n              14.0: \"较慢\",\n              12.0: \"慢\",\n              10.0: \"正常\",\n              8.0: \"快\",\n              6.0: \"较快\",\n              4.0: \"很快\",\n            },\n            value: AppSettingsController.instance.danmuSpeed.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuSpeed(e);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuAreaFoucsNode,\n            autofocus: controller.danmakuAreaFoucsNode.isFoucsed.value,\n            title: \"显示区域\",\n            items: {\n              0.25: \"1/4\",\n              0.5: \"1/2\",\n              0.75: \"3/4\",\n              1.0: \"全屏\",\n            },\n            value: AppSettingsController.instance.danmuArea.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuArea(e);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuOpacityFoucsNode,\n            autofocus: controller.danmakuOpacityFoucsNode.isFoucsed.value,\n            title: \"不透明度\",\n            items: {\n              0.1: \"10%\",\n              0.2: \"20%\",\n              0.3: \"30%\",\n              0.4: \"40%\",\n              0.5: \"50%\",\n              0.6: \"60%\",\n              0.7: \"70%\",\n              0.8: \"80%\",\n              0.9: \"90%\",\n              1.0: \"100%\",\n            },\n            value: AppSettingsController.instance.danmuOpacity.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuOpacity(e);\n            },\n          ),\n        ),\n        AppStyle.vGap24,\n        Obx(\n          () => SettingsItemWidget(\n            foucsNode: controller.danmakuStorkeFoucsNode,\n            autofocus: controller.danmakuStorkeFoucsNode.isFoucsed.value,\n            title: \"描边宽度\",\n            items: {\n              2.0: \"2\",\n              4.0: \"4\",\n              6.0: \"6\",\n              8.0: \"8\",\n              10.0: \"10\",\n              12.0: \"12\",\n              14.0: \"14\",\n              16.0: \"16\",\n            },\n            value: AppSettingsController.instance.danmuStrokeWidth.value,\n            onChanged: (e) {\n              AppSettingsController.instance.setDanmuStrokeWidth(e);\n            },\n          ),\n        ),\n      ],\n    );\n  }\n\n  Widget buildAccountSettings() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA48,\n      children: [\n        Obx(\n          () => HighlightListTile(\n            focusNode: controller.bilibiliFoucsNode,\n            autofocus: controller.bilibiliFoucsNode.isFoucsed.value,\n            title: \"哔哩哔哩账号\",\n            subtitle: BiliBiliAccountService.instance.logined.value\n                ? \"已登录：${BiliBiliAccountService.instance.name.value}\"\n                : \"未登录，点击登录\",\n            leading: Image.asset(\n              \"assets/images/bilibili.png\",\n              width: 64.w,\n              height: 64.w,\n            ),\n            onTap: controller.bilibiliTap,\n          ),\n        ),\n        AppStyle.vGap24,\n        HighlightListTile(\n          focusNode: AppFocusNode(),\n          title: \"斗鱼账号\",\n          subtitle: \"无需登录\",\n          leading: Image.asset(\n            \"assets/images/douyu.png\",\n            width: 64.w,\n            height: 64.w,\n          ),\n          onTap: () {\n            SmartDialog.showToast(\"无需登录斗鱼，您可以直接观看直播\");\n          },\n        ),\n        AppStyle.vGap24,\n        HighlightListTile(\n          focusNode: AppFocusNode(),\n          title: \"虎牙账号\",\n          subtitle: \"无需登录\",\n          leading: Image.asset(\n            \"assets/images/huya.png\",\n            width: 64.w,\n            height: 64.w,\n          ),\n          onTap: () {\n            SmartDialog.showToast(\"无需登录虎牙，您可以直接观看直播\");\n          },\n        ),\n        AppStyle.vGap24,\n        HighlightListTile(\n          focusNode: AppFocusNode(),\n          title: \"抖音账号\",\n          subtitle: \"无需登录\",\n          leading: Image.asset(\n            \"assets/images/douyin.png\",\n            width: 64.w,\n            height: 64.w,\n          ),\n          onTap: () {\n            SmartDialog.showToast(\"无需登录抖音，您可以直接观看直播\");\n          },\n        )\n      ],\n    );\n  }\n\n  Widget buildAbout() {\n    return ListView(\n      padding: AppStyle.edgeInsetsA48,\n      children: [\n        HighlightListTile(\n          focusNode: controller.versionFocusNode,\n          title: \"版本\",\n          subtitle: \"v${Utils.packageInfo.version}\",\n          onTap: controller.checkUpdate,\n        ),\n      ],\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/sync/sync_controller.dart",
    "content": "import 'dart:async';\nimport 'dart:convert';\n\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/event_bus.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\nimport 'package:simple_live_tv_app/models/db/history.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\nimport 'package:simple_live_tv_app/services/signalr_service.dart';\n\nclass SyncController extends BaseController {\n  final SignalRService signalR = SignalRService();\n  StreamSubscription? _stateSubscription;\n  StreamSubscription? _roomDestroyedSubscription;\n  StreamSubscription? _roomUserUpdatedSubscription;\n  StreamSubscription? _onFavoriteSubscription;\n  StreamSubscription? _onHistorySubscription;\n  StreamSubscription? _onShieldWordSubscription;\n  StreamSubscription? _onBiliAccountSubscription;\n  var currentRoomId = \"--\".obs;\n  RxList<RoomUser> roomUsers = <RoomUser>[].obs;\n  Timer? _timer;\n  var countDown = 600.obs;\n\n  Rx<SignalRConnectionState> state =\n      Rx<SignalRConnectionState>(SignalRConnectionState.connecting);\n\n  @override\n  void onInit() {\n    connect();\n    super.onInit();\n  }\n\n  void connect() async {\n    listenSignalR();\n    await signalR.connect();\n    if (signalR.state == SignalRConnectionState.connected) {\n      createRoom();\n    }\n  }\n\n  void createRoom() async {\n    try {\n      var resp = await signalR.createRoom();\n      if (resp.isSuccess) {\n        currentRoomId.value = resp.data!;\n        _startTimer();\n      } else {\n        SmartDialog.showToast(resp.message);\n        Get.back();\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"创建房间失败\");\n      Get.back();\n    }\n  }\n\n  void _startTimer() {\n    // 倒计时5分钟，自动关闭页面\n    countDown.value = 600;\n    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {\n      countDown--;\n      if (countDown <= 0) {\n        timer.cancel();\n        Get.back();\n      }\n    });\n  }\n\n  void listenSignalR() {\n    _stateSubscription = signalR.stateStream.listen((event) {\n      state.value = event;\n    });\n    _roomDestroyedSubscription = signalR.onRoomDestroyedStream.listen((roomId) {\n      SmartDialog.showToast(\"房间已被销毁\");\n      Get.back();\n    });\n    _roomUserUpdatedSubscription = signalR.onRoomUserUpdatedStream.listen(\n      (roomUsers) {\n        this.roomUsers.assignAll(roomUsers);\n      },\n    );\n    _onFavoriteSubscription = signalR.onFavoriteStream.listen((data) {\n      onReceiveFavorite(data.$1, data.$2);\n    });\n    _onHistorySubscription = signalR.onHistoryStream.listen((data) {\n      onReceiveHistory(data.$1, data.$2);\n    });\n    _onShieldWordSubscription = signalR.onShieldWordStream.listen((data) {\n      onReceiveShieldWord(data.$1, data.$2);\n    });\n    _onBiliAccountSubscription = signalR.onBiliAccountStream.listen((data) {\n      onReceiveBiliAccount(data.$1, data.$2);\n    });\n  }\n\n  void onReceiveFavorite(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        await DBService.instance.followBox.clear();\n      }\n      for (var item in jsonBody) {\n        var user = FollowUser.fromJson(item);\n        await DBService.instance.followBox.put(user.id, user);\n      }\n      SmartDialog.showToast('已同步关注用户列表');\n      EventBus.instance.emit(Constant.kUpdateFollow, 0);\n      SmartDialog.showToast(\"已同步关注列表\");\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveHistory(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        await DBService.instance.historyBox.clear();\n      }\n      for (var item in jsonBody) {\n        var history = History.fromJson(item);\n        if (DBService.instance.historyBox.containsKey(history.id)) {\n          var old = DBService.instance.historyBox.get(history.id);\n          //如果本地的更新时间比较新，就不更新\n          if (old!.updateTime.isAfter(history.updateTime)) {\n            continue;\n          }\n        }\n        await DBService.instance.addOrUpdateHistory(history);\n      }\n      SmartDialog.showToast('已同步历史记录');\n      EventBus.instance.emit(Constant.kUpdateHistory, 0);\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveShieldWord(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      if (overlay) {\n        AppSettingsController.instance.clearShieldList();\n      }\n      for (var item in jsonBody) {\n        AppSettingsController.instance.addShieldList(item);\n      }\n      SmartDialog.showToast('已同步屏蔽词');\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  void onReceiveBiliAccount(bool overlay, String data) async {\n    try {\n      var jsonBody = json.decode(data);\n      var cookie = jsonBody['cookie'];\n      BiliBiliAccountService.instance.setCookie(cookie);\n      BiliBiliAccountService.instance.loadUserInfo();\n      SmartDialog.showToast('已同步哔哩哔哩账号');\n    } catch (e) {\n      SmartDialog.showToast(\"同步失败:$e\");\n      Log.logPrint(e);\n    }\n  }\n\n  @override\n  void onClose() {\n    _timer?.cancel();\n    _stateSubscription?.cancel();\n    _roomDestroyedSubscription?.cancel();\n    _roomUserUpdatedSubscription?.cancel();\n    _onFavoriteSubscription?.cancel();\n    _onHistorySubscription?.cancel();\n    _onShieldWordSubscription?.cancel();\n    _onBiliAccountSubscription?.cancel();\n    signalR.dispose();\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/modules/sync/sync_page.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:qr_flutter/qr_flutter.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/modules/sync/sync_controller.dart';\nimport 'package:simple_live_tv_app/services/signalr_service.dart';\nimport 'package:simple_live_tv_app/services/sync_service.dart';\nimport 'package:simple_live_tv_app/widgets/app_scaffold.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\n\nclass SyncPage extends GetView<SyncController> {\n  const SyncPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AppScaffold(\n      child: Column(\n        children: [\n          AppStyle.vGap24,\n          Row(\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              AppStyle.hGap48,\n              HighlightButton(\n                focusNode: AppFocusNode(),\n                iconData: Icons.arrow_back,\n                text: \"返回\",\n                autofocus: true,\n                onTap: () {\n                  Get.back();\n                },\n              ),\n              AppStyle.hGap32,\n              Text(\n                \"数据同步\",\n                style: AppStyle.titleStyleWhite.copyWith(\n                  fontSize: 36.w,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n              const Spacer(),\n            ],\n          ),\n          AppStyle.vGap24,\n          Expanded(\n            child: Row(\n              children: [\n                Expanded(\n                  child: Column(\n                    crossAxisAlignment: CrossAxisAlignment.center,\n                    mainAxisAlignment: MainAxisAlignment.center,\n                    children: [\n                      Text(\n                        \"远程同步\",\n                        style: AppStyle.titleStyleWhite.copyWith(\n                          fontSize: 32.w,\n                          fontWeight: FontWeight.bold,\n                        ),\n                      ),\n                      AppStyle.vGap16,\n                      Obx(\n                        () => Visibility(\n                          visible: SyncService.instance.httpRunning.value,\n                          child: GestureDetector(\n                            onTap: () {\n                              Get.back();\n                            },\n                            child: QrImageView(\n                              data: controller.currentRoomId.value,\n                              version: QrVersions.auto,\n                              backgroundColor: Colors.white,\n                              padding: AppStyle.edgeInsetsA24,\n                              size: 420.0.w,\n                            ),\n                          ),\n                        ),\n                      ),\n                      AppStyle.vGap24,\n                      Obx(\n                        () => Visibility(\n                          visible: controller.state.value ==\n                              SignalRConnectionState.connected,\n                          child: Text.rich(\n                            TextSpan(\n                              text: '房间号：',\n                              children: [\n                                TextSpan(\n                                  text: controller.currentRoomId.value,\n                                  style: AppStyle.textStyleWhite\n                                      .copyWith(fontWeight: FontWeight.bold),\n                                )\n                              ],\n                            ),\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                      Obx(\n                        () => Visibility(\n                          visible: controller.state.value ==\n                              SignalRConnectionState.disconnected,\n                          child: Text(\n                            '连接已断开，请尝试重进此页面',\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                      Obx(\n                        () => Visibility(\n                          visible: controller.state.value ==\n                              SignalRConnectionState.connecting,\n                          child: Text(\n                            '正在创建房间...',\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                      AppStyle.vGap12,\n                      Obx(\n                        () => Visibility(\n                          visible: controller.state.value ==\n                              SignalRConnectionState.connected,\n                          child: Text(\n                            \"${controller.countDown}秒后将自动关闭服务\\n请扫描二维码或输入房间号进行连接\",\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                    ],\n                  ),\n                ),\n                VerticalDivider(\n                  color: Colors.white.withAlpha(50),\n                  thickness: 2.w,\n                  endIndent: 120.w,\n                  indent: 120.w,\n                ),\n                Expanded(\n                  child: Column(\n                    crossAxisAlignment: CrossAxisAlignment.center,\n                    mainAxisAlignment: MainAxisAlignment.center,\n                    children: [\n                      Text(\n                        \"局域网同步\",\n                        style: AppStyle.titleStyleWhite.copyWith(\n                          fontSize: 32.w,\n                          fontWeight: FontWeight.bold,\n                        ),\n                      ),\n                      AppStyle.vGap16,\n                      Obx(\n                        () => Visibility(\n                          visible: SyncService.instance.httpRunning.value,\n                          child: GestureDetector(\n                            onTap: () {\n                              Get.back();\n                            },\n                            child: QrImageView(\n                              data: SyncService.instance.ipAddress.value,\n                              version: QrVersions.auto,\n                              backgroundColor: Colors.white,\n                              padding: AppStyle.edgeInsetsA24,\n                              size: 420.0.w,\n                            ),\n                          ),\n                        ),\n                      ),\n                      AppStyle.vGap24,\n                      Obx(\n                        () => Visibility(\n                          visible: SyncService.instance.httpRunning.value,\n                          child: Text(\n                            '服务已启动：${SyncService.instance.ipAddress.value.split(';').map((e) => '$e:${SyncService.httpPort}').join('；')}',\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                      Obx(\n                        () => Visibility(\n                          visible: !SyncService.instance.httpRunning.value,\n                          child: Text(\n                            'HTTP服务未启动：${SyncService.instance.httpErrorMsg}，请尝试重启应用',\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                      AppStyle.vGap12,\n                      Obx(\n                        () => Visibility(\n                          visible: SyncService.instance.httpRunning.value,\n                          child: Text(\n                            \"请扫描二维码或输入IP地址进行连接\\n建立连接后可在APP端选择需要同步至TV端的数据\",\n                            style: AppStyle.textStyleWhite,\n                            textAlign: TextAlign.center,\n                          ),\n                        ),\n                      ),\n                    ],\n                  ),\n                ),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/requests/common_request.dart",
    "content": "import 'dart:convert';\n\nimport 'package:simple_live_tv_app/models/version_model.dart';\nimport 'package:simple_live_tv_app/requests/http_client.dart';\n\n/// 通用的请求\nclass CommonRequest {\n  Future<VersionModel> checkUpdate() async {\n    try {\n      return await checkUpdateGitMirror();\n    } catch (e) {\n      return await checkUpdateJsDelivr();\n    }\n  }\n\n  /// 检查更新\n  Future<VersionModel> checkUpdateGitMirror() async {\n    var result = await HttpClient.instance.getJson(\n      \"https://raw.gitmirror.com/xiaoyaocz/dart_simple_live/master/assets/tv_app_version.json\",\n      queryParameters: {\n        \"ts\": DateTime.now().millisecondsSinceEpoch,\n      },\n    );\n    if (result is Map) {\n      return VersionModel.fromJson(result as Map<String, dynamic>);\n    }\n    return VersionModel.fromJson(json.decode(result));\n  }\n\n  /// 检查更新\n  Future<VersionModel> checkUpdateJsDelivr() async {\n    var result = await HttpClient.instance.getJson(\n      \"https://cdn.jsdelivr.net/gh/xiaoyaocz/dart_simple_live@master/assets/tv_app_version.json\",\n      queryParameters: {\n        \"ts\": DateTime.now().millisecondsSinceEpoch,\n      },\n    );\n    if (result is Map) {\n      return VersionModel.fromJson(result as Map<String, dynamic>);\n    }\n    return VersionModel.fromJson(json.decode(result));\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/requests/custom_log_interceptor.dart",
    "content": "import 'package:dio/dio.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\n\nclass CustomLogInterceptor extends Interceptor {\n  @override\n  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {\n    options.extra[\"ts\"] = DateTime.now().millisecondsSinceEpoch;\n\n    super.onRequest(options, handler);\n  }\n\n  @override\n  void onError(DioException err, ErrorInterceptorHandler handler) {\n    var time =\n        DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra[\"ts\"];\n    Log.e('''【HTTP请求错误-${err.type}】 耗时:${time}ms\n${err.message}\n\nRequest Method：${err.requestOptions.method}\nResponse Code：${err.response?.statusCode}\nRequest URL：${err.requestOptions.uri}\nRequest Query：${err.requestOptions.queryParameters}\nRequest Data：${err.requestOptions.data}\nRequest Headers：${err.requestOptions.headers}\nResponse Headers：${err.response?.headers.map}\nResponse Data：${err.response?.data}''', err.stackTrace);\n    super.onError(err, handler);\n  }\n\n  @override\n  void onResponse(Response response, ResponseInterceptorHandler handler) {\n    var time = DateTime.now().millisecondsSinceEpoch -\n        response.requestOptions.extra[\"ts\"];\n    Log.i(\n      '''【HTTP请求响应】 耗时:${time}ms\nRequest Method：${response.requestOptions.method}\nRequest Code：${response.statusCode}\nRequest URL：${response.requestOptions.uri}\nRequest Query：${response.requestOptions.queryParameters}\nRequest Data：${response.requestOptions.data}\nRequest Headers：${response.requestOptions.headers}\nResponse Headers：${response.headers.map}\nResponse Data：${response.data}''',\n    );\n    super.onResponse(response, handler);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/requests/http_client.dart",
    "content": "import 'package:dio/dio.dart';\nimport 'package:simple_live_tv_app/requests/custom_log_interceptor.dart';\nimport 'package:simple_live_tv_app/requests/http_error.dart';\n\nclass HttpClient {\n  static HttpClient? _httpUtil;\n\n  static HttpClient get instance {\n    _httpUtil ??= HttpClient();\n    return _httpUtil!;\n  }\n\n  late Dio dio;\n  HttpClient() {\n    dio = Dio(\n      BaseOptions(\n        connectTimeout: const Duration(seconds: 20),\n        receiveTimeout: const Duration(seconds: 20),\n        sendTimeout: const Duration(seconds: 20),\n      ),\n    );\n    dio.interceptors.add(CustomLogInterceptor());\n  }\n\n  /// Get请求，返回String\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<String> getText(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.plain,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Get请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<dynamic> getJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Get请求，返回Response\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<Response<dynamic>> get(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.get(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n        ),\n        cancelToken: cancel,\n      );\n      return result;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送GET请求失败\");\n      }\n    }\n  }\n\n  /// Post请求，返回Map\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [data] 内容\n  /// * [cancel] 任务取消Token\n  Future<dynamic> postJson(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    dynamic data,\n    Map<String, dynamic>? header,\n    bool formUrlEncoded = false,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      data ??= {};\n      var result = await dio.post(\n        url,\n        queryParameters: queryParameters,\n        data: data,\n        options: Options(\n          responseType: ResponseType.json,\n          headers: header,\n          contentType:\n              formUrlEncoded ? Headers.formUrlEncodedContentType : null,\n        ),\n        cancelToken: cancel,\n      );\n      return result.data;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        throw HttpError(e.message ?? \"\",\n            statusCode: e.response?.statusCode ?? 0);\n      } else {\n        throw HttpError(\"发送POST请求失败\");\n      }\n    }\n  }\n\n  /// Head请求，返回Response\n  /// * [url] 请求链接\n  /// * [queryParameters] 请求参数\n  /// * [cancel] 任务取消Token\n  Future<Response> head(\n    String url, {\n    Map<String, dynamic>? queryParameters,\n    Map<String, dynamic>? header,\n    CancelToken? cancel,\n  }) async {\n    try {\n      queryParameters ??= {};\n      header ??= {};\n      var result = await dio.head(\n        url,\n        queryParameters: queryParameters,\n        options: Options(\n          headers: header,\n          receiveDataWhenStatusError: true,\n        ),\n        cancelToken: cancel,\n      );\n      return result;\n    } catch (e) {\n      if (e is DioException && e.type == DioExceptionType.badResponse) {\n        return e.response!;\n      } else {\n        throw HttpError(\"发送HEAD请求失败\");\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/requests/http_error.dart",
    "content": "class HttpError extends Error {\n  /// 错误码\n  final int statusCode;\n\n  /// 错误信息\n  final String message;\n\n  HttpError(\n    this.message, {\n    this.statusCode = 0,\n  });\n  @override\n  String toString() {\n    if (statusCode != 0) {\n      return statusCodeToString(statusCode);\n    }\n\n    return message;\n  }\n\n  String statusCodeToString(int statusCode) {\n    switch (statusCode) {\n      case 400:\n        return \"错误的请求(400)\";\n      case 401:\n        return \"无权限访问资源(401)\";\n      case 403:\n        return \"无权限访问资源(403)\";\n      case 404:\n        return \"服务器找不到请求的资源(404)\";\n      case 500:\n        return \"服务器出现错误(500)\";\n      case 502:\n        return \"服务器出现错误(502)\";\n      case 503:\n        return \"服务器出现错误(503)\";\n      default:\n        return \"连接服务器失败，请稍后再试($statusCode)\";\n    }\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/routes/app_navigation.dart",
    "content": "import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/modules/category/category_controller.dart';\nimport 'package:simple_live_tv_app/routes/route_path.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\n\n/// APP页面跳转封装\n/// * 需要参数的页面都应使用此类\n/// * 如不需要参数，可以使用Get.toNamed\nclass AppNavigator {\n  /// 跳转至直播间\n  static void toLiveRoomDetail(\n      {required Site site, required String roomId}) async {\n    if (site.id == Constant.kBiliBili &&\n        !BiliBiliAccountService.instance.logined.value &&\n        AppSettingsController.instance.bilibiliLoginTip.value) {\n      await toBiliBiliLogin();\n      if (!BiliBiliAccountService.instance.logined.value) {\n        SmartDialog.showToast(\"未完成登录\");\n        return;\n      }\n    }\n\n    Get.toNamed(RoutePath.kLiveRoomDetail, arguments: site, parameters: {\n      \"roomId\": roomId,\n    });\n  }\n\n  /// 跳转至哔哩哔哩登录\n  static Future toBiliBiliLogin() async {\n    await Get.toNamed(RoutePath.kBiliBiliQRLogin);\n  }\n\n  /// 跳转至分类详情\n  static void toCategoryDetail(\n      {required Site site, required LiveSubCategoryExt category}) {\n    Get.toNamed(RoutePath.kCategoryDetail, arguments: [site, category]);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/routes/app_pages.dart",
    "content": "// ignore_for_file: prefer_inlined_adds\n\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/modules/account/bilibili/qr_login_controller.dart';\nimport 'package:simple_live_tv_app/modules/account/bilibili/qr_login_page.dart';\nimport 'package:simple_live_tv_app/modules/agreement/agreement_page.dart';\nimport 'package:simple_live_tv_app/modules/category/category_controller.dart';\nimport 'package:simple_live_tv_app/modules/category/category_page.dart';\nimport 'package:simple_live_tv_app/modules/category/detail/category_detail_controller.dart';\nimport 'package:simple_live_tv_app/modules/category/detail/category_detail_page.dart';\nimport 'package:simple_live_tv_app/modules/follow_user/follow_user_page.dart';\nimport 'package:simple_live_tv_app/modules/history/history_controller.dart';\nimport 'package:simple_live_tv_app/modules/history/history_page.dart';\nimport 'package:simple_live_tv_app/modules/home/home_controller.dart';\nimport 'package:simple_live_tv_app/modules/home/home_page.dart';\nimport 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart';\nimport 'package:simple_live_tv_app/modules/hot_live/hot_live_page.dart';\nimport 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart';\nimport 'package:simple_live_tv_app/modules/live_room/live_room_page.dart';\nimport 'package:simple_live_tv_app/modules/search/anchor/search_anchor_controller.dart';\nimport 'package:simple_live_tv_app/modules/search/anchor/search_anchor_page.dart';\nimport 'package:simple_live_tv_app/modules/search/room/search_room_controller.dart';\nimport 'package:simple_live_tv_app/modules/search/room/search_room_page.dart';\nimport 'package:simple_live_tv_app/modules/settings/settings_controller.dart';\nimport 'package:simple_live_tv_app/modules/settings/settings_page.dart';\nimport 'package:simple_live_tv_app/modules/sync/sync_controller.dart';\nimport 'package:simple_live_tv_app/modules/sync/sync_page.dart';\n\nimport 'route_path.dart';\n\nclass AppPages {\n  AppPages._();\n  static final routes = [\n    GetPage(\n      name: RoutePath.kAgreement,\n      page: () => const AgreementPage(),\n    ),\n    // 首页\n    GetPage(\n      name: RoutePath.kHome,\n      page: () => const HomePage(),\n      bindings: [\n        BindingsBuilder.put(() => HomeController()),\n      ],\n    ),\n    // 数据同步\n    GetPage(\n      name: RoutePath.kSync,\n      page: () => const SyncPage(),\n      bindings: [\n        BindingsBuilder.put(() => SyncController()),\n      ],\n    ),\n\n    // 关注\n    GetPage(\n      name: RoutePath.kFollow,\n      page: () => const FollowUserPage(),\n    ),\n\n    //直播间\n    GetPage(\n      name: RoutePath.kLiveRoomDetail,\n      page: () => const LiveRoomPage(),\n      binding: BindingsBuilder.put(\n        () => LiveRoomController(\n          pSite: Get.arguments,\n          pRoomId: Get.parameters[\"roomId\"] ?? \"\",\n        ),\n      ),\n    ),\n    //哔哩哔哩二维码登录\n    GetPage(\n      name: RoutePath.kBiliBiliQRLogin,\n      page: () => const BiliBiliQRLoginPage(),\n      bindings: [\n        BindingsBuilder.put(() => BiliBiliQRLoginController()),\n      ],\n    ),\n    // 设置\n    GetPage(\n      name: RoutePath.kSettings,\n      page: () => const SettingsPage(),\n      bindings: [\n        BindingsBuilder.put(() => SettingsController()),\n      ],\n    ),\n    // 历史记录\n    GetPage(\n      name: RoutePath.kHistory,\n      page: () => const HistoryPage(),\n      bindings: [\n        BindingsBuilder.put(() => HistoryController()),\n      ],\n    ),\n    //热门直播\n    GetPage(\n      name: RoutePath.kHotLive,\n      page: () => const HotLivePage(),\n      bindings: [\n        BindingsBuilder.put(() => HotliveController()),\n      ],\n    ),\n    //分类\n    GetPage(\n      name: RoutePath.kCategory,\n      page: () => const CategoryPage(),\n      bindings: [\n        BindingsBuilder.put(() => CategoryController()),\n      ],\n    ),\n    //分类\n    GetPage(\n      name: RoutePath.kCategoryDetail,\n      page: () => const CategoryDetailPage(),\n      binding: BindingsBuilder.put(\n        () => CategoryDetailController(\n          site: Get.arguments[0],\n          subCategory: Get.arguments[1],\n        ),\n      ),\n    ),\n    // 搜索房间\n    GetPage(\n      name: RoutePath.kSearchRoom,\n      page: () => const SearchRoomPage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => SearchRoomController(\n            Get.arguments,\n          ),\n        ),\n      ],\n    ),\n    // 搜索主播\n    GetPage(\n      name: RoutePath.kSearchAnchor,\n      page: () => const SearchAnchorPage(),\n      bindings: [\n        BindingsBuilder.put(\n          () => SearchAnchorController(\n            Get.arguments,\n          ),\n        ),\n      ],\n    ),\n  ];\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/routes/route_path.dart",
    "content": "/// 路由路径\nclass RoutePath {\n  /// 用户协议\n  static const kAgreement = \"/agreement\";\n\n  /// 首页\n  static const kHome = \"/home\";\n\n  /// 数据同步\n  static const kSync = \"/sync\";\n\n  /// 搜索房间\n  static const kSearchRoom = \"/search/room\";\n\n  /// 搜索主播\n  static const kSearchAnchor = \"/search/anchor\";\n\n  /// 关注\n  static const kFollow = \"/follow\";\n\n  /// 历史记录\n  static const kHistory = \"/history\";\n\n  /// 直播间\n  static const kLiveRoomDetail = \"/room/detail\";\n\n  /// 哔哩哔哩登录\n  static const kBiliBiliQRLogin = \"/bilibili/qr_login\";\n\n  /// 设置\n  static const kSettings = \"/settings\";\n\n  /// 热门直播\n  static const kHotLive = \"/hot_live\";\n\n  /// 分类\n  static const kCategory = \"/category\";\n\n  /// 分类详情\n  static const kCategoryDetail = \"/category/detail\";\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/bilibili_account_service.dart",
    "content": "import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_core/simple_live_core.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/models/account/bilibili_user_info_page.dart';\nimport 'package:simple_live_tv_app/requests/http_client.dart';\nimport 'package:simple_live_tv_app/services/local_storage_service.dart';\n\nclass BiliBiliAccountService extends GetxService {\n  static BiliBiliAccountService get instance =>\n      Get.find<BiliBiliAccountService>();\n\n  var logined = false.obs;\n\n  var cookie = \"\";\n  var uid = 0;\n  var name = \"未登录\".obs;\n\n  @override\n  void onInit() {\n    cookie = LocalStorageService.instance\n        .getValue(LocalStorageService.kBilibiliCookie, \"\");\n    logined.value = cookie.isNotEmpty;\n    loadUserInfo();\n    super.onInit();\n  }\n\n  Future loadUserInfo() async {\n    if (cookie.isEmpty) {\n      return;\n    }\n    try {\n      var result = await HttpClient.instance.getJson(\n        \"https://api.bilibili.com/x/member/web/account\",\n        header: {\n          \"Cookie\": cookie,\n        },\n      );\n      if (result[\"code\"] == 0) {\n        var info = BiliBiliUserInfoModel.fromJson(result[\"data\"]);\n        name.value = info.uname ?? \"未登录\";\n        uid = info.mid ?? 0;\n        setSite();\n      } else {\n        SmartDialog.showToast(\"哔哩哔哩登录已失效，请重新登录\");\n        logout();\n      }\n    } catch (e) {\n      SmartDialog.showToast(\"获取哔哩哔哩用户信息失败，可前往账号管理重试\");\n    }\n  }\n\n  void setSite() {\n    var site = (Sites.allSites[Constant.kBiliBili]!.liveSite as BiliBiliSite);\n    site.userId = uid;\n    site.cookie = cookie;\n  }\n\n  void setCookie(String cookie) {\n    this.cookie = cookie;\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliCookie, cookie);\n    logined.value = cookie.isNotEmpty;\n  }\n\n  void logout() async {\n    cookie = \"\";\n    uid = 0;\n    name.value = \"未登录\";\n    setSite();\n    LocalStorageService.instance\n        .setValue(LocalStorageService.kBilibiliCookie, \"\");\n    logined.value = false;\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/db_service.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:hive/hive.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\n\nimport 'package:simple_live_tv_app/models/db/history.dart';\n\nclass DBService extends GetxService {\n  static DBService get instance => Get.find<DBService>();\n  late Box<History> historyBox;\n  late Box<FollowUser> followBox;\n\n  Future init() async {\n    historyBox = await Hive.openBox(\"TVHostiry\");\n    followBox = await Hive.openBox(\"TVFollowUser\");\n  }\n\n  bool getFollowExist(String id) {\n    return followBox.containsKey(id);\n  }\n\n  List<FollowUser> getFollowList() {\n    return followBox.values.toList();\n  }\n\n  Future addFollow(FollowUser follow) async {\n    await followBox.put(follow.id, follow);\n  }\n\n  Future deleteFollow(String id) async {\n    await followBox.delete(id);\n  }\n\n  History? getHistory(String id) {\n    if (historyBox.containsKey(id)) {\n      return historyBox.get(id);\n    }\n    return null;\n  }\n\n  Future addOrUpdateHistory(History history) async {\n    await historyBox.put(history.id, history);\n  }\n\n  List<History> getHistores() {\n    var his = historyBox.values.toList();\n    his.sort((a, b) => b.updateTime.compareTo(a.updateTime));\n    return his;\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/follow_user_service.dart",
    "content": "import 'dart:async';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/app/event_bus.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\n\nclass FollowUserService extends BasePageController<FollowUser> {\n  static FollowUserService get instance => Get.find<FollowUserService>();\n  StreamSubscription<dynamic>? subscription;\n\n  RxList<FollowUser> livingList = RxList<FollowUser>();\n  Timer? updateTimer;\n  bool needUpdate = true;\n  @override\n  void onInit() {\n    subscription = EventBus.instance.listen(Constant.kUpdateFollow, (p0) {\n      needUpdate = false;\n      refreshData();\n    });\n\n    if (list.isEmpty) {\n      refreshData();\n    }\n    initTimer();\n    super.onInit();\n  }\n\n  void initTimer() {\n    if (AppSettingsController.instance.autoUpdateFollowEnable.value) {\n      updateTimer?.cancel();\n      updateTimer = Timer.periodic(\n        Duration(\n          minutes:\n              AppSettingsController.instance.autoUpdateFollowDuration.value,\n        ),\n        (timer) {\n          Log.logPrint(\"Update Follow Timer\");\n          refreshData();\n        },\n      );\n    } else {\n      updateTimer?.cancel();\n    }\n  }\n\n  var updatedCount = 0;\n  var updating = false.obs;\n  @override\n  Future<List<FollowUser>> getData(int page, int pageSize) async {\n    if (page > 1) {\n      return [];\n    }\n\n    var followList = DBService.instance.getFollowList();\n    if (needUpdate) {\n      startUpdateStatus(followList);\n    }\n    needUpdate = true;\n    if (followList.isEmpty) {\n      updating.value = false;\n    }\n    return followList;\n  }\n\n  void sortList() {\n    list.sort((a, b) => b.liveStatus.value.compareTo(a.liveStatus.value));\n    updateLivingList();\n  }\n\n  void updateLivingList() {\n    livingList.assignAll(list.where((x) => x.liveStatus.value == 2));\n  }\n\n  void startUpdateStatus(List<FollowUser> followList) async {\n    updatedCount = 0;\n    updating.value = true;\n\n    var threadCount =\n        AppSettingsController.instance.updateFollowThreadCount.value;\n\n    var tasks = <Future>[];\n    for (var i = 0; i < threadCount; i++) {\n      tasks.add(\n        Future(() async {\n          var start = i * followList.length ~/ threadCount;\n          var end = (i + 1) * followList.length ~/ threadCount;\n\n          // 确保 end 不超出列表长度\n          if (end > followList.length) {\n            end = followList.length;\n          }\n          var items = followList.sublist(start, end);\n          for (var item in items) {\n            await updateLiveStatus(item);\n          }\n        }),\n      );\n    }\n    await Future.wait(tasks);\n  }\n\n  Future updateLiveStatus(FollowUser item) async {\n    try {\n      var site = Sites.allSites[item.siteId]!;\n      item.liveStatus.value =\n          (await site.liveSite.getLiveStatus(roomId: item.roomId)) ? 2 : 1;\n      //sortList();\n      //updateLivingList();\n    } catch (e) {\n      Log.logPrint(e);\n    } finally {\n      updatedCount++;\n      if (updatedCount >= list.length) {\n        sortList();\n        updating.value = false;\n      }\n    }\n  }\n\n  void removeItem(FollowUser item, {bool refresh = true}) async {\n    var result =\n        await Utils.showAlertDialog(\"确定要取消关注${item.userName}吗?\", title: \"取消关注\");\n    if (!result) {\n      return;\n    }\n    await DBService.instance.followBox.delete(item.id);\n    if (refresh) {\n      refreshData();\n    } else {\n      list.remove(item);\n      livingList.remove(item);\n    }\n  }\n\n  @override\n  void onClose() {\n    updateTimer?.cancel();\n    subscription?.cancel();\n\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/local_storage_service.dart",
    "content": "import 'package:get/get.dart';\nimport 'package:hive/hive.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\n\nclass LocalStorageService extends GetxService {\n  static LocalStorageService get instance => Get.find<LocalStorageService>();\n\n  /// 首次运行\n  static const String kFirstRun = \"FirstRun\";\n\n  /// 缩放模式\n  static const String kPlayerScaleMode = \"ScaleMode\";\n\n  /// 网站排序\n  static const String kSiteSort = \"SiteSort\";\n\n  /// 首页排序\n  static const String kHomeSort = \"HomeSort\";\n\n  /// 显示模式\n  /// * [0] 跟随系统\n  /// * [1] 浅色模式\n  /// * [2] 深色模式\n  static const String kThemeMode = \"ThemeMode\";\n\n  /// DEBUG模式\n  static const String kDebugModeKey = \"DebugMode\";\n\n  /// 弹幕大小\n  static const String kDanmuSize = \"DanmuSize\";\n\n  /// 弹幕速度\n  static const String kDanmuSpeed = \"DanmuSpeed\";\n\n  /// 弹幕区域\n  static const String kDanmuArea = \"DanmuArea\";\n\n  /// 弹幕透明度\n  static const String kDanmuOpacity = \"DanmuOpacity\";\n\n  /// 弹幕描边大小\n  static const String kDanmuStrokeWidth = \"DanmuStrokeWidth\";\n\n  /// 弹幕-屏蔽滚动\n  static const String kDanmuHideScroll = \"DanmuHideScroll\";\n\n  /// 弹幕-屏蔽底部\n  static const String kDanmuHideBottom = \"DanmuHideBottom\";\n\n  /// 弹幕-屏蔽顶部\n  static const String kDanmuHideTop = \"DanmuHideTop\";\n\n  /// 弹幕-顶部边距\n  static const String kDanmuTopMargin = \"DanmuTopMargin\";\n\n  /// 弹幕-底部边距\n  static const String kDanmuBottomMargin = \"DanmuBottomMargin\";\n\n  /// 弹幕开启\n  static const String kDanmuEnable = \"DanmuEnable\";\n\n  /// 硬件解码\n  static const String kHardwareDecode = \"HardwareDecode\";\n\n  /// 聊天区文字大小\n  static const String kChatTextSize = \"ChatTextSize\";\n\n  /// 聊天区间隔\n  static const String kChatTextGap = \"ChatTextGap\";\n\n  /// 聊天区-气泡样式\n  static const String kChatBubbleStyle = \"ChatBubbleStyle\";\n\n  /// 播放清晰度，0=低，1=中，2=高\n  static const String kQualityLevel = \"QualityLevel\";\n\n  /// 蜂窝网络下播放清晰度，0=低，1=中，2=高\n  static const String kQualityLevelCellular = \"QualityLevelCellular\";\n\n  /// 开启定时关闭\n  static const String kAutoExitEnable = \"AutoExitEnable\";\n\n  /// 定时关闭时间（分钟）\n  static const String kAutoExitDuration = \"AutoExitDuration\";\n\n  /// 房间内定时关闭时间（分钟）\n  /// 需要一个不同的 key，因为用户在房间内设置的倒计时和全局的可能不同。\n  static const String kRoomAutoExitDuration = \"RoomAutoExitDuration\";\n\n  /// 播放器兼容模式\n  static const String kPlayerCompatMode = \"PlayerCompatMode\";\n\n  /// 播放器后台自动暂停\n  static const String kPlayerAutoPause = \"PlayerAutoPause\";\n\n  /// 播放器缓冲区大小\n  static const String kPlayerBufferSize = \"PlayerBufferSize\";\n\n  /// 自动全屏\n  static const String kAutoFullScreen = \"AutoFullScreen\";\n\n  /// 小窗隐藏弹幕\n  static const String kPIPHideDanmu = \"PIPHideDanmu\";\n\n  /// 哔哩哔哩cookie\n  static const String kBilibiliCookie = \"BilibiliCookie\";\n\n  ///主题色\n  static const String kStyleColor = \"kStyleColor\";\n\n  ///动态取色\n  static const String kIsDynamic = \"kIsDynamic\";\n\n  /// 提示哔哩哔哩登录\n  static const String kBilibiliLoginTip = \"BilibiliLoginTip\";\n\n  /// 开启自动更新关注\n  static const String kAutoUpdateFollowEnable = \"AutoUpdateFollowEnable\";\n\n  /// 定时自动更新关注间隔（分钟）\n  static const String kUpdateFollowDuration = \"AutoUpdateFollowDuration\";\n\n  /// 开启多线程更新关注\n  static const String kUpdateFollowThreadCount = \"UpdateFollowThreadCount\";\n\n  late Box settingsBox;\n  late Box<String> shieldBox;\n\n  Future init() async {\n    settingsBox = await Hive.openBox(\n      \"TVLocalStorage\",\n    );\n    shieldBox = await Hive.openBox(\n      \"TVDanmuShield\",\n    );\n  }\n\n  T getValue<T>(dynamic key, T defaultValue) {\n    try {\n      var value = settingsBox.get(key, defaultValue: defaultValue) as T;\n      Log.d(\"Get LocalStorage：$key\\r\\n$value\");\n      return value;\n    } catch (e) {\n      Log.logPrint(e);\n      return defaultValue;\n    }\n  }\n\n  Future setValue<T>(dynamic key, T value) async {\n    Log.d(\"Set LocalStorage：$key\\r\\n$value\");\n    return await settingsBox.put(key, value);\n  }\n\n  Future removeValue<T>(dynamic key) async {\n    Log.d(\"Remove LocalStorage：$key\");\n    return await settingsBox.delete(key);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/signalr_service.dart",
    "content": "import 'dart:async';\nimport 'package:signalr_netcore/signalr_client.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\n\nenum SignalRConnectionState {\n  connecting,\n  connected,\n  disconnected,\n}\n\nclass SignalRService {\n  static const String kUrl = \"https://sync1.nsapps.cn/sync\";\n\n  SignalRConnectionState state = SignalRConnectionState.connecting;\n\n  final _stateStreamController =\n      StreamController<SignalRConnectionState>.broadcast();\n  Stream<SignalRConnectionState> get stateStream =>\n      _stateStreamController.stream;\n\n  final _onFavoriteStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onFavoriteStream =>\n      _onFavoriteStreamController.stream;\n\n  final _onHistoryStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onHistoryStream =>\n      _onHistoryStreamController.stream;\n\n  final _onShieldWordStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onShieldWordStream =>\n      _onShieldWordStreamController.stream;\n\n  final _onBiliAccountStreamController =\n      StreamController<(bool, String)>.broadcast();\n  Stream<(bool, String)> get onBiliAccountStream =>\n      _onBiliAccountStreamController.stream;\n\n  final _onRoomDestroyedStreamController = StreamController<String>.broadcast();\n  Stream<String> get onRoomDestroyedStream =>\n      _onRoomDestroyedStreamController.stream;\n\n  final _onRoomUserUpdatedStreamController =\n      StreamController<List<RoomUser>>.broadcast();\n  Stream<List<RoomUser>> get onRoomUserUpdatedStream =>\n      _onRoomUserUpdatedStreamController.stream;\n\n  HubConnection? hubConnection;\n  Future<void> connect() async {\n    hubConnection = HubConnectionBuilder().withUrl(kUrl).build();\n    hubConnection!.onclose(({Exception? error}) {\n      state = SignalRConnectionState.disconnected;\n      _stateStreamController.add(state);\n    });\n    hubConnection!.onreconnected(({String? connectionId}) {\n      Log.d(\"reconnected: $connectionId\");\n      state = SignalRConnectionState.connected;\n      _stateStreamController.add(state);\n    });\n    await hubConnection!.start();\n    state = SignalRConnectionState.connected;\n    _stateStreamController.add(state);\n    _listen();\n  }\n\n  void _listen() {\n    hubConnection?.on(\"onFavoriteReceived\", (args) {\n      _onFavoriteStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onHistoryReceived\", (args) {\n      _onHistoryStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onShieldWordReceived\", (args) {\n      _onShieldWordStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onBiliAccountReceived\", (args) {\n      _onBiliAccountStreamController.add((args![0] as bool, args[1] as String));\n    });\n    hubConnection?.on(\"onRoomDestroyed\", (args) {\n      _onRoomDestroyedStreamController.add(args![0].toString());\n    });\n    hubConnection?.on(\"onUserUpdated\", (args) {\n      var list = (args![0] as List).map((e) => RoomUser.fromObject(e)).toList();\n      _onRoomUserUpdatedStreamController.add(list);\n    });\n  }\n\n  Future<void> disconnect() async {\n    await hubConnection?.stop();\n    state = SignalRConnectionState.disconnected;\n    _stateStreamController.add(state);\n  }\n\n  Future<Resp<String>> createRoom() async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    String app = \"Simple Live TV\";\n    String platform = 'tv';\n    String version = Utils.packageInfo.version;\n    var resp = await hubConnection\n        ?.invoke(\"CreateRoom\", args: [app, platform, version]);\n    return Resp<String>.fromObject(resp);\n  }\n\n  Future<Resp> joinRoom(String roomId) async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    String app = \"Simple Live TV\";\n    String platform = 'tv';\n    String version = Utils.packageInfo.version;\n    var resp = await hubConnection\n        ?.invoke(\"JoinRoom\", args: [roomId, app, platform, version]);\n    return Resp.fromObject(resp);\n  }\n\n  Future<Resp> sendContent({\n    required String roomName,\n    required String action,\n    required bool overlay,\n    required String content,\n  }) async {\n    if (state != SignalRConnectionState.connected) {\n      throw Exception(\"not connected\");\n    }\n    var resp =\n        await hubConnection?.invoke(action, args: [roomName, overlay, content]);\n    return Resp.fromObject(resp);\n  }\n\n  void dispose() {\n    _stateStreamController.close();\n    _onFavoriteStreamController.close();\n    _onHistoryStreamController.close();\n    _onShieldWordStreamController.close();\n    _onBiliAccountStreamController.close();\n    _onRoomDestroyedStreamController.close();\n    _onRoomUserUpdatedStreamController.close();\n\n    hubConnection?.stop();\n  }\n}\n\nclass Resp<T> {\n  final bool isSuccess;\n  final String message;\n  final T? data;\n  Resp(this.isSuccess, this.message, this.data);\n\n  factory Resp.fromJson(Map<String, dynamic> json) {\n    return Resp(\n      json['isSuccess'],\n      json['message'] ?? \"\",\n      json['data'],\n    );\n  }\n\n  factory Resp.fromObject(Object? obj) {\n    if (obj is Map<String, dynamic>) {\n      return Resp.fromJson(obj);\n    }\n    return Resp(false, \"unknown\", null);\n  }\n}\n\nclass RoomUser {\n  final String connectionId;\n  final String shortId;\n  final String platform;\n  final String version;\n  final String app;\n  final bool? isCreator;\n\n  RoomUser({\n    required this.connectionId,\n    required this.shortId,\n    required this.platform,\n    required this.version,\n    required this.app,\n    this.isCreator = false,\n  });\n\n  factory RoomUser.fromJson(Map<String, dynamic> json) {\n    return RoomUser(\n      connectionId: json['connectionId'],\n      shortId: json['shortId'],\n      platform: json['platform'],\n      version: json['version'],\n      app: json['app'],\n      isCreator: json['isCreator'],\n    );\n  }\n\n  factory RoomUser.fromObject(Object? obj) {\n    if (obj is Map<String, dynamic>) {\n      return RoomUser.fromJson(obj);\n    }\n    return RoomUser(\n      connectionId: \"\",\n      shortId: \"\",\n      platform: \"\",\n      version: \"\",\n      app: \"\",\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/services/sync_service.dart",
    "content": "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:device_info_plus/device_info_plus.dart';\nimport 'package:flutter_smart_dialog/flutter_smart_dialog.dart';\nimport 'package:get/get.dart';\nimport 'package:network_info_plus/network_info_plus.dart';\nimport 'package:simple_live_tv_app/app/constant.dart';\nimport 'package:simple_live_tv_app/app/controller/app_settings_controller.dart';\nimport 'package:simple_live_tv_app/app/event_bus.dart';\nimport 'package:simple_live_tv_app/app/log.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/models/db/follow_user.dart';\nimport 'package:simple_live_tv_app/models/db/history.dart';\nimport 'package:simple_live_tv_app/services/bilibili_account_service.dart';\nimport 'package:simple_live_tv_app/services/db_service.dart';\nimport 'package:udp/udp.dart';\nimport 'package:shelf/shelf.dart' as shelf;\nimport 'package:shelf/shelf_io.dart' as shelf_io;\nimport 'package:shelf_router/shelf_router.dart';\nimport 'package:uuid/uuid.dart';\n\nclass SyncService extends GetxService {\n  static SyncService get instance => Get.find<SyncService>();\n\n  UDP? udp;\n  static const int udpPort = 23235;\n  static const int httpPort = 23234;\n  DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();\n  NetworkInfo networkInfo = NetworkInfo();\n  HttpServer? server;\n\n  var ipAddress = \"\".obs;\n  var httpRunning = false.obs;\n  var httpErrorMsg = \"\".obs;\n\n  var deviceId = \"\";\n  @override\n  void onInit() {\n    Log.d('SyncService init');\n    deviceId = (const Uuid().v4()).split('-').first;\n    listenUDP();\n    initServer();\n    super.onInit();\n  }\n\n  /// 监听来自其他客户端的UDP广播\n  /// - 如果收到广播，回复自己的信息\n  void listenUDP() async {\n    udp = await UDP.bind(Endpoint.any(port: const Port(udpPort)));\n    udp!.asStream().listen((datagram) {\n      var str = String.fromCharCodes(datagram!.data);\n      Log.i(\"Received: $str from ${datagram.address}:${datagram.port}\");\n      if (str.startsWith('{') && str.endsWith('}')) {\n        var data = json.decode(str);\n\n        //处理Hello的广播\n        if (data[\"type\"] == \"hello\") {\n          //如果http服务已经启动，就回复自己的信息\n          if (httpRunning.value) {\n            sendInfo();\n          }\n          return;\n        }\n      } else if (str == 'Who is SimpleLive?') {\n        //如果http服务已经启动，就回复自己的信息\n        if (httpRunning.value) {\n          sendInfo();\n        }\n      }\n    });\n  }\n\n  /// 发送自己的信息\n  void sendInfo() async {\n    //var ip = await getLocalIP();\n\n    var name = await getDeviceName();\n\n    var data = {\n      \"id\": deviceId,\n      \"type\": \"tv\",\n      \"name\": name,\n      //\"address\": ip,\n      //\"port\": httpPort,\n    };\n\n    await udp!.send(\n      json.encode(data).codeUnits,\n      Endpoint.broadcast(\n        port: const Port(udpPort),\n      ),\n    );\n    Log.i(\"send udp info: $data\");\n  }\n\n  /// 读取本地IP\n  /// - 如果是wifi，直接获取wifi的IP\n  /// - 如果是有线，获取所有的IP，找到全部的IP\n  Future<String> getLocalIP() async {\n    var ip = await networkInfo.getWifiIP();\n    if (ip == null || ip.isEmpty) {\n      var interfaces = await NetworkInterface.list();\n      var ipList = <String>[];\n      for (var interface in interfaces) {\n        for (var addr in interface.addresses) {\n          if (addr.type.name == 'IPv4' &&\n              !addr.address.startsWith('127') &&\n              !addr.isMulticast &&\n              !addr.isLoopback) {\n            ipList.add(addr.address);\n            break;\n          }\n        }\n      }\n      ip = ipList.join(';');\n    }\n    return ip;\n  }\n\n  Future<String> getDeviceName() async {\n    var name = \"SimpleLive-TV\";\n    if (Platform.isAndroid) {\n      var info = await deviceInfo.androidInfo;\n      name = info.model;\n    } else if (Platform.isIOS) {\n      var info = await deviceInfo.iosInfo;\n      name = info.name;\n    } else if (Platform.isMacOS) {\n      var info = await deviceInfo.macOsInfo;\n      name = info.computerName;\n    } else if (Platform.isLinux) {\n      var info = await deviceInfo.linuxInfo;\n      name = info.name;\n    } else if (Platform.isWindows) {\n      var info = await deviceInfo.windowsInfo;\n      name = info.userName;\n    }\n    return name;\n  }\n\n  /// 初始化HTTP服务\n  void initServer() async {\n    try {\n      var serverRouter = Router();\n      serverRouter.get('/', _helloRequest);\n      serverRouter.get('/info', _infoRequest);\n      serverRouter.post('/sync/follow', _syncFollowUserReuqest);\n      serverRouter.post('/sync/history', _syncHistoryReuqest);\n      serverRouter.post('/sync/blocked_word', _syncBlockedWordReuqest);\n      serverRouter.post('/sync/account/bilibili', _syncBiliAccountReuqest);\n\n      var server = await shelf_io.serve(\n        serverRouter.call,\n        InternetAddress.anyIPv4,\n        httpPort,\n      );\n\n      // Enable content compression\n      server.autoCompress = true;\n\n      httpRunning.value = true;\n\n      var ip = await getLocalIP();\n      ipAddress.value = ip;\n\n      Log.d('Serving at http://$ip:${server.port}');\n    } catch (e) {\n      httpErrorMsg.value = e.toString();\n      Log.logPrint(e);\n    }\n  }\n\n  /// 测试服务能否正常访问\n  shelf.Response _helloRequest(shelf.Request request) {\n    return toJsonResponse({\n      'status': true,\n      'message': 'http server is running...',\n      \"version\":\n          'SimpeLive ${Platform.operatingSystem} v${Utils.packageInfo.version}',\n    });\n  }\n\n  /// 发送自己的信息\n  Future<shelf.Response> _infoRequest(shelf.Request request) async {\n    var name = await getDeviceName();\n    return toJsonResponse({\n      \"id\": deviceId,\n      'type': 'tv',\n      'name': name,\n      'version': Utils.packageInfo.version,\n      'address': ipAddress.value,\n      'port': httpPort,\n    });\n  }\n\n  /// 同步关注用户列表\n  Future<shelf.Response> _syncFollowUserReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n\n      var body = await request.readAsString();\n      Log.d('_syncFollowUserReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        await DBService.instance.followBox.clear();\n      }\n      for (var item in jsonBody) {\n        var user = FollowUser.fromJson(item);\n        await DBService.instance.followBox.put(user.id, user);\n      }\n\n      SmartDialog.showToast('已同步关注用户列表');\n      EventBus.instance.emit(Constant.kUpdateFollow, 0);\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步观看记录\n  Future<shelf.Response> _syncHistoryReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n      var body = await request.readAsString();\n      Log.d('_syncFollowUserReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        await DBService.instance.historyBox.clear();\n      }\n      for (var item in jsonBody) {\n        var history = History.fromJson(item);\n        if (DBService.instance.historyBox.containsKey(history.id)) {\n          var old = DBService.instance.historyBox.get(history.id);\n          //如果本地的更新时间比较新，就不更新\n          if (old!.updateTime.isAfter(history.updateTime)) {\n            continue;\n          }\n        }\n        await DBService.instance.addOrUpdateHistory(history);\n      }\n\n      SmartDialog.showToast('已同步观看记录');\n      EventBus.instance.emit(Constant.kUpdateHistory, 0);\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步弹幕屏蔽词\n  Future<shelf.Response> _syncBlockedWordReuqest(shelf.Request request) async {\n    try {\n      var overlay =\n          int.parse(request.requestedUri.queryParameters['overlay'] ?? '0');\n      var body = await request.readAsString();\n      Log.d('_syncBlockedWordReuqest: $body');\n      var jsonBody = json.decode(body);\n      if (overlay == 1) {\n        AppSettingsController.instance.clearShieldList();\n      }\n      for (var keyword in jsonBody) {\n        AppSettingsController.instance.addShieldList(keyword.trim());\n      }\n      SmartDialog.showToast('已同步弹幕屏蔽词');\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  /// 同步哔哩哔哩账号\n  Future<shelf.Response> _syncBiliAccountReuqest(shelf.Request request) async {\n    try {\n      var body = await request.readAsString();\n      Log.d('_syncBiliAccountReuqest: $body');\n      var jsonBody = json.decode(body);\n      var cookie = jsonBody['cookie'];\n      BiliBiliAccountService.instance.setCookie(cookie);\n      BiliBiliAccountService.instance.loadUserInfo();\n      SmartDialog.showToast('已同步哔哩哔哩账号');\n      return toJsonResponse({\n        'status': true,\n        'message': 'success',\n      });\n    } catch (e) {\n      return toJsonResponse({\n        'status': false,\n        'message': e.toString(),\n      });\n    }\n  }\n\n  shelf.Response toJsonResponse(Map<String, dynamic> data) {\n    return shelf.Response.ok(\n      json.encode(data),\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      encoding: Encoding.getByName('utf-8'),\n    );\n  }\n\n  @override\n  void onClose() {\n    Log.d('SyncService close');\n    udp?.close();\n    server?.close(force: true);\n    super.onClose();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/app_scaffold.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass AppScaffold extends StatelessWidget {\n  final Widget child;\n  const AppScaffold({required this.child, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: Stack(\n        children: [\n          Container(\n            decoration: const BoxDecoration(\n              gradient: LinearGradient(\n                begin: Alignment.topLeft,\n                end: Alignment.bottomRight,\n                colors: [\n                  // //linear-gradient(135deg,#152331,#000000)\n                  // Color.fromARGB(255, 29, 50, 70),\n                  // Color.fromARGB(255, 14, 21, 29),\n                  // Color.fromARGB(255, 29, 50, 70),\n                  // linear-gradient(135deg,#141e30,#243b55)\n                  Color(0xff141e30),\n                  Color(0xff243b55),\n                  Color(0xff141e30),\n                ],\n              ),\n            ),\n          ),\n          Positioned.fill(child: child),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/button/highlight_button.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\n\nclass HighlightButton extends StatelessWidget {\n  final String text;\n  final IconData? iconData;\n  final Widget? icon;\n  final AppFocusNode focusNode;\n  final Function()? onTap;\n  final bool autofocus;\n  final bool selected;\n  const HighlightButton({\n    this.iconData,\n    required this.text,\n    this.icon,\n    this.onTap,\n    required this.focusNode,\n    this.autofocus = false,\n    this.selected = false,\n    super.key,\n  });\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => HighlightWidget(\n        focusNode: focusNode,\n        borderRadius: AppStyle.radius32,\n        color: Colors.white10,\n        onTap: onTap,\n        autofocus: autofocus,\n        selected: selected,\n        child: Container(\n          height: 64.w,\n          //width: 64.w,\n          padding: AppStyle.edgeInsetsH24,\n          decoration: BoxDecoration(\n            borderRadius: AppStyle.radius32,\n          ),\n          child: Row(\n            mainAxisSize: MainAxisSize.min,\n            crossAxisAlignment: CrossAxisAlignment.center,\n            children: [\n              buildIcon(),\n              Text(\n                text,\n                style: TextStyle(\n                  fontSize: 28.w,\n                  color: (focusNode.isFoucsed.value || selected)\n                      ? Colors.black\n                      : Colors.white,\n                ),\n              ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n\n  Widget buildIcon() {\n    if (icon != null || iconData != null) {\n      return Padding(\n        padding: AppStyle.edgeInsetsR12,\n        child: icon ??\n            Icon(\n              iconData,\n              size: 40.w,\n              color: (focusNode.isFoucsed.value || selected)\n                  ? Colors.black\n                  : Colors.white,\n            ),\n      );\n    }\n    return const SizedBox();\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/button/highlight_list_tile.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\n\nclass HighlightListTile extends StatelessWidget {\n  final String title;\n  final String? subtitle;\n  final Widget? leading;\n  final Widget? trailing;\n  final AppFocusNode focusNode;\n  final Function()? onTap;\n  final bool autofocus;\n\n  const HighlightListTile({\n    this.subtitle,\n    required this.title,\n    this.leading,\n    this.onTap,\n    required this.focusNode,\n    this.autofocus = false,\n    this.trailing,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => IconTheme(\n        data: IconThemeData(\n          color: focusNode.isFoucsed.value ? Colors.black : Colors.white,\n        ),\n        child: HighlightWidget(\n          onTap: onTap,\n          autofocus: autofocus,\n          focusNode: focusNode,\n          borderRadius: AppStyle.radius16,\n          child: Padding(\n            padding: AppStyle.edgeInsetsA24,\n            child: Row(\n              children: [\n                if (leading != null) leading!,\n                if (leading != null) AppStyle.hGap32,\n                Expanded(\n                  child: Column(\n                    crossAxisAlignment: CrossAxisAlignment.start,\n                    mainAxisAlignment: MainAxisAlignment.center,\n                    children: [\n                      Text(\n                        title,\n                        style: focusNode.isFoucsed.value\n                            ? AppStyle.textStyleBlack\n                            : AppStyle.textStyleWhite,\n                      ),\n                      if (subtitle != null)\n                        Text(\n                          subtitle!,\n                          style: focusNode.isFoucsed.value\n                              ? AppStyle.textStyleBlack.copyWith(fontSize: 24.w)\n                              : AppStyle.textStyleWhite\n                                  .copyWith(fontSize: 24.w),\n                        ),\n                    ],\n                  ),\n                ),\n                AppStyle.hGap12,\n                if (onTap != null &&\n                    focusNode.isFoucsed.value &&\n                    trailing == null)\n                  Icon(\n                    Icons.chevron_right,\n                    size: 40.w,\n                    color:\n                        focusNode.isFoucsed.value ? Colors.black : Colors.white,\n                  ),\n                if (trailing != null) trailing!,\n              ],\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/button/home_big_button.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\n\nclass HomeBigButton extends StatelessWidget {\n  final String text;\n  final IconData iconData;\n  final AppFocusNode focusNode;\n  final Function()? onTap;\n  final bool autofocus;\n  const HomeBigButton({\n    required this.iconData,\n    required this.text,\n    this.onTap,\n    required this.focusNode,\n    this.autofocus = false,\n    super.key,\n  });\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => HighlightWidget(\n        onTap: onTap,\n        autofocus: autofocus,\n        focusNode: focusNode,\n        borderRadius: AppStyle.radius16,\n        color: Colors.white10,\n        child: Container(\n          padding: AppStyle.edgeInsetsA32.copyWith(left: 48.w, right: 48.w),\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            crossAxisAlignment: CrossAxisAlignment.start,\n            children: [\n              Container(\n                padding: AppStyle.edgeInsetsA12,\n                decoration: const BoxDecoration(\n                  shape: BoxShape.circle,\n                ),\n                child: Icon(\n                  iconData,\n                  size: 64.w,\n                  color:\n                      focusNode.isFoucsed.value ? Colors.black : Colors.white,\n                ),\n              ),\n              AppStyle.vGap24,\n              Text(\n                text,\n                style: TextStyle(\n                  fontSize: 36.w,\n                  color:\n                      focusNode.isFoucsed.value ? Colors.black : Colors.white,\n                ),\n              ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/card/anchor_card.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/sites.dart';\nimport 'package:simple_live_tv_app/routes/app_navigation.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\nimport 'package:simple_live_tv_app/widgets/net_image.dart';\n\nclass AnchorCard extends StatelessWidget {\n  final String siteId;\n  final String face;\n  final String name;\n  final String roomId;\n  final int liveStatus;\n  final bool autofocus;\n  final Function()? onTap;\n  final AppFocusNode? focusNode;\n  const AnchorCard({\n    required this.face,\n    required this.siteId,\n    required this.name,\n    required this.liveStatus,\n    required this.roomId,\n    this.autofocus = false,\n    this.focusNode,\n    this.onTap,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    var site = Sites.allSites[siteId]!;\n    var focusNode = this.focusNode ?? AppFocusNode();\n    return Obx(\n      () => HighlightWidget(\n        onTap: onTap ??\n            () {\n              AppNavigator.toLiveRoomDetail(site: site, roomId: roomId);\n            },\n        focusNode: focusNode,\n        autofocus: autofocus,\n        borderRadius: AppStyle.radius16,\n        color: Colors.white10,\n        child: Stack(\n          children: [\n            Padding(\n              padding: AppStyle.edgeInsetsA20,\n              child: Row(\n                mainAxisSize: MainAxisSize.max,\n                children: [\n                  NetImage(\n                    face,\n                    width: 100.w,\n                    height: 100.w,\n                    borderRadius: 100.w,\n                    cacheWidth: 100,\n                  ),\n                  AppStyle.hGap16,\n                  Expanded(\n                    child: Column(\n                      crossAxisAlignment: CrossAxisAlignment.stretch,\n                      children: [\n                        Text(\n                          name,\n                          style: TextStyle(\n                            fontSize: 36.w,\n                            overflow: TextOverflow.ellipsis,\n                            color: focusNode.isFoucsed.value\n                                ? Colors.black\n                                : Colors.white,\n                          ),\n                        ),\n                        Text.rich(\n                          TextSpan(\n                            children: [\n                              WidgetSpan(\n                                child: Image.asset(\n                                  site.logo,\n                                  width: 32.w,\n                                ),\n                              ),\n                              TextSpan(\n                                text: \" ${site.name}\",\n                              ),\n                            ],\n                          ),\n                          style: TextStyle(\n                            fontSize: 24.w,\n                            color: focusNode.isFoucsed.value\n                                ? Colors.black\n                                : Colors.white,\n                          ),\n                        ),\n                      ],\n                    ),\n                  ),\n                ],\n              ),\n            ),\n            if (liveStatus == 2)\n              Positioned(\n                right: 0,\n                top: 0,\n                child: Container(\n                  padding:\n                      AppStyle.edgeInsetsH16.copyWith(top: 4.w, bottom: 4.w),\n                  decoration: BoxDecoration(\n                    color: Colors.green,\n                    borderRadius: BorderRadius.only(\n                      topRight: Radius.circular(12.w),\n                      bottomLeft: Radius.circular(12.w),\n                    ),\n                  ),\n                  child: Text(\n                    \"直播中\",\n                    style: TextStyle(\n                      fontSize: 24.w,\n                      color: Colors.white,\n                    ),\n                  ),\n                ),\n              ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/card/live_room_card.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/app/utils.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\nimport 'package:simple_live_tv_app/widgets/net_image.dart';\nimport 'package:marquee/marquee.dart';\n\nclass LiveRoomCard extends StatelessWidget {\n  final String cover;\n  final String title;\n  final String anchor;\n  final String roomId;\n  final int online;\n  final bool autofocus;\n  final AppFocusNode focusNode;\n  final Function()? onTap;\n  const LiveRoomCard({\n    required this.cover,\n    required this.title,\n    required this.anchor,\n    required this.roomId,\n    required this.focusNode,\n    required this.online,\n    this.autofocus = false,\n    this.onTap,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return HighlightWidget(\n      focusNode: focusNode,\n      color: Colors.white10,\n      onTap: onTap,\n      borderRadius: AppStyle.radius16,\n      child: Obx(\n        () => Column(\n          crossAxisAlignment: CrossAxisAlignment.start,\n          children: [\n            ClipRRect(\n              borderRadius: BorderRadius.only(\n                topLeft: Radius.circular(16.w),\n                topRight: Radius.circular(16.w),\n              ),\n              child: Stack(\n                children: [\n                  AspectRatio(\n                    aspectRatio: 16 / 9,\n                    child: NetImage(\n                      cover,\n                      cacheWidth: 400,\n                    ),\n                  ),\n                  Positioned(\n                    right: 8.w,\n                    top: 8.w,\n                    child: Container(\n                      padding:\n                          AppStyle.edgeInsetsH8.copyWith(top: 4.w, bottom: 4.w),\n                      decoration: BoxDecoration(\n                        color: focusNode.isFoucsed.value\n                            ? Colors.white\n                            : Colors.black54,\n                        borderRadius: AppStyle.radius8,\n                      ),\n                      child: Text.rich(\n                        TextSpan(\n                          text: \"\",\n                          children: [\n                            WidgetSpan(\n                              alignment: PlaceholderAlignment.middle,\n                              child: Padding(\n                                padding: AppStyle.edgeInsetsR8,\n                                child: Icon(\n                                  Icons.whatshot,\n                                  color: focusNode.isFoucsed.value\n                                      ? Colors.orange\n                                      : Colors.white,\n                                  size: 20.w,\n                                ),\n                              ),\n                            ),\n                            TextSpan(\n                              text: Utils.onlineToString(online),\n                            ),\n                          ],\n                        ),\n                        style: TextStyle(\n                          fontSize: 20.w,\n                          color: focusNode.isFoucsed.value\n                              ? Colors.black\n                              : Colors.white,\n                        ),\n                      ),\n                    ),\n                  ),\n                ],\n              ),\n              // child: Container(\n              //   height: 200.w,\n              // ),\n            ),\n            AppStyle.vGap8,\n            Padding(\n              padding: AppStyle.edgeInsetsH20,\n              child: SizedBox(\n                height: 56.w,\n                child: focusNode.isFoucsed.value\n                    ? Marquee(\n                        text: title,\n                        style: AppStyle.textStyleBlack,\n                        startAfter: const Duration(seconds: 1),\n                        velocity: 20,\n                        blankSpace: 200.w,\n                        //decelerationDuration: const Duration(seconds: 2),\n                        scrollAxis: Axis.horizontal,\n                      )\n                    : Container(\n                        alignment: Alignment.centerLeft,\n                        child: Text(\n                          title,\n                          style: AppStyle.textStyleWhite,\n                          maxLines: 1,\n                          overflow: TextOverflow.ellipsis,\n                        ),\n                      ),\n              ),\n            ),\n            Row(\n              crossAxisAlignment: CrossAxisAlignment.end,\n              children: [\n                AppStyle.hGap20,\n                Icon(\n                  Icons.account_circle,\n                  color: focusNode.isFoucsed.value\n                      ? Colors.black54\n                      : Colors.white54,\n                  size: 32.w,\n                ),\n                AppStyle.hGap12,\n                Expanded(\n                  child: Text(\n                    anchor,\n                    style: focusNode.isFoucsed.value\n                        ? AppStyle.subTextStyleBlack\n                        : AppStyle.subTextStyleWhite,\n                    maxLines: 1,\n                    overflow: TextOverflow.ellipsis,\n                  ),\n                ),\n              ],\n            ),\n            AppStyle.vGap12,\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/highlight_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\n\ntypedef FocusOnKeyDownCallback = KeyEventResult Function();\n\n/// 高亮组件\nclass HighlightWidget extends StatelessWidget {\n  final AppFocusNode focusNode;\n  final Widget child;\n  final FocusOnKeyDownCallback? onUpKey;\n  final FocusOnKeyDownCallback? onDownKey;\n  final FocusOnKeyDownCallback? onLeftKey;\n  final FocusOnKeyDownCallback? onRightKey;\n  final Function(bool)? onFocusChange;\n  final Function()? onTap;\n  final Color foucsedColor;\n  final Color color;\n  final bool autofocus;\n  final BorderRadius? borderRadius;\n  final double order;\n  final bool selected;\n  const HighlightWidget({\n    required this.focusNode,\n    required this.child,\n    this.onUpKey,\n    this.onDownKey,\n    this.onLeftKey,\n    this.onRightKey,\n    this.onFocusChange,\n    this.onTap,\n    this.autofocus = false,\n    this.selected = false,\n    this.borderRadius,\n    this.order = 0.0,\n    this.color = Colors.transparent,\n    this.foucsedColor = Colors.white,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return FocusTraversalOrder(\n      order: NumericFocusOrder(order),\n      child: Focus(\n        focusNode: focusNode,\n        autofocus: autofocus,\n        onFocusChange: onFocusChange,\n        onKeyEvent: (node, e) {\n          if (e is KeyDownEvent) {\n            if (e.logicalKey == LogicalKeyboardKey.arrowRight) {\n              return onRightKey?.call() ?? KeyEventResult.ignored;\n            }\n            if (e.logicalKey == LogicalKeyboardKey.arrowLeft) {\n              return onLeftKey?.call() ?? KeyEventResult.ignored;\n            }\n            if (e.logicalKey == LogicalKeyboardKey.arrowUp) {\n              return onUpKey?.call() ?? KeyEventResult.ignored;\n            }\n            if (e.logicalKey == LogicalKeyboardKey.arrowDown) {\n              return onDownKey?.call() ?? KeyEventResult.ignored;\n            }\n            if (e.logicalKey == LogicalKeyboardKey.enter ||\n                e.logicalKey == LogicalKeyboardKey.select ||\n                e.logicalKey == LogicalKeyboardKey.space) {\n              return onTap?.call() ?? KeyEventResult.ignored;\n            }\n          }\n\n          return KeyEventResult.ignored;\n        },\n        child: GestureDetector(\n          onTap: onTap,\n          child: Obx(\n            () => AnimatedScale(\n              scale: focusNode.isFoucsed.value ? 1.1 : 1,\n              duration: const Duration(milliseconds: 200),\n              child: GestureDetector(\n                onTap: onTap,\n                child: Container(\n                  decoration: BoxDecoration(\n                    borderRadius: borderRadius,\n                    boxShadow: focusNode.isFoucsed.value\n                        ? AppStyle.highlightShadow\n                        : null,\n                    color: (focusNode.isFoucsed.value || selected)\n                        ? foucsedColor\n                        : color,\n                  ),\n                  child: child,\n                ),\n              ),\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/keep_alive_wrapper.dart",
    "content": "import 'package:flutter/material.dart';\n\nclass KeepAliveWrapper extends StatefulWidget {\n  final Widget child;\n\n  const KeepAliveWrapper({super.key, required this.child});\n\n  @override\n  State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();\n}\n\nclass _KeepAliveWrapperState extends State<KeepAliveWrapper>\n    with AutomaticKeepAliveClientMixin {\n  @override\n  Widget build(BuildContext context) {\n    super.build(context);\n    return widget.child;\n  }\n\n  @override\n  bool get wantKeepAlive => true;\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/net_image.dart",
    "content": "import 'package:extended_image/extended_image.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\n\nclass NetImage extends StatelessWidget {\n  final String picUrl;\n  final double? width;\n  final double? height;\n  final BoxFit? fit;\n  final double borderRadius;\n  final int? cacheWidth;\n  const NetImage(this.picUrl,\n      {this.width,\n      this.height,\n      this.fit = BoxFit.cover,\n      this.borderRadius = 0,\n      this.cacheWidth,\n      super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    var pic = picUrl;\n    if (pic.startsWith(\"//\")) {\n      pic = 'https:$pic';\n    }\n    return ClipRRect(\n      borderRadius: BorderRadius.circular(borderRadius),\n      child: ExtendedImage.network(\n        pic,\n        fit: fit,\n        height: height,\n        width: width,\n        cacheWidth: cacheWidth,\n        shape: BoxShape.rectangle,\n        borderRadius: BorderRadius.circular(borderRadius),\n        loadStateChanged: (e) {\n          if (e.extendedImageLoadState == LoadState.loading) {\n            return const SizedBox();\n          }\n          if (e.extendedImageLoadState == LoadState.failed) {\n            return Icon(\n              Icons.broken_image,\n              color: Colors.grey,\n              size: 24.w,\n            );\n          }\n          return null;\n        },\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/page_grid_view.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:simple_live_tv_app/app/controller/base_controller.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_error_widget.dart';\nimport 'package:simple_live_tv_app/widgets/status/app_loadding_widget.dart';\nimport 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';\nimport 'package:get/get.dart';\n\nclass PageGridView extends StatelessWidget {\n  final BasePageController pageController;\n  final IndexedWidgetBuilder itemBuilder;\n  final EdgeInsets? padding;\n  final bool firstRefresh;\n  final Function()? onLoginSuccess;\n  final bool showPageLoadding;\n  final double crossAxisSpacing, mainAxisSpacing;\n  final int crossAxisCount;\n  const PageGridView({\n    required this.itemBuilder,\n    required this.pageController,\n    this.padding,\n    this.firstRefresh = false,\n    this.showPageLoadding = false,\n    this.onLoginSuccess,\n    this.crossAxisSpacing = 0.0,\n    this.mainAxisSpacing = 0.0,\n    required this.crossAxisCount,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Obx(\n      () => Stack(\n        children: [\n          MasonryGridView.count(\n            padding: padding,\n            controller: pageController.scrollController,\n            itemCount: pageController.list.length,\n            itemBuilder: itemBuilder,\n            crossAxisCount: crossAxisCount,\n            crossAxisSpacing: crossAxisSpacing,\n            mainAxisSpacing: mainAxisSpacing,\n          ),\n          Offstage(\n            offstage: !pageController.pageEmpty.value,\n            child: AppEmptyWidget(\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n          Offstage(\n            offstage: !(showPageLoadding && pageController.pageLoadding.value),\n            child: const AppLoaddingWidget(),\n          ),\n          Offstage(\n            offstage: !pageController.pageError.value,\n            child: AppErrorWidget(\n              errorMsg: pageController.errorMsg.value,\n              onRefresh: () => pageController.refreshData(),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/rectangular_indicator.dart",
    "content": "import 'package:flutter/material.dart';\n\n/// 来自 https://github.com/adar2378/tab_indicator_styler\n\nclass RectangularIndicator extends Decoration {\n  /// topRight radius of the indicator, default to 5.\n  final double topRightRadius;\n\n  /// topLeft radius of the indicator, default to 5.\n  final double topLeftRadius;\n\n  /// bottomRight radius of the indicator, default to 0.\n  final double bottomRightRadius;\n\n  /// bottomLeft radius of the indicator, default to 0\n  final double bottomLeftRadius;\n\n  /// Color of the indicator, default set to [Colors.black]\n  final Color color;\n\n  /// Horizontal padding of the indicator, default set to 0\n  final double horizontalPadding;\n\n  /// Vertical padding of the indicator, default set to 0\n  final double verticalPadding;\n\n  /// [PagingStyle] determines if the indicator should be fill or stroke, default to fill\n  final PaintingStyle paintingStyle;\n\n  /// StrokeWidth, used for [PaintingStyle.stroke], default set to 0\n  final double strokeWidth;\n\n  const RectangularIndicator({\n    this.topRightRadius = 5,\n    this.topLeftRadius = 5,\n    this.bottomRightRadius = 0,\n    this.bottomLeftRadius = 0,\n    this.color = Colors.black,\n    this.horizontalPadding = 0,\n    this.verticalPadding = 0,\n    this.paintingStyle = PaintingStyle.fill,\n    this.strokeWidth = 2,\n  });\n  @override\n  MyCustomPainter createBoxPainter([VoidCallback? onChanged]) {\n    return MyCustomPainter(\n      this,\n      onChanged,\n      bottomLeftRadius: bottomLeftRadius,\n      bottomRightRadius: bottomRightRadius,\n      color: color,\n      horizontalPadding: horizontalPadding,\n      topLeftRadius: topLeftRadius,\n      topRightRadius: topRightRadius,\n      verticalPadding: verticalPadding,\n      paintingStyle: paintingStyle,\n      strokeWidth: strokeWidth,\n    );\n  }\n}\n\nclass MyCustomPainter extends BoxPainter {\n  final RectangularIndicator decoration;\n  final double topRightRadius;\n  final double topLeftRadius;\n  final double bottomRightRadius;\n  final double bottomLeftRadius;\n  final Color color;\n  final double horizontalPadding;\n  final double verticalPadding;\n  final PaintingStyle paintingStyle;\n  final double strokeWidth;\n\n  MyCustomPainter(\n    this.decoration,\n    VoidCallback? onChanged, {\n    required this.topRightRadius,\n    required this.topLeftRadius,\n    required this.bottomRightRadius,\n    required this.bottomLeftRadius,\n    required this.color,\n    required this.horizontalPadding,\n    required this.verticalPadding,\n    required this.paintingStyle,\n    required this.strokeWidth,\n  }) : super(onChanged);\n\n  @override\n  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {\n    assert(horizontalPadding >= 0);\n    assert(horizontalPadding < configuration.size!.width / 2,\n        \"Padding must be less than half of the size of the tab\");\n    assert(verticalPadding < configuration.size!.height / 2 &&\n        verticalPadding >= 0);\n    assert(strokeWidth >= 0 &&\n        strokeWidth < configuration.size!.width / 2 &&\n        strokeWidth < configuration.size!.height / 2);\n\n    //offset is the position from where the decoration should be drawn.\n    //configuration.size tells us about the height and width of the tab.\n    Size mysize = Size(configuration.size!.width - (horizontalPadding * 2),\n        configuration.size!.height - (2 * verticalPadding));\n\n    Offset myoffset =\n        Offset(offset.dx + (horizontalPadding), offset.dy + verticalPadding);\n    final Rect rect = myoffset & mysize;\n    final Paint paint = Paint();\n    paint.color = color;\n    paint.style = paintingStyle;\n    paint.strokeWidth = 3;\n    canvas.drawRRect(\n        RRect.fromRectAndCorners(\n          rect,\n          bottomRight: Radius.circular(bottomRightRadius),\n          bottomLeft: Radius.circular(bottomLeftRadius),\n          topLeft: Radius.circular(topLeftRadius),\n          topRight: Radius.circular(topRightRadius),\n        ),\n        paint);\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/settings_item_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:simple_live_tv_app/widgets/highlight_widget.dart';\n\nclass SettingsItemWidget extends StatelessWidget {\n  final AppFocusNode foucsNode;\n  final Map<dynamic, String> items;\n  final dynamic value;\n  final String title;\n  final bool autofocus;\n  final Function(dynamic) onChanged;\n  const SettingsItemWidget({\n    required this.foucsNode,\n    required this.items,\n    required this.value,\n    required this.title,\n    required this.onChanged,\n    this.autofocus = false,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return HighlightWidget(\n      focusNode: foucsNode,\n      autofocus: autofocus,\n      borderRadius: AppStyle.radius16,\n      onLeftKey: () {\n        if (items.isEmpty) return KeyEventResult.handled;\n        if (items.keys.first == value) {\n          onChanged(items.keys.last);\n        } else {\n          onChanged(\n              items.keys.elementAt(items.keys.toList().indexOf(value) - 1));\n        }\n        return KeyEventResult.handled;\n      },\n      onRightKey: () {\n        if (items.isEmpty) return KeyEventResult.handled;\n        if (items.keys.last == value) {\n          onChanged(items.keys.first);\n        } else {\n          onChanged(\n              items.keys.elementAt(items.keys.toList().indexOf(value) + 1));\n        }\n        return KeyEventResult.handled;\n      },\n      onTap: () {\n        showSettingsDialog();\n      },\n      child: Obx(\n        () => Padding(\n          padding: AppStyle.edgeInsetsA24,\n          child: Row(\n            children: [\n              Text(\n                title,\n                style: foucsNode.isFoucsed.value\n                    ? AppStyle.textStyleBlack\n                    : AppStyle.textStyleWhite,\n              ),\n              const Spacer(),\n              if (foucsNode.isFoucsed.value && items.isNotEmpty)\n                Icon(\n                  Icons.chevron_left,\n                  size: 40.w,\n                  color:\n                      foucsNode.isFoucsed.value ? Colors.black : Colors.white,\n                ),\n              AppStyle.hGap12,\n              ConstrainedBox(\n                constraints: BoxConstraints(minWidth: 120.w),\n                child: Text(\n                  items[value] ?? '',\n                  style: foucsNode.isFoucsed.value\n                      ? AppStyle.textStyleBlack\n                      : AppStyle.textStyleWhite,\n                  textAlign: foucsNode.isFoucsed.value\n                      ? TextAlign.center\n                      : TextAlign.right,\n                ),\n              ),\n              AppStyle.hGap12,\n              if (foucsNode.isFoucsed.value && items.isNotEmpty)\n                Icon(\n                  Icons.chevron_right,\n                  size: 40.w,\n                  color:\n                      foucsNode.isFoucsed.value ? Colors.black : Colors.white,\n                ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n\n  void showSettingsDialog() {\n    Get.dialog(\n      AlertDialog(\n        backgroundColor: Get.theme.cardColor,\n        surfaceTintColor: Colors.transparent,\n        title: Text(title, style: AppStyle.titleStyleWhite),\n        scrollable: true,\n        content: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: items.keys.map((e) {\n            return ListTile(\n              title: Text(items[e] ?? '', style: AppStyle.textStyleWhite),\n              contentPadding: AppStyle.edgeInsetsH20,\n              autofocus: e == value,\n              shape: RoundedRectangleBorder(\n                borderRadius: AppStyle.radius16,\n              ),\n              focusColor: Colors.white54,\n              onTap: () {\n                onChanged(e);\n                Get.back();\n              },\n            );\n          }).toList(),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/status/app_empty_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:simple_live_tv_app/app/app_focus_node.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:lottie/lottie.dart';\nimport 'package:simple_live_tv_app/widgets/button/highlight_button.dart';\n\nclass AppEmptyWidget extends StatelessWidget {\n  final Function()? onRefresh;\n  final String? text;\n  const AppEmptyWidget({\n    this.onRefresh,\n    this.text,\n    super.key,\n  });\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: GestureDetector(\n        onTap: () {\n          onRefresh?.call();\n        },\n        child: Padding(\n          padding: AppStyle.edgeInsetsA48,\n          child: Column(\n            mainAxisSize: MainAxisSize.min,\n            children: [\n              LottieBuilder.asset(\n                'assets/lotties/empty.json',\n                width: 160.w,\n                height: 160.w,\n                repeat: false,\n              ),\n              AppStyle.vGap24,\n              Text(\n                text ?? \"这里什么都没有\",\n                textAlign: TextAlign.center,\n                style: AppStyle.textStyleWhite,\n              ),\n              AppStyle.vGap24,\n              if (onRefresh != null)\n                HighlightButton(\n                  text: \"刷新\",\n                  iconData: Icons.refresh,\n                  onTap: onRefresh,\n                  focusNode: AppFocusNode(),\n                ),\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/status/app_error_widget.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_screenutil/flutter_screenutil.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\nimport 'package:lottie/lottie.dart';\n\nclass AppErrorWidget extends StatelessWidget {\n  final Function()? onRefresh;\n  final String errorMsg;\n  const AppErrorWidget({this.errorMsg = \"\", this.onRefresh, super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: Padding(\n        padding: AppStyle.edgeInsetsA12,\n        child: Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            LottieBuilder.asset(\n              'assets/lotties/error.json',\n              width: 200.w,\n              repeat: false,\n            ),\n            AppStyle.vGap24,\n            Text(\n              errorMsg.isEmpty ? \"出错了，请稍后重试\" : errorMsg,\n              textAlign: TextAlign.center,\n              style: AppStyle.textStyleWhite,\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/lib/widgets/status/app_loadding_widget.dart",
    "content": "import 'package:flutter/cupertino.dart';\nimport 'package:flutter/material.dart';\nimport 'package:get/get.dart';\nimport 'package:simple_live_tv_app/app/app_style.dart';\n\nclass AppLoaddingWidget extends StatelessWidget {\n  const AppLoaddingWidget({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: Container(\n        padding: AppStyle.edgeInsetsA12,\n        decoration: BoxDecoration(\n          shape: BoxShape.circle,\n          color: Theme.of(context).cardColor,\n          boxShadow: Get.isDarkMode\n              ? []\n              : [\n                  BoxShadow(\n                    blurRadius: 4,\n                    color: Colors.grey.withAlpha(50),\n                  )\n                ],\n        ),\n        child: const CupertinoActivityIndicator(\n          radius: 10,\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/pubspec.yaml",
    "content": "name: simple_live_tv_app\ndescription: A new Flutter project.\npublish_to: \"none\"\nversion: 1.5.0+10500\n\nenvironment:\n  sdk: \">=3.1.2 <4.0.0\"\n  flutter: 3.35.7\n\ndependencies:\n  flutter:\n    sdk: flutter\n  simple_live_core:\n    path: ../simple_live_core\n  cupertino_icons: ^1.0.2\n  remixicon: ^1.0.0 #Remix图标\n\n  # 框架、工具\n  get: ^4.7.2 #状态管理、路由管理、国际化\n  dio: ^5.9.0 #网络请求\n  hive: 2.2.3 #持久化存储\n  hive_flutter: 1.1.0 #持久化存储\n  logger: ^2.6.1 #日志\n  intl: ^0.20.2 #国际化\n  flutter_screenutil: ^5.9.3 #UI适配\n  uuid: ^4.5.1 #UUID\n  signalr_netcore: ^1.4.4 #SignalR\n  crypto: ^3.0.6\n\n  #Widget\n  flutter_staggered_grid_view: ^0.7.0 #瀑布流/GridView\n  flutter_easyrefresh: 2.2.2 #下拉刷新、上拉加载\n  extended_image: ^10.0.1 #拓展Image,支持缓存\n  flutter_smart_dialog: ^4.9.8+9 #各种弹窗 Toast/Dialog/Popup\n  marquee: ^2.3.0 #跑马灯\n  lottie: ^3.3.2 #Lottie动画\n  qr_flutter: ^4.1.0 #二维码\n  sticky_headers: ^0.3.0+2 #吸顶\n  canvas_danmaku: ^0.2.7 #弹幕\n\n  #系统交互\n  package_info_plus: ^9.0.0 #包信息\n  url_launcher: ^6.3.2 #打开链接\n  network_info_plus: ^7.0.0\n  shelf: ^1.4.2\n  shelf_router: ^1.1.4\n  udp: ^5.0.3 #UDP\n  device_info_plus: ^12.1.0 #设备信息\n  wakelock_plus: ^1.4.0 #屏幕常亮，media_kit中自带，但似乎不生效\n\n  # 视频播放\n  media_kit: ^1.2.1\n  media_kit_video: ^1.3.1\n  media_kit_libs_video: ^1.0.7\n\ndependency_overrides:\n  fading_edge_scrollview: ^4.1.1\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\n  flutter_lints: ^5.0.0\n\nflutter:\n  uses-material-design: true\n  assets:\n    - assets/statement.txt\n    - assets/images/\n    - assets/icons/\n    - assets/lotties/\n"
  },
  {
    "path": "simple_live_tv_app/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility in the flutter_test package. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'package:simple_live_tv_app/main.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    await tester.pumpWidget(const MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/.gitignore",
    "content": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio build-related files.\nx64/\nx86/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n"
  },
  {
    "path": "simple_live_tv_app/windows/CMakeLists.txt",
    "content": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.14)\nproject(simple_live_tv_app LANGUAGES CXX)\n\n# The name of the executable created for the application. Change this to change\n# the on-disk name of your application.\nset(BINARY_NAME \"simple_live_tv_app\")\n\n# Explicitly opt in to modern CMake behaviors to avoid warnings with recent\n# versions of CMake.\ncmake_policy(VERSION 3.14...3.25)\n\n# Define build configuration option.\nget_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\nif(IS_MULTICONFIG)\n  set(CMAKE_CONFIGURATION_TYPES \"Debug;Profile;Release\"\n    CACHE STRING \"\" FORCE)\nelse()\n  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n    set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n      STRING \"Flutter build mode\" FORCE)\n    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n      \"Debug\" \"Profile\" \"Release\")\n  endif()\nendif()\n# Define settings for the Profile build mode.\nset(CMAKE_EXE_LINKER_FLAGS_PROFILE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_SHARED_LINKER_FLAGS_PROFILE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_C_FLAGS_PROFILE \"${CMAKE_C_FLAGS_RELEASE}\")\nset(CMAKE_CXX_FLAGS_PROFILE \"${CMAKE_CXX_FLAGS_RELEASE}\")\n\n# Use Unicode for all projects.\nadd_definitions(-DUNICODE -D_UNICODE)\n\n# Compilation settings that should be applied to most targets.\n#\n# Be cautious about adding new options here, as plugins use this function by\n# default. In most cases, you should add new options to specific targets instead\n# of modifying this function.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_17)\n  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd\"4100\")\n  target_compile_options(${TARGET} PRIVATE /EHsc)\n  target_compile_definitions(${TARGET} PRIVATE \"_HAS_EXCEPTIONS=0\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<CONFIG:Debug>:_DEBUG>\")\nendfunction()\n\n# Flutter library and tool build rules.\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# Application build; see runner/CMakeLists.txt.\nadd_subdirectory(\"runner\")\n\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# Support files are copied into place next to the executable, so that it can\n# run in place. This is done instead of making a separate bundle (as on Linux)\n# so that building and running from within Visual Studio will work.\nset(BUILD_BUNDLE_DIR \"$<TARGET_FILE_DIR:${BINARY_NAME}>\")\n# Make the \"install\" step default, as it's required to run.\nset(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\ninstall(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  CONFIGURATIONS Profile;Release\n  COMPONENT Runtime)\n"
  },
  {
    "path": "simple_live_tv_app/windows/flutter/CMakeLists.txt",
    "content": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.14)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\nset(WRAPPER_ROOT \"${EPHEMERAL_DIR}/cpp_client_wrapper\")\n\n# Set fallback configurations for older versions of the flutter tool.\nif (NOT DEFINED FLUTTER_TARGET_PLATFORM)\n  set(FLUTTER_TARGET_PLATFORM \"windows-x64\")\nendif()\n\n# === Flutter Library ===\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/flutter_windows.dll\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/windows/app.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"flutter_export.h\"\n  \"flutter_windows.h\"\n  \"flutter_messenger.h\"\n  \"flutter_plugin_registrar.h\"\n  \"flutter_texture_registrar.h\"\n)\nlist(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND \"${EPHEMERAL_DIR}/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}.lib\")\nadd_dependencies(flutter flutter_assemble)\n\n# === Wrapper ===\nlist(APPEND CPP_WRAPPER_SOURCES_CORE\n  \"core_implementations.cc\"\n  \"standard_codec.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_PLUGIN\n  \"plugin_registrar.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_APP\n  \"flutter_engine.cc\"\n  \"flutter_view_controller.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND \"${WRAPPER_ROOT}/\")\n\n# Wrapper sources needed for a plugin.\nadd_library(flutter_wrapper_plugin STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n)\napply_standard_settings(flutter_wrapper_plugin)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  POSITION_INDEPENDENT_CODE ON)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  CXX_VISIBILITY_PRESET hidden)\ntarget_link_libraries(flutter_wrapper_plugin PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_plugin PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_plugin flutter_assemble)\n\n# Wrapper sources needed for the runner.\nadd_library(flutter_wrapper_app STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\napply_standard_settings(flutter_wrapper_app)\ntarget_link_libraries(flutter_wrapper_app PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_app PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_app flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nset(PHONY_OUTPUT \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\")\nset_source_files_properties(\"${PHONY_OUTPUT}\" PROPERTIES SYMBOLIC TRUE)\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}\n    ${CPP_WRAPPER_SOURCES_APP}\n    ${PHONY_OUTPUT}\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat\"\n      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\n"
  },
  {
    "path": "simple_live_tv_app/windows/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n#include <flutter_qjs/flutter_qjs_plugin.h>\n#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>\n#include <media_kit_video/media_kit_video_plugin_c_api.h>\n#include <url_launcher_windows/url_launcher_windows.h>\n#include <volume_controller/volume_controller_plugin_c_api.h>\n\nvoid RegisterPlugins(flutter::PluginRegistry* registry) {\n  FlutterQjsPluginRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"FlutterQjsPlugin\"));\n  MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"MediaKitLibsWindowsVideoPluginCApi\"));\n  MediaKitVideoPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"MediaKitVideoPluginCApi\"));\n  UrlLauncherWindowsRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"UrlLauncherWindows\"));\n  VolumeControllerPluginCApiRegisterWithRegistrar(\n      registry->GetRegistrarForPlugin(\"VolumeControllerPluginCApi\"));\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter/plugin_registry.h>\n\n// Registers Flutter plugins.\nvoid RegisterPlugins(flutter::PluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "simple_live_tv_app/windows/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n  flutter_qjs\n  media_kit_libs_windows_video\n  media_kit_video\n  url_launcher_windows\n  volume_controller\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.14)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name, change BINARY_NAME in the\n# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer\n# work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME} WIN32\n  \"flutter_window.cpp\"\n  \"main.cpp\"\n  \"utils.cpp\"\n  \"win32_window.cpp\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n  \"Runner.rc\"\n  \"runner.exe.manifest\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add preprocessor definitions for the build version.\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION=\\\"${FLUTTER_VERSION}\\\"\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}\")\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}\")\n\n# Disable Windows macros that collide with C++ standard library functions.\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"NOMINMAX\")\n\n# Add dependency libraries and include directories. Add any application-specific\n# dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)\ntarget_link_libraries(${BINARY_NAME} PRIVATE \"dwmapi.lib\")\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\n\n# Run the Flutter tool portions of the build. This must not be removed.\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/Runner.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_APP_ICON            ICON                    \"resources\\\\app_icon.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\n#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)\n#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD\n#else\n#define VERSION_AS_NUMBER 1,0,0,0\n#endif\n\n#if defined(FLUTTER_VERSION)\n#define VERSION_AS_STRING FLUTTER_VERSION\n#else\n#define VERSION_AS_STRING \"1.0.0\"\n#endif\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION VERSION_AS_NUMBER\n PRODUCTVERSION VERSION_AS_NUMBER\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS__WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904e4\"\n        BEGIN\n            VALUE \"CompanyName\", \"com.example\" \"\\0\"\n            VALUE \"FileDescription\", \"simple_live_tv_app\" \"\\0\"\n            VALUE \"FileVersion\", VERSION_AS_STRING \"\\0\"\n            VALUE \"InternalName\", \"simple_live_tv_app\" \"\\0\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2023 com.example. All rights reserved.\" \"\\0\"\n            VALUE \"OriginalFilename\", \"simple_live_tv_app.exe\" \"\\0\"\n            VALUE \"ProductName\", \"simple_live_tv_app\" \"\\0\"\n            VALUE \"ProductVersion\", VERSION_AS_STRING \"\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/flutter_window.cpp",
    "content": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::FlutterWindow(const flutter::DartProject& project)\n    : project_(project) {}\n\nFlutterWindow::~FlutterWindow() {}\n\nbool FlutterWindow::OnCreate() {\n  if (!Win32Window::OnCreate()) {\n    return false;\n  }\n\n  RECT frame = GetClientArea();\n\n  // The size here must match the window dimensions to avoid unnecessary surface\n  // creation / destruction in the startup path.\n  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(\n      frame.right - frame.left, frame.bottom - frame.top, project_);\n  // Ensure that basic setup of the controller was successful.\n  if (!flutter_controller_->engine() || !flutter_controller_->view()) {\n    return false;\n  }\n  RegisterPlugins(flutter_controller_->engine());\n  SetChildContent(flutter_controller_->view()->GetNativeWindow());\n\n  flutter_controller_->engine()->SetNextFrameCallback([&]() {\n    this->Show();\n  });\n\n  // Flutter can complete the first frame before the \"show window\" callback is\n  // registered. The following call ensures a frame is pending to ensure the\n  // window is shown. It is a no-op if the first frame hasn't completed yet.\n  flutter_controller_->ForceRedraw();\n\n  return true;\n}\n\nvoid FlutterWindow::OnDestroy() {\n  if (flutter_controller_) {\n    flutter_controller_ = nullptr;\n  }\n\n  Win32Window::OnDestroy();\n}\n\nLRESULT\nFlutterWindow::MessageHandler(HWND hwnd, UINT const message,\n                              WPARAM const wparam,\n                              LPARAM const lparam) noexcept {\n  // Give Flutter, including plugins, an opportunity to handle window messages.\n  if (flutter_controller_) {\n    std::optional<LRESULT> result =\n        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,\n                                                      lparam);\n    if (result) {\n      return *result;\n    }\n  }\n\n  switch (message) {\n    case WM_FONTCHANGE:\n      flutter_controller_->engine()->ReloadSystemFonts();\n      break;\n  }\n\n  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/flutter_window.h",
    "content": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n\n#include <memory>\n\n#include \"win32_window.h\"\n\n// A window that does nothing but host a Flutter view.\nclass FlutterWindow : public Win32Window {\n public:\n  // Creates a new FlutterWindow hosting a Flutter view running |project|.\n  explicit FlutterWindow(const flutter::DartProject& project);\n  virtual ~FlutterWindow();\n\n protected:\n  // Win32Window:\n  bool OnCreate() override;\n  void OnDestroy() override;\n  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,\n                         LPARAM const lparam) noexcept override;\n\n private:\n  // The project to run.\n  flutter::DartProject project_;\n\n  // The Flutter instance hosted by this window.\n  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;\n};\n\n#endif  // RUNNER_FLUTTER_WINDOW_H_\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/main.cpp",
    "content": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_window.h\"\n#include \"utils.h\"\n\nint APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,\n                      _In_ wchar_t *command_line, _In_ int show_command) {\n  // Attach to console when present (e.g., 'flutter run') or create a\n  // new console when running with a debugger.\n  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {\n    CreateAndAttachConsole();\n  }\n\n  // Initialize COM, so that it is available for use in the library and/or\n  // plugins.\n  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);\n\n  flutter::DartProject project(L\"data\");\n\n  std::vector<std::string> command_line_arguments =\n      GetCommandLineArguments();\n\n  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));\n\n  FlutterWindow window(project);\n  Win32Window::Point origin(10, 10);\n  Win32Window::Size size(1280, 720);\n  if (!window.Create(L\"simple_live_tv_app\", origin, size)) {\n    return EXIT_FAILURE;\n  }\n  window.SetQuitOnClose(true);\n\n  ::MSG msg;\n  while (::GetMessage(&msg, nullptr, 0, 0)) {\n    ::TranslateMessage(&msg);\n    ::DispatchMessage(&msg);\n  }\n\n  ::CoUninitialize();\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Runner.rc\n//\n#define IDI_APP_ICON                    101\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/runner.exe.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2</dpiAwareness>\n    </windowsSettings>\n  </application>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <!-- Windows 10 and Windows 11 -->\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n      <!-- Windows 8.1 -->\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <!-- Windows 8 -->\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <!-- Windows 7 -->\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n    </application>\n  </compatibility>\n</assembly>\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/utils.cpp",
    "content": "#include \"utils.h\"\n\n#include <flutter_windows.h>\n#include <io.h>\n#include <stdio.h>\n#include <windows.h>\n\n#include <iostream>\n\nvoid CreateAndAttachConsole() {\n  if (::AllocConsole()) {\n    FILE *unused;\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stdout)) {\n      _dup2(_fileno(stdout), 1);\n    }\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stderr)) {\n      _dup2(_fileno(stdout), 2);\n    }\n    std::ios::sync_with_stdio();\n    FlutterDesktopResyncOutputStreams();\n  }\n}\n\nstd::vector<std::string> GetCommandLineArguments() {\n  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.\n  int argc;\n  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);\n  if (argv == nullptr) {\n    return std::vector<std::string>();\n  }\n\n  std::vector<std::string> command_line_arguments;\n\n  // Skip the first argument as it's the binary name.\n  for (int i = 1; i < argc; i++) {\n    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));\n  }\n\n  ::LocalFree(argv);\n\n  return command_line_arguments;\n}\n\nstd::string Utf8FromUtf16(const wchar_t* utf16_string) {\n  if (utf16_string == nullptr) {\n    return std::string();\n  }\n  int target_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, nullptr, 0, nullptr, nullptr)\n    -1; // remove the trailing null character\n  int input_length = (int)wcslen(utf16_string);\n  std::string utf8_string;\n  if (target_length <= 0 || target_length > utf8_string.max_size()) {\n    return utf8_string;\n  }\n  utf8_string.resize(target_length);\n  int converted_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      input_length, utf8_string.data(), target_length, nullptr, nullptr);\n  if (converted_length == 0) {\n    return std::string();\n  }\n  return utf8_string;\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/utils.h",
    "content": "#ifndef RUNNER_UTILS_H_\n#define RUNNER_UTILS_H_\n\n#include <string>\n#include <vector>\n\n// Creates a console for the process, and redirects stdout and stderr to\n// it for both the runner and the Flutter library.\nvoid CreateAndAttachConsole();\n\n// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string\n// encoded in UTF-8. Returns an empty std::string on failure.\nstd::string Utf8FromUtf16(const wchar_t* utf16_string);\n\n// Gets the command line arguments passed in as a std::vector<std::string>,\n// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.\nstd::vector<std::string> GetCommandLineArguments();\n\n#endif  // RUNNER_UTILS_H_\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/win32_window.cpp",
    "content": "#include \"win32_window.h\"\n\n#include <dwmapi.h>\n#include <flutter_windows.h>\n\n#include \"resource.h\"\n\nnamespace {\n\n/// Window attribute that enables dark mode window decorations.\n///\n/// Redefined in case the developer's machine has a Windows SDK older than\n/// version 10.0.22000.0.\n/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute\n#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE\n#define DWMWA_USE_IMMERSIVE_DARK_MODE 20\n#endif\n\nconstexpr const wchar_t kWindowClassName[] = L\"FLUTTER_RUNNER_WIN32_WINDOW\";\n\n/// Registry key for app theme preference.\n///\n/// A value of 0 indicates apps should use dark mode. A non-zero or missing\n/// value indicates apps should use light mode.\nconstexpr const wchar_t kGetPreferredBrightnessRegKey[] =\n  L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Themes\\\\Personalize\";\nconstexpr const wchar_t kGetPreferredBrightnessRegValue[] = L\"AppsUseLightTheme\";\n\n// The number of Win32Window objects that currently exist.\nstatic int g_active_window_count = 0;\n\nusing EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);\n\n// Scale helper to convert logical scaler values to physical using passed in\n// scale factor\nint Scale(int source, double scale_factor) {\n  return static_cast<int>(source * scale_factor);\n}\n\n// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.\n// This API is only needed for PerMonitor V1 awareness mode.\nvoid EnableFullDpiSupportIfAvailable(HWND hwnd) {\n  HMODULE user32_module = LoadLibraryA(\"User32.dll\");\n  if (!user32_module) {\n    return;\n  }\n  auto enable_non_client_dpi_scaling =\n      reinterpret_cast<EnableNonClientDpiScaling*>(\n          GetProcAddress(user32_module, \"EnableNonClientDpiScaling\"));\n  if (enable_non_client_dpi_scaling != nullptr) {\n    enable_non_client_dpi_scaling(hwnd);\n  }\n  FreeLibrary(user32_module);\n}\n\n}  // namespace\n\n// Manages the Win32Window's window class registration.\nclass WindowClassRegistrar {\n public:\n  ~WindowClassRegistrar() = default;\n\n  // Returns the singleton registrar instance.\n  static WindowClassRegistrar* GetInstance() {\n    if (!instance_) {\n      instance_ = new WindowClassRegistrar();\n    }\n    return instance_;\n  }\n\n  // Returns the name of the window class, registering the class if it hasn't\n  // previously been registered.\n  const wchar_t* GetWindowClass();\n\n  // Unregisters the window class. Should only be called if there are no\n  // instances of the window.\n  void UnregisterWindowClass();\n\n private:\n  WindowClassRegistrar() = default;\n\n  static WindowClassRegistrar* instance_;\n\n  bool class_registered_ = false;\n};\n\nWindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;\n\nconst wchar_t* WindowClassRegistrar::GetWindowClass() {\n  if (!class_registered_) {\n    WNDCLASS window_class{};\n    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);\n    window_class.lpszClassName = kWindowClassName;\n    window_class.style = CS_HREDRAW | CS_VREDRAW;\n    window_class.cbClsExtra = 0;\n    window_class.cbWndExtra = 0;\n    window_class.hInstance = GetModuleHandle(nullptr);\n    window_class.hIcon =\n        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));\n    window_class.hbrBackground = 0;\n    window_class.lpszMenuName = nullptr;\n    window_class.lpfnWndProc = Win32Window::WndProc;\n    RegisterClass(&window_class);\n    class_registered_ = true;\n  }\n  return kWindowClassName;\n}\n\nvoid WindowClassRegistrar::UnregisterWindowClass() {\n  UnregisterClass(kWindowClassName, nullptr);\n  class_registered_ = false;\n}\n\nWin32Window::Win32Window() {\n  ++g_active_window_count;\n}\n\nWin32Window::~Win32Window() {\n  --g_active_window_count;\n  Destroy();\n}\n\nbool Win32Window::Create(const std::wstring& title,\n                         const Point& origin,\n                         const Size& size) {\n  Destroy();\n\n  const wchar_t* window_class =\n      WindowClassRegistrar::GetInstance()->GetWindowClass();\n\n  const POINT target_point = {static_cast<LONG>(origin.x),\n                              static_cast<LONG>(origin.y)};\n  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);\n  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);\n  double scale_factor = dpi / 96.0;\n\n  HWND window = CreateWindow(\n      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,\n      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),\n      Scale(size.width, scale_factor), Scale(size.height, scale_factor),\n      nullptr, nullptr, GetModuleHandle(nullptr), this);\n\n  if (!window) {\n    return false;\n  }\n\n  UpdateTheme(window);\n\n  return OnCreate();\n}\n\nbool Win32Window::Show() {\n  return ShowWindow(window_handle_, SW_SHOWNORMAL);\n}\n\n// static\nLRESULT CALLBACK Win32Window::WndProc(HWND const window,\n                                      UINT const message,\n                                      WPARAM const wparam,\n                                      LPARAM const lparam) noexcept {\n  if (message == WM_NCCREATE) {\n    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);\n    SetWindowLongPtr(window, GWLP_USERDATA,\n                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));\n\n    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);\n    EnableFullDpiSupportIfAvailable(window);\n    that->window_handle_ = window;\n  } else if (Win32Window* that = GetThisFromHandle(window)) {\n    return that->MessageHandler(window, message, wparam, lparam);\n  }\n\n  return DefWindowProc(window, message, wparam, lparam);\n}\n\nLRESULT\nWin32Window::MessageHandler(HWND hwnd,\n                            UINT const message,\n                            WPARAM const wparam,\n                            LPARAM const lparam) noexcept {\n  switch (message) {\n    case WM_DESTROY:\n      window_handle_ = nullptr;\n      Destroy();\n      if (quit_on_close_) {\n        PostQuitMessage(0);\n      }\n      return 0;\n\n    case WM_DPICHANGED: {\n      auto newRectSize = reinterpret_cast<RECT*>(lparam);\n      LONG newWidth = newRectSize->right - newRectSize->left;\n      LONG newHeight = newRectSize->bottom - newRectSize->top;\n\n      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,\n                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);\n\n      return 0;\n    }\n    case WM_SIZE: {\n      RECT rect = GetClientArea();\n      if (child_content_ != nullptr) {\n        // Size and position the child window.\n        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,\n                   rect.bottom - rect.top, TRUE);\n      }\n      return 0;\n    }\n\n    case WM_ACTIVATE:\n      if (child_content_ != nullptr) {\n        SetFocus(child_content_);\n      }\n      return 0;\n\n    case WM_DWMCOLORIZATIONCOLORCHANGED:\n      UpdateTheme(hwnd);\n      return 0;\n  }\n\n  return DefWindowProc(window_handle_, message, wparam, lparam);\n}\n\nvoid Win32Window::Destroy() {\n  OnDestroy();\n\n  if (window_handle_) {\n    DestroyWindow(window_handle_);\n    window_handle_ = nullptr;\n  }\n  if (g_active_window_count == 0) {\n    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();\n  }\n}\n\nWin32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {\n  return reinterpret_cast<Win32Window*>(\n      GetWindowLongPtr(window, GWLP_USERDATA));\n}\n\nvoid Win32Window::SetChildContent(HWND content) {\n  child_content_ = content;\n  SetParent(content, window_handle_);\n  RECT frame = GetClientArea();\n\n  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,\n             frame.bottom - frame.top, true);\n\n  SetFocus(child_content_);\n}\n\nRECT Win32Window::GetClientArea() {\n  RECT frame;\n  GetClientRect(window_handle_, &frame);\n  return frame;\n}\n\nHWND Win32Window::GetHandle() {\n  return window_handle_;\n}\n\nvoid Win32Window::SetQuitOnClose(bool quit_on_close) {\n  quit_on_close_ = quit_on_close;\n}\n\nbool Win32Window::OnCreate() {\n  // No-op; provided for subclasses.\n  return true;\n}\n\nvoid Win32Window::OnDestroy() {\n  // No-op; provided for subclasses.\n}\n\nvoid Win32Window::UpdateTheme(HWND const window) {\n  DWORD light_mode;\n  DWORD light_mode_size = sizeof(light_mode);\n  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,\n                               kGetPreferredBrightnessRegValue,\n                               RRF_RT_REG_DWORD, nullptr, &light_mode,\n                               &light_mode_size);\n\n  if (result == ERROR_SUCCESS) {\n    BOOL enable_dark_mode = light_mode == 0;\n    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,\n                          &enable_dark_mode, sizeof(enable_dark_mode));\n  }\n}\n"
  },
  {
    "path": "simple_live_tv_app/windows/runner/win32_window.h",
    "content": "#ifndef RUNNER_WIN32_WINDOW_H_\n#define RUNNER_WIN32_WINDOW_H_\n\n#include <windows.h>\n\n#include <functional>\n#include <memory>\n#include <string>\n\n// A class abstraction for a high DPI-aware Win32 Window. Intended to be\n// inherited from by classes that wish to specialize with custom\n// rendering and input handling\nclass Win32Window {\n public:\n  struct Point {\n    unsigned int x;\n    unsigned int y;\n    Point(unsigned int x, unsigned int y) : x(x), y(y) {}\n  };\n\n  struct Size {\n    unsigned int width;\n    unsigned int height;\n    Size(unsigned int width, unsigned int height)\n        : width(width), height(height) {}\n  };\n\n  Win32Window();\n  virtual ~Win32Window();\n\n  // Creates a win32 window with |title| that is positioned and sized using\n  // |origin| and |size|. New windows are created on the default monitor. Window\n  // sizes are specified to the OS in physical pixels, hence to ensure a\n  // consistent size this function will scale the inputted width and height as\n  // as appropriate for the default monitor. The window is invisible until\n  // |Show| is called. Returns true if the window was created successfully.\n  bool Create(const std::wstring& title, const Point& origin, const Size& size);\n\n  // Show the current window. Returns true if the window was successfully shown.\n  bool Show();\n\n  // Release OS resources associated with window.\n  void Destroy();\n\n  // Inserts |content| into the window tree.\n  void SetChildContent(HWND content);\n\n  // Returns the backing Window handle to enable clients to set icon and other\n  // window properties. Returns nullptr if the window has been destroyed.\n  HWND GetHandle();\n\n  // If true, closing this window will quit the application.\n  void SetQuitOnClose(bool quit_on_close);\n\n  // Return a RECT representing the bounds of the current client area.\n  RECT GetClientArea();\n\n protected:\n  // Processes and route salient window messages for mouse handling,\n  // size change and DPI. Delegates handling of these to member overloads that\n  // inheriting classes can handle.\n  virtual LRESULT MessageHandler(HWND window,\n                                 UINT const message,\n                                 WPARAM const wparam,\n                                 LPARAM const lparam) noexcept;\n\n  // Called when CreateAndShow is called, allowing subclass window-related\n  // setup. Subclasses should return false if setup fails.\n  virtual bool OnCreate();\n\n  // Called when Destroy is called.\n  virtual void OnDestroy();\n\n private:\n  friend class WindowClassRegistrar;\n\n  // OS callback called by message pump. Handles the WM_NCCREATE message which\n  // is passed when the non-client area is being created and enables automatic\n  // non-client DPI scaling so that the non-client area automatically\n  // responds to changes in DPI. All other messages are handled by\n  // MessageHandler.\n  static LRESULT CALLBACK WndProc(HWND const window,\n                                  UINT const message,\n                                  WPARAM const wparam,\n                                  LPARAM const lparam) noexcept;\n\n  // Retrieves a class instance pointer for |window|\n  static Win32Window* GetThisFromHandle(HWND const window) noexcept;\n\n  // Update the window frame's theme to match the system theme.\n  static void UpdateTheme(HWND const window);\n\n  bool quit_on_close_ = false;\n\n  // window handle for top level window.\n  HWND window_handle_ = nullptr;\n\n  // window handle for hosted content.\n  HWND child_content_ = nullptr;\n};\n\n#endif  // RUNNER_WIN32_WINDOW_H_\n"
  }
]