diff --git a/.github/workflows/build-nym-vpn-core-ios.yml b/.github/workflows/build-nym-vpn-core-ios.yml index 88695e65d8..9b30ea667e 100644 --- a/.github/workflows/build-nym-vpn-core-ios.yml +++ b/.github/workflows/build-nym-vpn-core-ios.yml @@ -33,13 +33,7 @@ jobs: with: toolchain: stable components: rustfmt, clippy - - - name: Install extra arch apple - run: | - rustup target add x86_64-apple-darwin - rustup target add aarch64-apple-ios - rustup target add x86_64-apple-ios - rustup target add aarch64-apple-ios-sim + targets: x86_64-apple-darwin aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim - name: Setup cargo swift run: | diff --git a/.github/workflows/build-nym-vpn-core-mac.yml b/.github/workflows/build-nym-vpn-core-mac.yml index f94e26ba5b..de2b2263c2 100644 --- a/.github/workflows/build-nym-vpn-core-mac.yml +++ b/.github/workflows/build-nym-vpn-core-mac.yml @@ -26,10 +26,7 @@ jobs: with: toolchain: stable components: rustfmt, clippy - - - name: Install extra arch apple - run: | - rustup target add x86_64-apple-darwin + targets: x86_64-apple-darwin aarch64-apple-darwin - name: Install Go toochain uses: actions/setup-go@v5 diff --git a/.github/workflows/build-nym-vpn-core-windows.yml b/.github/workflows/build-nym-vpn-core-windows.yml index 37d2018bb7..f9315b1064 100644 --- a/.github/workflows/build-nym-vpn-core-windows.yml +++ b/.github/workflows/build-nym-vpn-core-windows.yml @@ -99,7 +99,7 @@ jobs: echo "moving binaries into ${{ env.UPLOAD_DIR_WINDOWS }}" rm -rf ${{ env.UPLOAD_DIR_WINDOWS }} || true mkdir ${{ env.UPLOAD_DIR_WINDOWS }} - cp -vpr ${{ env.SRC_BINARY }}/nym-gateway-probe.exe ${{ env.UPLOAD_DIR_WINDOWS }} + #cp -vpr ${{ env.SRC_BINARY }}/nym-gateway-probe.exe ${{ env.UPLOAD_DIR_WINDOWS }} cp -vpr ${{ env.SRC_BINARY }}/nym-vpn-cli.exe ${{ env.UPLOAD_DIR_WINDOWS }} cp -vpr ${{ env.SRC_BINARY }}/nym-vpnc.exe ${{ env.UPLOAD_DIR_WINDOWS }} cp -vpr ${{ env.SRC_BINARY }}/nym-vpnd.exe ${{ env.UPLOAD_DIR_WINDOWS }} diff --git a/.github/workflows/build-wireguard-go-windows.yml b/.github/workflows/build-wireguard-go-windows.yml index a26ef51017..a6c83bb7ae 100644 --- a/.github/workflows/build-wireguard-go-windows.yml +++ b/.github/workflows/build-wireguard-go-windows.yml @@ -29,11 +29,35 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v2 + - name: Install build tools + shell: cmd + run: | + winget install --disable-interactivity --id=Microsoft.VisualStudio.2022.BuildTools --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended" + if %ERRORLEVEL% EQU -1978335189 ( + exit /b 0 + ) + + - name: Update path with vctools + shell: pwsh + run: | + $path = "$Env:ProgramFiles (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC" + $contents = Get-ChildItem $path | Select-Object -First 1 + $subdir = $contents[0].Name + $vctoolsdir = "$path/$subdir/bin/Hostx64/x64" + echo "Add vctools dir to path: $vctoolsdir" + Add-Content $env:GITHUB_PATH "$vctoolsdir" + + - name: Setup msys2 + uses: msys2/setup-msys2@v2 + with: + update: false + msystem: MINGW64 + install: mingw-w64-x86_64-clang - name: Build wireguard - shell: bash + shell: msys2 {0} + env: + MSYS2_PATH_TYPE: inherit run: | ./wireguard/build-wireguard-go.sh diff --git a/.github/workflows/ci-nym-vpn-core-android.yml b/.github/workflows/ci-nym-vpn-core-android.yml new file mode 100644 index 0000000000..60309d34e0 --- /dev/null +++ b/.github/workflows/ci-nym-vpn-core-android.yml @@ -0,0 +1,103 @@ +name: ci-nym-vpn-core-android + +on: + # push: + pull_request: + paths: + - "nym-vpn-core/**" + - ".github/workflows/ci-nym-vpn-core-android.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 + +jobs: + build: + runs-on: arc-ubuntu-22.04 + + steps: + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libmnl-dev libnftnl-dev protobuf-compiler git curl gcc g++ make unzip + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install rust toolchain + uses: brndnmtthws/rust-action-rustup@v1 + with: + toolchain: stable + components: rustfmt, clippy + targets: aarch64-linux-android + + - name: Install cargo ndk + run: cargo install cargo-ndk + + - name: Setup NDK + uses: nttld/setup-ndk@v1 + id: setup-ndk + with: + ndk-version: r25c + add-to-path: false + + - name: Set env + shell: bash + run: | + echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV + echo "NDK_TOOLCHAIN_DIR=${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_ENV + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "stable" + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build wireguard + run: ./wireguard/libwg/build-android.sh + + - name: rustfmt check + working-directory: nym-vpn-core + run: | + cargo fmt --check + + - name: Build + working-directory: nym-vpn-core + run: | + cargo ndk -t aarch64-linux-android -o ./build build -p nym-vpn-lib + + - name: Generate uniffi + working-directory: nym-vpn-core + run: | + cargo run --bin uniffi-bindgen generate \ + --library target/aarch64-linux-android/debug/libnym_vpn_lib.so \ + --config crates/nym-vpn-lib/uniffi.toml \ + --language kotlin --out-dir build -n + + - name: Uniffi diff check + working-directory: nym-vpn-core + run: | + diff -B build/nym_vpn_lib/nym_vpn_lib.kt crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt + continue-on-error: true + id: diff_android + + - name: Upload generated uniffi file + if: steps.diff_android.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: updated-uniffi-android + path: nym-vpn-core/build/nym_vpn_lib/nym_vpn_lib.kt + retention-days: 1 + + - name: Fail workflow for uniffi + if: steps.diff_android.outcome == 'failure' + run: exit 1 + + - name: Clippy + working-directory: nym-vpn-core + run: | + cargo ndk -t aarch64-linux-android clippy -p nym-vpn-lib -- -Dwarning diff --git a/.github/workflows/ci-nym-vpn-core-ios.yml b/.github/workflows/ci-nym-vpn-core-ios.yml new file mode 100644 index 0000000000..1e93f1146e --- /dev/null +++ b/.github/workflows/ci-nym-vpn-core-ios.yml @@ -0,0 +1,94 @@ +name: ci-nym-vpn-core-ios + +on: + # push: + pull_request: + paths: + - "nym-vpn-core/**" + - ".github/workflows/ci-nym-vpn-core-ios.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 + +jobs: + build: + runs-on: custom-runner-mac-m1 + + steps: + - name: "Cleanup working directory" + shell: bash + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install rust toolchain + uses: brndnmtthws/rust-action-rustup@v1 + with: + toolchain: stable + components: rustfmt, clippy + targets: aarch64-apple-ios + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "stable" + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build wireguard + shell: bash + run: | + ./wireguard/build-wireguard-go.sh --ios + + - name: rustfmt check + working-directory: nym-vpn-core + run: | + cargo fmt --check + + - name: Build + working-directory: nym-vpn-core + run: | + cargo build --verbose --target aarch64-apple-ios -p nym-vpn-lib + + - name: Generate uniffi + working-directory: nym-vpn-core + run: | + cargo run --bin uniffi-bindgen generate \ + --library target/aarch64-apple-ios/debug/libnym_vpn_lib.a \ + --config crates/nym-vpn-lib/uniffi.toml \ + --language swift --out-dir build -n + + - name: Uniffi diff check + working-directory: nym-vpn-core + run: | + diff -B build/nym_vpn_lib.swift crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift + continue-on-error: true + id: diff_ios + + - name: Upload generated uniffi file + if: steps.diff_ios.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: updated-uniffi-ios + path: nym-vpn-core/build/nym_vpn_lib.swift + retention-days: 1 + + - name: Fail workflow for uniffi + if: steps.diff_ios.outcome == 'failure' + run: exit 1 + + - name: Clippy + working-directory: nym-vpn-core + run: | + cargo clippy --target aarch64-apple-ios -p nym-vpn-lib -- -Dwarnings diff --git a/.github/workflows/ci-nym-vpn-core-linux.yml b/.github/workflows/ci-nym-vpn-core-linux.yml new file mode 100644 index 0000000000..b3fbca725c --- /dev/null +++ b/.github/workflows/ci-nym-vpn-core-linux.yml @@ -0,0 +1,67 @@ +name: ci-nym-vpn-core-linux + +on: + # push: + pull_request: + paths: + - "nym-vpn-core/**" + - ".github/workflows/ci-nym-vpn-core-linux.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 + +jobs: + build: + runs-on: arc-ubuntu-22.04 + + steps: + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libmnl-dev libnftnl-dev protobuf-compiler git curl gcc g++ make unzip + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install rust toolchain + uses: brndnmtthws/rust-action-rustup@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "stable" + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build wireguard + shell: bash + run: | + ./wireguard/build-wireguard-go.sh + + - name: rustfmt check + working-directory: nym-vpn-core + run: | + cargo fmt --check + + - name: Build + working-directory: nym-vpn-core + run: | + cargo build --verbose + + - name: Run tests + working-directory: nym-vpn-core + run: | + cargo test --verbose + + - name: Clippy + working-directory: nym-vpn-core + run: | + cargo clippy -- -Dwarnings + diff --git a/.github/workflows/ci-nym-vpn-core-macos.yml b/.github/workflows/ci-nym-vpn-core-macos.yml new file mode 100644 index 0000000000..ae017291a0 --- /dev/null +++ b/.github/workflows/ci-nym-vpn-core-macos.yml @@ -0,0 +1,66 @@ +name: ci-nym-vpn-core-macos + +on: + # push: + pull_request: + paths: + - "nym-vpn-core/**" + - ".github/workflows/ci-nym-vpn-core-macos.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 + +jobs: + build: + runs-on: custom-runner-mac-m1 + + steps: + - name: "Cleanup working directory" + shell: bash + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install rust toolchain + uses: brndnmtthws/rust-action-rustup@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "stable" + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build wireguard + shell: bash + run: | + ./wireguard/build-wireguard-go.sh + + - name: rustfmt check + working-directory: nym-vpn-core + run: | + cargo fmt --check + + - name: Run tests + working-directory: nym-vpn-core + run: | + cargo test --verbose + + - name: Clippy + working-directory: nym-vpn-core + run: | + cargo clippy -- -Dwarnings diff --git a/.github/workflows/ci-nym-vpn-core-windows.yml b/.github/workflows/ci-nym-vpn-core-windows.yml new file mode 100644 index 0000000000..45b364c3cd --- /dev/null +++ b/.github/workflows/ci-nym-vpn-core-windows.yml @@ -0,0 +1,138 @@ +name: ci-nym-vpn-core-windows + +on: + # push: + pull_request: + paths: + - "nym-vpn-core/**" + - ".github/workflows/ci-nym-vpn-core-windows.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 + +jobs: + build: + runs-on: custom-windows-11 + + steps: + - name: "Cleanup working directory" + shell: bash + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + + - name: Support longpaths on windows + run: git config --system core.longpaths true + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install rust toolchain + uses: brndnmtthws/rust-action-rustup@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - name: Set env + shell: bash + run: | + echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib -Clink-args=/LIBPATH:${GITHUB_WORKSPACE}/build/lib/x64-Debug" >> $GITHUB_ENV + mkdir -p ${GITHUB_WORKSPACE}/build/lib/ + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "stable" + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install build tools + shell: cmd + run: | + winget install --disable-interactivity --id=Microsoft.VisualStudio.2022.BuildTools --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended" + if %ERRORLEVEL% EQU -1978335189 ( + exit /b 0 + ) + + - name: Update path with vctools + shell: pwsh + run: | + $buildtoolspath = "$Env:ProgramFiles (x86)/Microsoft Visual Studio/2022/BuildTools" + $msbuildpath = "$buildtoolspath/MSBuild/Current/Bin" + echo "Add msbuild dir to path: $msbuildpath" + Add-Content $env:GITHUB_PATH "$msbuildpath" + + $msvctoolspath = "$buildtoolspath/VC/Tools/MSVC" + $contents = Get-ChildItem $msvctoolspath | Select-Object -First 1 + $subdir = $contents[0].Name + $vctoolsdir = "$msvctoolspath/$subdir/bin/Hostx64/x64" + echo "Add vctools dir to path: $vctoolsdir" + Add-Content $env:GITHUB_PATH "$vctoolsdir" + + - name: Setup msys2 + uses: msys2/setup-msys2@v2 + with: + update: false + msystem: MINGW64 + install: mingw-w64-x86_64-clang + + - name: Build wireguard + shell: msys2 {0} + env: + MSYS2_PATH_TYPE: inherit + run: | + ./wireguard/build-wireguard-go.sh + + - name: Download wintun.zip + shell: bash + run: | + curl --output ${GITHUB_WORKSPACE}/wintun.zip https://www.wintun.net/builds/wintun-0.14.1.zip + unzip ${GITHUB_WORKSPACE}/wintun.zip + mv ${GITHUB_WORKSPACE}/wintun/bin/amd64/wintun.dll ${GITHUB_WORKSPACE}/build/lib/ + + - name: Checkout mullvad libs for Windows + uses: actions/checkout@v4 + with: + repository: nymtech/nym-vpn-mullvad-libs + ref: main + path: "nym-vpn-mullvad-libs" + submodules: true + + - name: Build winfw.dll from mullvad + shell: bash + run: | + cd ${GITHUB_WORKSPACE}/nym-vpn-mullvad-libs + ./build-windows-modules.sh + + - name: Move winfw.dll to build directory + shell: bash + run: | + mv ${GITHUB_WORKSPACE}/nym-vpn-mullvad-libs/windows/winfw/bin/x64-Debug ${GITHUB_WORKSPACE}/build/lib/ + + - name: rustfmt check + working-directory: nym-vpn-core + run: | + cargo fmt --check + + - name: Build + working-directory: nym-vpn-core + run: | + cargo build --verbose + + - name: Run tests + working-directory: nym-vpn-core + run: | + cargo test --verbose + + - name: Clippy + working-directory: nym-vpn-core + run: | + cargo clippy -- -Dwarnings diff --git a/.github/workflows/ci-nym-vpn-core.yml b/.github/workflows/ci-nym-vpn-core.yml deleted file mode 100644 index a1c45777b9..0000000000 --- a/.github/workflows/ci-nym-vpn-core.yml +++ /dev/null @@ -1,299 +0,0 @@ -name: ci-nym-vpn-core - -on: - # push: - pull_request: - paths: - - "nym-vpn-core/**" - - ".github/workflows/ci-nym-vpn-core.yml" - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - AGENT_ISSELFHOSTED: 1 # https://github.com/actions/setup-go/issues/432 - -jobs: - build: - strategy: - fail-fast: false - matrix: - # os: [arc-ubuntu-22.04, custom-runner-mac-m1, custom-windows-11] - os: [arc-ubuntu-22.04, custom-runner-mac-m1] - target: [native] - include: - - os: arc-ubuntu-22.04 - target: android - - os: custom-runner-mac-m1 - target: ios - runs-on: ${{ matrix.os }} - - steps: - - name: "Cleanup working directory" - if: contains(matrix.os, 'custom') - shell: bash - run: | - ls -la ./ - rm -rf ./* || true - rm -rf ./.??* || true - ls -la ./ - - - name: Install system dependencies - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libmnl-dev libnftnl-dev protobuf-compiler git curl gcc g++ make unzip - if: contains(matrix.os, 'ubuntu') - - - name: Support longpaths on windows - if: contains(matrix.os, 'windows') - run: git config --system core.longpaths true - - - name: Install script dependencies - if: contains(matrix.os, 'mac') - run: brew install gnu-getopt - - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Install rust toolchain - uses: brndnmtthws/rust-action-rustup@v1 - with: - toolchain: stable - components: rustfmt, clippy - - - name: Install cargo ndk - if: matrix.target == 'android' - run: cargo install cargo-ndk - - - name: Setup NDK - uses: nttld/setup-ndk@v1 - id: setup-ndk - if: matrix.target == 'android' - with: - ndk-version: r25c - add-to-path: false - - - name: Add iOS target - if: matrix.target == 'ios' - run: rustup target add aarch64-apple-ios - - - name: Add Android target - if: matrix.target == 'android' - run: rustup target add aarch64-linux-android - - - name: Set env - shell: bash - run: | - if ${{ contains(matrix.os, 'ubuntu') && contains(matrix.target, 'native') }}; then - triplet=x86_64-unknown-linux-gnu - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet}" >> $GITHUB_ENV - elif ${{ matrix.target == 'android' }}; then - triplet=aarch64-linux-android - echo "ANDROID_NDK_HOME=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV - echo "NDK_TOOLCHAIN_DIR=${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_ENV - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet} -L ${GITHUB_WORKSPACE}/build/lib/x86_64-unknown-linux-gnu" >> $GITHUB_ENV - elif ${{ matrix.target == 'ios' }}; then - triplet=aarch64-apple-ios - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet}" >> $GITHUB_ENV - elif ${{ matrix.os == 'macos-12' || matrix.os == 'macos-13' }}; then - triplet=x86_64-apple-darwin - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet}" >> $GITHUB_ENV - elif ${{ contains(matrix.os, 'macos') || contains(matrix.os, 'mac-m1') }}; then - triplet=universal-apple-darwin - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet}" >> $GITHUB_ENV - elif ${{ contains(matrix.os, 'windows') }}; then - triplet=x86_64-pc-windows-msvc - echo "TRIPLET=$triplet" >> $GITHUB_ENV - echo "RUSTFLAGS=-L ${GITHUB_WORKSPACE}/build/lib/${triplet} -L ${GITHUB_WORKSPACE}/build/lib/ -Clink-args=/LIBPATH:${GITHUB_WORKSPACE}/build/lib/x64-Debug" >> $GITHUB_ENV - mkdir -p ${GITHUB_WORKSPACE}/build/lib/ - else - echo " ✗ unknown platform/arch [${{ matrix.os }}]" - exit 1 - fi - - - name: Install Go - if: ${{ !contains(matrix.os, 'ubuntu') }} - uses: actions/setup-go@v5 - with: - go-version: "stable" - - - name: Install Protoc - uses: arduino/setup-protoc@v3 - with: - version: "21.12" # 3.21.12: the version on ubuntu 24.04. Don't change this! - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup MSBuild.exe - if: contains(matrix.os, 'windows') - uses: microsoft/setup-msbuild@v2 - - - name: Build wireguard - if: matrix.target != 'ios' && matrix.target != 'android' - shell: bash - run: | - ./wireguard/build-wireguard-go.sh - - - name: Build wireguard (iOS) - if: matrix.target == 'ios' - shell: bash - run: | - ./wireguard/build-wireguard-go.sh --ios - - - name: Build wireguard (Android) - if: matrix.target == 'android' - run: ./wireguard/libwg/build-android.sh - - - name: Download wintun.zip and winpcap.zip - if: contains(matrix.os, 'windows') - shell: bash - run: | - curl --output ${GITHUB_WORKSPACE}/wintun.zip https://www.wintun.net/builds/wintun-0.14.1.zip - curl --output ${GITHUB_WORKSPACE}/winpcap.zip https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip - - - name: Unzip wintun.zip and winpcap.zip - if: contains(matrix.os, 'windows') - shell: bash - run: | - unzip ${GITHUB_WORKSPACE}/wintun.zip - unzip ${GITHUB_WORKSPACE}/winpcap.zip - - - name: Move wintun.dll and packet.lib to build directory - if: contains(matrix.os, 'windows') - shell: bash - run: | - mv ${GITHUB_WORKSPACE}/wintun/bin/amd64/wintun.dll ${GITHUB_WORKSPACE}/build/lib/ - mv ${GITHUB_WORKSPACE}/WpdPack/Lib/x64/Packet.lib ${GITHUB_WORKSPACE}/build/lib/ - - - name: Checkout mullvad libs for Windows - if: contains(matrix.os, 'windows') - uses: actions/checkout@v4 - with: - repository: nymtech/nym-vpn-mullvad-libs - ref: main - path: "nym-vpn-mullvad-libs" - submodules: true - - - name: Build winfw.dll from mullvad - if: contains(matrix.os, 'windows') - shell: bash - run: | - cd ${GITHUB_WORKSPACE}/nym-vpn-mullvad-libs - ./build-windows-modules.sh - - - name: Move winfw.dll to build directory - if: contains(matrix.os, 'windows') - shell: bash - run: | - mv ${GITHUB_WORKSPACE}/nym-vpn-mullvad-libs/windows/winfw/bin/x64-Debug ${GITHUB_WORKSPACE}/build/lib/ - - - name: rustfmt check - working-directory: nym-vpn-core - run: | - cargo fmt --check - - - name: Build - if: matrix.target != 'android' && matrix.target != 'ios' - working-directory: nym-vpn-core - run: | - cargo build --verbose - - - name: Build (Android) - if: matrix.target == 'android' - working-directory: nym-vpn-core - run: | - cargo ndk -t aarch64-linux-android -o ./build build -p nym-vpn-lib - - - name: Build (iOS) - if: matrix.target == 'ios' - working-directory: nym-vpn-core - run: | - cargo build --verbose --target aarch64-apple-ios -p nym-vpn-lib - - - name: Generate uniffi (Android) - if: matrix.target == 'android' - working-directory: nym-vpn-core - run: | - cargo run --bin uniffi-bindgen generate \ - --library target/aarch64-linux-android/debug/libnym_vpn_lib.so \ - --config crates/nym-vpn-lib/uniffi.toml \ - --language kotlin --out-dir build -n - - - name: Generate uniffi (iOS) - if: matrix.target == 'ios' - working-directory: nym-vpn-core - run: | - cargo run --bin uniffi-bindgen generate \ - --library target/aarch64-apple-ios/debug/libnym_vpn_lib.a \ - --config crates/nym-vpn-lib/uniffi.toml \ - --language swift --out-dir build -n - - - name: Uniffi diff check (Android) - if: matrix.target == 'android' - working-directory: nym-vpn-core - run: | - diff -B build/nym_vpn_lib/nym_vpn_lib.kt crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt - continue-on-error: true - id: diff_android - - - name: Upload generated uniffi file (Android) - if: steps.diff_android.outcome == 'failure' && matrix.target == 'android' - uses: actions/upload-artifact@v4 - with: - name: updated-uniffi-android - path: nym-vpn-core/build/nym_vpn_lib/nym_vpn_lib.kt - retention-days: 1 - - - name: Fail workflow for uniffi (Android) - if: steps.diff_android.outcome == 'failure' && matrix.target == 'android' - run: exit 1 - - - name: Uniffi diff check (iOS) - if: matrix.target == 'ios' - working-directory: nym-vpn-core - run: | - diff -B build/nym_vpn_lib.swift crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift - continue-on-error: true - id: diff_ios - - - name: Upload generated uniffi file (iOS) - if: steps.diff_ios.outcome == 'failure' && matrix.target == 'ios' - uses: actions/upload-artifact@v4 - with: - name: updated-uniffi-ios - path: nym-vpn-core/build/nym_vpn_lib.swift - retention-days: 1 - - - name: Fail workflow for uniffi (iOS) - if: steps.diff_ios.outcome == 'failure' && matrix.target == 'ios' - run: exit 1 - - - name: Run tests (Linux, macOS) - if: matrix.target != 'android' && matrix.target != 'ios' && !contains(matrix.os, 'windows') - working-directory: nym-vpn-core - run: | - cargo test --verbose - - - name: Run tests (Windows excluding gateway probe) - if: contains(matrix.os, 'windows') - working-directory: nym-vpn-core - run: | - cargo test --verbose --workspace --exclude nym-gateway-probe - - - name: Clippy - working-directory: nym-vpn-core - run: | - cargo clippy -- -Dwarnings - - - name: Clippy (Android) - if: matrix.target == 'android' - working-directory: nym-vpn-core - run: | - cargo ndk -t aarch64-linux-android clippy -p nym-vpn-lib -- -Dwarnings - - - name: Clippy (iOS) - if: matrix.target == 'ios' - working-directory: nym-vpn-core - run: | - cargo clippy --target aarch64-apple-ios -p nym-vpn-lib -- -Dwarnings diff --git a/.github/workflows/publish-nym-vpn-core.yml b/.github/workflows/publish-nym-vpn-core.yml index de0e18cd2c..882efef3f0 100644 --- a/.github/workflows/publish-nym-vpn-core.yml +++ b/.github/workflows/publish-nym-vpn-core.yml @@ -19,7 +19,7 @@ env: UPLOAD_DIR_DEB: deb_artifacts UPLOAD_DIR_ANDROID: android_artifacts UPLOAD_DIR_IOS: ios_artifacts - # UPLOAD_DIR_WINDOWS: windows_artifacts + UPLOAD_DIR_WINDOWS: windows_artifacts GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: @@ -33,8 +33,8 @@ jobs: uses: ./.github/workflows/build-nym-vpn-core-android.yml build-nym-vpn-core-ios: uses: ./.github/workflows/build-nym-vpn-core-ios.yml - # build-nym-vpn-core-windows: - # uses: ./.github/workflows/build-nym-vpn-core-windows.yml + build-nym-vpn-core-windows: + uses: ./.github/workflows/build-nym-vpn-core-windows.yml generate-build-info-core: uses: ./.github/workflows/generate-build-info-core.yml @@ -50,7 +50,7 @@ jobs: - build-nym-vpn-core-deb - build-nym-vpn-core-android - build-nym-vpn-core-ios - # - build-nym-vpn-core-windows + - build-nym-vpn-core-windows - generate-build-info-core runs-on: arc-ubuntu-22.04 permissions: @@ -100,30 +100,30 @@ jobs: ARCHIVE_MAC=nym-vpn-core-v${{ steps.workspace-version.outputs.metadata }}_macos_universal ARCHIVE_ANDROID=nym-vpn-core-v${{ steps.workspace-version.outputs.metadata }}_android_aarch64 ARCHIVE_IOS=nym-vpn-core-v${{ steps.workspace-version.outputs.metadata }}_ios_universal - # ARCHIVE_WINDOWS=nym-vpn-core-v${{ steps.workspace-version.outputs.metadata }}_windows_x86_64 + ARCHIVE_WINDOWS=nym-vpn-core-v${{ steps.workspace-version.outputs.metadata }}_windows_x86_64 echo "ARCHIVE_LINUX=${ARCHIVE_LINUX}" >> $GITHUB_ENV echo "ARCHIVE_MAC=${ARCHIVE_MAC}" >> $GITHUB_ENV echo "ARCHIVE_ANDROID=${ARCHIVE_ANDROID}" >> $GITHUB_ENV echo "ARCHIVE_IOS=${ARCHIVE_IOS}" >> $GITHUB_ENV - # echo "ARCHIVE_WINDOWS=${ARCHIVE_WINDOWS}" >> $GITHUB_ENV + echo "ARCHIVE_WINDOWS=${ARCHIVE_WINDOWS}" >> $GITHUB_ENV mv ${{ env.UPLOAD_DIR_LINUX }} ${ARCHIVE_LINUX} mv ${{ env.UPLOAD_DIR_MAC }} ${ARCHIVE_MAC} mv ${{ env.UPLOAD_DIR_ANDROID }} ${ARCHIVE_ANDROID} mv ${{ env.UPLOAD_DIR_IOS }} ${ARCHIVE_IOS} - # mv ${{ env.UPLOAD_DIR_WINDOWS }} ${ARCHIVE_WINDOWS} + mv ${{ env.UPLOAD_DIR_WINDOWS }} ${ARCHIVE_WINDOWS} tar cvzf ${ARCHIVE_LINUX}.tar.gz ${ARCHIVE_LINUX} tar cvzf ${ARCHIVE_MAC}.tar.gz ${ARCHIVE_MAC} tar cvzf ${ARCHIVE_ANDROID}.tar.gz ${ARCHIVE_ANDROID} zip -r ${ARCHIVE_IOS}.zip ${ARCHIVE_IOS} - # zip -r ${ARCHIVE_WINDOWS}.zip ${ARCHIVE_WINDOWS} + zip -r ${ARCHIVE_WINDOWS}.zip ${ARCHIVE_WINDOWS} sha256sum ${ARCHIVE_LINUX}.tar.gz > "${ARCHIVE_LINUX}.tar.gz.sha256sum" sha256sum ${ARCHIVE_MAC}.tar.gz > "${ARCHIVE_MAC}.tar.gz.sha256sum" sha256sum ${ARCHIVE_ANDROID}.tar.gz > "${ARCHIVE_ANDROID}.tar.gz.sha256sum" sha256sum ${ARCHIVE_IOS}.zip > "${ARCHIVE_IOS}.zip.sha256sum" - # sha256sum ${ARCHIVE_WINDOWS}.zip > "${ARCHIVE_WINDOWS}.zip.sha256sum" + sha256sum ${ARCHIVE_WINDOWS}.zip > "${ARCHIVE_WINDOWS}.zip.sha256sum" pushd ${{ env.UPLOAD_DIR_DEB }} for deb in nym-vpn*_amd64.deb; do @@ -136,7 +136,7 @@ jobs: cat ${ARCHIVE_MAC}.tar.gz.sha256sum >> $GITHUB_ENV cat ${ARCHIVE_ANDROID}.tar.gz.sha256sum >> $GITHUB_ENV cat ${ARCHIVE_IOS}.zip.sha256sum >> $GITHUB_ENV - # cat ${ARCHIVE_WINDOWS}.zip.sha256sum >> $GITHUB_ENV + cat ${ARCHIVE_WINDOWS}.zip.sha256sum >> $GITHUB_ENV pushd ${{ env.UPLOAD_DIR_DEB }} for deb_sha256 in nym-vpn*_amd64.deb.sha256sum; do cat ${deb_sha256} >> $GITHUB_ENV @@ -176,9 +176,9 @@ jobs: ${{ env.ARCHIVE_MAC }}.tar.gz ${{ env.ARCHIVE_MAC }}.tar.gz.sha256sum \ ${{ env.ARCHIVE_IOS }}.zip ${{ env.ARCHIVE_IOS }}.zip.sha256sum \ ${{ env.ARCHIVE_ANDROID }}.tar.gz ${{ env.ARCHIVE_ANDROID }}.tar.gz.sha256sum \ + ${{ env.ARCHIVE_WINDOWS }}.zip ${{ env.ARCHIVE_WINDOWS }}.zip.sha256sum \ ${{ env.UPLOAD_DIR_DEB}}/nym-vpn*_amd64.deb ${{ env.UPLOAD_DIR_DEB }}/nym-vpn*_amd64.deb.sha256sum - # ${{ env.ARCHIVE_WINDOWS }}.zip ${{ env.ARCHIVE_WINDOWS }}.zip.sha256sum \ gen-hashes: uses: ./.github/workflows/gen-hashes-json.yml diff --git a/nym-vpn-android/app/build.gradle.kts b/nym-vpn-android/app/build.gradle.kts index 6c6a71d65c..2f4cba91af 100644 --- a/nym-vpn-android/app/build.gradle.kts +++ b/nym-vpn-android/app/build.gradle.kts @@ -223,9 +223,6 @@ dependencies { implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.security.crypto) - // splash - implementation(libs.androidx.core.splashscreen) - detektPlugins(libs.detekt.rules.compose) // moshi/retrofit @@ -238,6 +235,9 @@ dependencies { // barcode scanning implementation(libs.zxing.android.embedded) + + // animations + implementation(libs.lottie.compose) } fun determineVersionCode(): Int { diff --git a/nym-vpn-android/app/src/main/AndroidManifest.xml b/nym-vpn-android/app/src/main/AndroidManifest.xml index 0a3ad92c16..2906c05936 100644 --- a/nym-vpn-android/app/src/main/AndroidManifest.xml +++ b/nym-vpn-android/app/src/main/AndroidManifest.xml @@ -26,19 +26,9 @@ android:largeHeap="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.AppSplashScreen" + android:theme="@style/Theme.NymVPN" tools:node="merge" tools:targetApi="33"> - - - - - - - + + + diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/notification/VpnAlertNotifications.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/notification/VpnAlertNotifications.kt index e49d0bd3ec..bada0bbeb5 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/notification/VpnAlertNotifications.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/notification/VpnAlertNotifications.kt @@ -13,7 +13,7 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import dagger.hilt.android.qualifiers.ApplicationContext import net.nymtech.nymvpn.R -import net.nymtech.nymvpn.ui.SplashActivity +import net.nymtech.nymvpn.ui.MainActivity import javax.inject.Inject class VpnAlertNotifications @@ -66,7 +66,7 @@ constructor( Unit } val pendingIntent: PendingIntent = - Intent(context, SplashActivity::class.java).let { notificationIntent -> + Intent(context, MainActivity::class.java).let { notificationIntent -> PendingIntent.getActivity( context, 0, diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/tunnel/NymTunnelManager.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/tunnel/NymTunnelManager.kt index 5df7c1695e..dea7f5cbef 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/tunnel/NymTunnelManager.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/service/tunnel/NymTunnelManager.kt @@ -2,6 +2,7 @@ package net.nymtech.nymvpn.service.tunnel import android.content.Context import android.net.VpnService +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -9,10 +10,13 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus import net.nymtech.nymvpn.NymVpn import net.nymtech.nymvpn.R import net.nymtech.nymvpn.data.SettingsRepository import net.nymtech.nymvpn.module.qualifiers.ApplicationScope +import net.nymtech.nymvpn.module.qualifiers.IoDispatcher import net.nymtech.nymvpn.service.notification.NotificationService import net.nymtech.nymvpn.util.Constants import net.nymtech.nymvpn.util.extensions.requestTileServiceStateUpdate @@ -33,6 +37,7 @@ class NymTunnelManager @Inject constructor( private val backend: Provider, private val context: Context, @ApplicationScope private val applicationScope: CoroutineScope, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : TunnelManager { private val _state = MutableStateFlow(TunnelState()) @@ -40,7 +45,7 @@ class NymTunnelManager @Inject constructor( _state.update { it.copy(isMnemonicStored = isMnemonicStored()) } - }.stateIn(applicationScope, SharingStarted.WhileSubscribed(Constants.SUBSCRIPTION_TIMEOUT), TunnelState()) + }.stateIn(applicationScope.plus(ioDispatcher), SharingStarted.WhileSubscribed(Constants.SUBSCRIPTION_TIMEOUT), TunnelState()) @get:Synchronized @set:Synchronized private var running: Boolean = false @@ -101,6 +106,13 @@ class NymTunnelManager @Inject constructor( private fun onBackendMessage(backendMessage: BackendMessage) { launchBackendNotification(backendMessage) emitMessage(backendMessage) + // TODO For now, we'll stop tunnel on errors + if (backendMessage is BackendMessage.Failure) { + Timber.d("Shutting tunnel down on fatal error") + applicationScope.launch(ioDispatcher) { + backend.get().stop() + } + } } private fun emitMessage(backendMessage: BackendMessage) { diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt index 65281d8555..e50ff52f5f 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt @@ -3,6 +3,10 @@ package net.nymtech.nymvpn.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import io.sentry.Instrumenter +import io.sentry.android.core.SentryAndroid +import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asStateFlow @@ -10,9 +14,14 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.nymtech.nymvpn.BuildConfig +import net.nymtech.nymvpn.NymVpn import net.nymtech.nymvpn.data.GatewayRepository import net.nymtech.nymvpn.data.SettingsRepository +import net.nymtech.nymvpn.module.qualifiers.IoDispatcher import net.nymtech.nymvpn.module.qualifiers.Native +import net.nymtech.nymvpn.service.country.CountryCacheService import net.nymtech.nymvpn.service.gateway.GatewayService import net.nymtech.nymvpn.service.tunnel.TunnelManager import net.nymtech.nymvpn.ui.common.navigation.NavBarState @@ -27,8 +36,10 @@ class AppViewModel constructor( private val settingsRepository: SettingsRepository, private val gatewayRepository: GatewayRepository, + private val countryCacheService: CountryCacheService, @Native private val gatewayService: GatewayService, private val tunnelManager: TunnelManager, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : ViewModel() { private val _navBarState = MutableStateFlow(NavBarState()) @@ -105,4 +116,50 @@ constructor( navBarState } } + + fun onAppStartup() = viewModelScope.launch { + launch { + Timber.d("Updating exit country cache") + countryCacheService.updateExitCountriesCache().onSuccess { + Timber.d("Exit countries updated") + }.onFailure { Timber.w("Failed to get exit countries: ${it.message}") } + } + launch { + Timber.d("Updating entry country cache") + countryCacheService.updateEntryCountriesCache().onSuccess { + Timber.d("Entry countries updated") + }.onFailure { Timber.w("Failed to get entry countries: ${it.message}") } + } + launch { + Timber.d("Updating entry country cache") + countryCacheService.updateWgCountriesCache().onSuccess { + Timber.d("Wg countries updated") + }.onFailure { Timber.w("Failed to get wg countries: ${it.message}") } + } + launch { + Timber.d("Configuring sentry") + configureSentry() + } + } + + private suspend fun configureSentry() { + withContext(ioDispatcher) { + if (settingsRepository.isErrorReportingEnabled()) { + SentryAndroid.init(NymVpn.instance) { options -> + options.enableTracing = true + options.enableAllAutoBreadcrumbs(true) + options.isEnableUserInteractionTracing = true + options.isEnableUserInteractionBreadcrumbs = true + options.dsn = BuildConfig.SENTRY_DSN + options.sampleRate = 1.0 + options.tracesSampleRate = 1.0 + options.profilesSampleRate = 1.0 + options.instrumenter = Instrumenter.OTEL + options.addEventProcessor(OpenTelemetryLinkErrorEventProcessor()) + options.environment = + if (BuildConfig.DEBUG) Constants.SENTRY_DEV_ENV else Constants.SENTRY_PROD_ENV + } + } + } + } } diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt index 660eccbbfa..0b5524590f 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt @@ -26,8 +26,11 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState @@ -35,6 +38,7 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import net.nymtech.localizationutil.LocaleStorage import net.nymtech.localizationutil.LocaleUtil import net.nymtech.nymvpn.NymVpn @@ -62,6 +66,7 @@ import net.nymtech.nymvpn.ui.screens.settings.legal.LegalScreen import net.nymtech.nymvpn.ui.screens.settings.legal.licenses.LicensesScreen import net.nymtech.nymvpn.ui.screens.settings.logs.LogsScreen import net.nymtech.nymvpn.ui.screens.settings.support.SupportScreen +import net.nymtech.nymvpn.ui.screens.splash.SplashScreen import net.nymtech.nymvpn.ui.theme.NymVPNTheme import net.nymtech.nymvpn.ui.theme.Theme import net.nymtech.nymvpn.util.Constants @@ -91,11 +96,16 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + appViewModel = ViewModelProvider(this)[AppViewModel::class.java] + this.resetTile() - val isAnalyticsShown = intent.extras?.getBoolean(SplashActivity.IS_ANALYTICS_SHOWN_INTENT_KEY) - val theme = intent.extras?.getString(SplashActivity.THEME) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + appViewModel.onAppStartup() + } + } setContent { val appState by appViewModel.uiState.collectAsStateWithLifecycle(lifecycle = this.lifecycle) @@ -148,13 +158,9 @@ class MainActivity : ComponentActivity() { } } - fun getTheme(): Theme { - return appState.settings.theme ?: theme?.let { Theme.valueOf(it) } ?: Theme.default() - } - CompositionLocalProvider(LocalNavController provides navController) { SnackbarControllerProvider { host -> - NymVPNTheme(theme = getTheme()) { + NymVPNTheme(theme = appState.settings.theme ?: Theme.default()) { Scaffold( contentWindowInsets = WindowInsets(0.dp), modifier = Modifier.semantics { @@ -181,7 +187,7 @@ class MainActivity : ComponentActivity() { ) { padding -> NavHost( navController, - startDestination = if (isAnalyticsShown == true) Route.Main() else Route.Analytics, + startDestination = Route.Splash, modifier = Modifier .fillMaxSize() @@ -191,6 +197,9 @@ class MainActivity : ComponentActivity() { popEnterTransition = { fadeIn(tween(200)) }, popExitTransition = { fadeOut(tween(200)) }, ) { + composable { + SplashScreen(appViewModel, appState) + } composable { val args = it.toRoute() MainScreen(appViewModel, appState, args.autoStart) diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt index 1bf1ea83c8..59d7a8c4ad 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt @@ -9,6 +9,9 @@ sealed class Route { val changeLanguage: Boolean = false, ) : Route() + @Serializable + data object Splash : Route() + @Serializable data object Analytics : Route() diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/SplashActivity.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/SplashActivity.kt deleted file mode 100644 index eb5a73feeb..0000000000 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/SplashActivity.kt +++ /dev/null @@ -1,112 +0,0 @@ -package net.nymtech.nymvpn.ui - -import android.annotation.SuppressLint -import android.content.Intent -import android.os.Build -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import dagger.hilt.android.AndroidEntryPoint -import io.sentry.Instrumenter -import io.sentry.android.core.SentryAndroid -import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import net.nymtech.nymvpn.BuildConfig -import net.nymtech.nymvpn.NymVpn -import net.nymtech.nymvpn.data.SettingsRepository -import net.nymtech.nymvpn.module.qualifiers.ApplicationScope -import net.nymtech.nymvpn.service.country.CountryCacheService -import net.nymtech.nymvpn.util.Constants -import timber.log.Timber -import javax.inject.Inject - -@SuppressLint("CustomSplashScreen") -@AndroidEntryPoint -class SplashActivity : ComponentActivity() { - - @Inject - lateinit var countryCacheService: CountryCacheService - - @Inject - lateinit var settingsRepository: SettingsRepository - - @Inject - @ApplicationScope - lateinit var applicationScope: CoroutineScope - - override fun onCreate(savedInstanceState: Bundle?) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val splashScreen = installSplashScreen() - splashScreen.setKeepOnScreenCondition { true } - } - super.onCreate(savedInstanceState) - - applicationScope.launch { - launch { - Timber.d("Updating exit country cache") - countryCacheService.updateExitCountriesCache().onSuccess { - Timber.d("Exit countries updated") - }.onFailure { Timber.w("Failed to get exit countries: ${it.message}") } - } - launch { - Timber.d("Updating entry country cache") - countryCacheService.updateEntryCountriesCache().onSuccess { - Timber.d("Entry countries updated") - }.onFailure { Timber.w("Failed to get entry countries: ${it.message}") } - } - launch { - Timber.d("Updating entry country cache") - countryCacheService.updateWgCountriesCache().onSuccess { - Timber.d("Wg countries updated") - }.onFailure { Timber.w("Failed to get wg countries: ${it.message}") } - } - } - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.CREATED) { - // init data - settingsRepository.init() - - configureSentry() - - val isAnalyticsShown = settingsRepository.isAnalyticsShown() - val theme = settingsRepository.getTheme() - - val intent = Intent(this@SplashActivity, MainActivity::class.java).apply { - putExtra(IS_ANALYTICS_SHOWN_INTENT_KEY, isAnalyticsShown) - putExtra(THEME, theme.name) - } - startActivity(intent) - finish() - } - } - } - - private suspend fun configureSentry() { - if (settingsRepository.isErrorReportingEnabled()) { - SentryAndroid.init(NymVpn.instance) { options -> - options.enableTracing = true - options.enableAllAutoBreadcrumbs(true) - options.isEnableUserInteractionTracing = true - options.isEnableUserInteractionBreadcrumbs = true - options.dsn = BuildConfig.SENTRY_DSN - options.sampleRate = 1.0 - options.tracesSampleRate = 1.0 - options.profilesSampleRate = 1.0 - options.instrumenter = Instrumenter.OTEL - options.addEventProcessor(OpenTelemetryLinkErrorEventProcessor()) - options.environment = - if (BuildConfig.DEBUG) Constants.SENTRY_DEV_ENV else Constants.SENTRY_PROD_ENV - } - } - } - - companion object { - const val IS_ANALYTICS_SHOWN_INTENT_KEY = "is_analytics_shown" - const val THEME = "theme" - } -} diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt index aa66623cfa..4bf03b21dc 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt @@ -117,12 +117,7 @@ fun SettingsScreen(appViewModel: AppViewModel, appUiState: AppUiState, viewModel }, title = { Text(stringResource(R.string.account), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, onClick = { - val url = when (appUiState.settings.environment) { - Tunnel.Environment.MAINNET -> context.getString( - R.string.account_url, - ) - else -> context.getString(R.string.account_url_qa) - } + val url = appUiState.settings.environment.accountUrl.toString() context.openWebUrl(url) }, ), diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/display/DisplayScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/display/DisplayScreen.kt index 6633a47bc0..7b9b3f553d 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/display/DisplayScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/display/DisplayScreen.kt @@ -1,5 +1,6 @@ package net.nymtech.nymvpn.ui.screens.settings.appearance.display +import android.os.Build import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -51,23 +52,29 @@ fun DisplayScreen(appUiState: AppUiState, appViewModel: AppViewModel, viewModel: .padding(top = 24.dp.scaledHeight()) .padding(horizontal = 24.dp.scaledWidth()), ) { - IconSurfaceButton( - title = stringResource(R.string.automatic), - description = stringResource(R.string.device_theme), - onClick = { - viewModel.onThemeChange(Theme.AUTOMATIC) - }, - selected = appUiState.settings.theme == Theme.AUTOMATIC, - ) - IconSurfaceButton( - title = stringResource(R.string.light_theme), - onClick = { viewModel.onThemeChange(Theme.LIGHT_MODE) }, - selected = appUiState.settings.theme == Theme.LIGHT_MODE, - ) - IconSurfaceButton( - title = stringResource(R.string.dark_theme), - onClick = { viewModel.onThemeChange(Theme.DARK_MODE) }, - selected = appUiState.settings.theme == Theme.DARK_MODE, - ) + enumValues().forEach { + val title = when (it) { + Theme.DARK_MODE -> stringResource(R.string.dark_theme) + Theme.LIGHT_MODE -> stringResource(R.string.light_theme) + Theme.AUTOMATIC -> stringResource(R.string.automatic) + Theme.DYNAMIC -> stringResource(R.string.dynamic) + } + val description = when (it) { + Theme.AUTOMATIC -> stringResource(R.string.device_theme) + Theme.DYNAMIC -> stringResource(R.string.system_wallpaper) + else -> null + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && it == Theme.DYNAMIC) { + return@Column + } + IconSurfaceButton( + title = title, + description = description, + onClick = { + viewModel.onThemeChange(it) + }, + selected = appUiState.settings.theme == it, + ) + } } } diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt index 43d9cec58b..e3ac70a45a 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt @@ -56,7 +56,6 @@ import net.nymtech.nymvpn.util.extensions.navigateAndForget import net.nymtech.nymvpn.util.extensions.openWebUrl import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth -import net.nymtech.vpn.backend.Tunnel @OptIn(ExperimentalPermissionsApi::class) @Composable @@ -223,12 +222,7 @@ fun CredentialScreen(appUiState: AppUiState, appViewModel: AppViewModel, viewMod append(" ") pushStringAnnotation( tag = "create", - annotation = when (appUiState.settings.environment) { - Tunnel.Environment.MAINNET -> stringResource( - id = R.string.create_account_link, - ) - else -> stringResource(R.string.create_account_link_qa) - }, + annotation = appUiState.settings.environment.createAccountUrl.toString(), ) withStyle(style = SpanStyle(color = MaterialTheme.colorScheme.primary)) { append(stringResource(id = R.string.create_account)) diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/splash/SplashScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/splash/SplashScreen.kt new file mode 100644 index 0000000000..bef01bbb5b --- /dev/null +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/splash/SplashScreen.kt @@ -0,0 +1,75 @@ +package net.nymtech.nymvpn.ui.screens.splash + +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition +import net.nymtech.nymvpn.ui.Route +import net.nymtech.nymvpn.ui.common.navigation.LocalNavController +import net.nymtech.nymvpn.R +import net.nymtech.nymvpn.ui.AppUiState +import net.nymtech.nymvpn.ui.AppViewModel +import net.nymtech.nymvpn.ui.common.navigation.NavBarState +import net.nymtech.nymvpn.ui.theme.Theme +import net.nymtech.nymvpn.util.extensions.navigateAndForget + +@Composable +fun SplashScreen(appViewModel: AppViewModel, appUiState: AppUiState) { + val navController = LocalNavController.current + + LaunchedEffect(Unit) { + appViewModel.onNavBarStateChange( + NavBarState( + show = false, + ), + ) + } + + Box( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background), + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxSize(), + ) { + val animation = when (appUiState.settings.theme) { + Theme.DARK_MODE -> R.raw.splash_animation_dark + Theme.LIGHT_MODE -> R.raw.splash_animation_light + else -> if (isSystemInDarkTheme()) { + R.raw.splash_animation_dark + } else { + R.raw.splash_animation_light + } + } + val composition = rememberLottieComposition(LottieCompositionSpec.RawRes(animation)) + val logoAnimationState = + animateLottieCompositionAsState(composition = composition.value, speed = 2.0f) + LottieAnimation( + composition = composition.value, + progress = { logoAnimationState.progress }, + ) + if (logoAnimationState.isAtEnd && logoAnimationState.isPlaying) { + val route = if (appUiState.settings.isAnalyticsShown) { + Route.Main() + } else { + Route.Analytics + } + navController.navigateAndForget(route) + } + } + } +} diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt index aa9bd94483..ffd76aa9f8 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt @@ -17,9 +17,10 @@ import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat enum class Theme { + AUTOMATIC, DARK_MODE, + DYNAMIC, LIGHT_MODE, - AUTOMATIC, ; companion object { @@ -58,32 +59,25 @@ private val LightColorScheme = ) @Composable -fun NymVPNTheme( - theme: Theme, - // Dynamic color is available on Android 12+ - // disable for now.. - dynamicColor: Boolean = false, - content: @Composable () -> Unit, -) { +fun NymVPNTheme(theme: Theme, content: @Composable () -> Unit) { val context = LocalContext.current - - val darkTheme = - when (theme) { - Theme.AUTOMATIC -> isSystemInDarkTheme() - Theme.DARK_MODE -> true - Theme.LIGHT_MODE -> false - } + val isDark = isSystemInDarkTheme() val colorScheme = - when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + when (theme) { + Theme.AUTOMATIC -> { + if (isDark) DarkColorScheme else LightColorScheme + } + Theme.DARK_MODE -> DarkColorScheme + Theme.LIGHT_MODE -> LightColorScheme + Theme.DYNAMIC -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } else { + if (isDark) DarkColorScheme else LightColorScheme + } } - - darkTheme -> DarkColorScheme - else -> LightColorScheme } - val view = LocalView.current if (!view.isInEditMode) { SideEffect { @@ -92,7 +86,7 @@ fun NymVPNTheme( window.statusBarColor = Color.Transparent.toArgb() window.navigationBarColor = Color.Transparent.toArgb() WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = - !darkTheme + !isDark } } diff --git a/nym-vpn-android/app/src/main/res/raw/splash_animation_dark.json b/nym-vpn-android/app/src/main/res/raw/splash_animation_dark.json new file mode 100644 index 0000000000..6645b8d255 --- /dev/null +++ b/nym-vpn-android/app/src/main/res/raw/splash_animation_dark.json @@ -0,0 +1 @@ +{"nm":"NVPN screen animation","ddd":0,"h":281,"w":390,"meta":{"g":"LottieFiles Figma v64"},"layers":[{"ty":4,"nm":"Intersect","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,16.5],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,16.5],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[33,16.5],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[33,16.5],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":217},{"s":[33,16.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[184.39,116.52],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[184.39,116.52],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[184.39,116.52],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[184.39,116.52],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":217},{"s":[184.39,116.52],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[45],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[45],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1098,0.1059,0.1216],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.1098,0.1059,0.1216],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.1098,0.1059,0.1216],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.1098,0.1059,0.1216],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Ellipse 27","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[36,36],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[36,36],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[36,36],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[36,36],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":217},{"s":[36,36],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,115.39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,115.39],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[170.6,130.31],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[170.6,130.31],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":217},{"s":[170.6,130.31],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9529,0.4275,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9529,0.4275,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":217},{"s":[0.9529,0.4275,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":0,"nm":"Group 962","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100.5,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100.5,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100.5,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100.5,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":217},{"s":[100.5,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[199.5,219.41],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[199.5,219.41],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[199.5,219.41],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[199.5,219.41],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":217},{"s":[199.5,219.41],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"w":390,"h":281,"refId":"1","ind":3},{"ty":4,"nm":"Ellipse 26","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,51],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,51],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":217},{"s":[51,51],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[390,71.01],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[390,71.01],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[208.79,92.12],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[208.79,92.12],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":217},{"s":[208.79,92.12],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":4},{"ty":4,"nm":"Rectangle 175","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":217},{"s":[109.5,2.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":217},{"s":[198.5,157.91],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]}}],"ind":5},{"ty":0,"nm":"Group 961","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":217},{"s":[42.5,42.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":217},{"s":[197.5,102.91],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]}},"w":390,"h":281,"refId":"4","ind":6}],"v":"5.7.0","fr":60,"op":235,"ip":0,"assets":[{"nm":"[Asset] Group 962","id":"1","layers":[{"ty":0,"nm":"VPN","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[41.71,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[41.71,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[41.71,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[41.71,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":217},{"s":[41.71,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[159.29,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[159.29,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[159.29,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[159.29,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":217},{"s":[159.29,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"w":390,"h":281,"refId":"2","ind":1},{"ty":0,"nm":"Logo","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":217},{"s":[52.76,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":217},{"s":[52.76,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"w":390,"h":281,"refId":"3","ind":2}]},{"nm":"[Asset] VPN","id":"2","layers":[{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":217},{"s":[13.81,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":217},{"s":[13.81,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[10.3,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[10.3,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[10.3,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[10.3,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":217},{"s":[10.3,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[43.07,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[43.07,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[43.07,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[43.07,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":217},{"s":[43.07,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[11.92,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[11.92,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[11.92,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[11.92,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":217},{"s":[11.92,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[71.5,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[71.5,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[71.5,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[71.5,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":217},{"s":[71.5,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":3}]},{"nm":"[Asset] Logo","id":"3","layers":[{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.95,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.95,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.95,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.95,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":217},{"s":[15.95,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":217},{"s":[48.62,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.68,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.68,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.68,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.68,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":217},{"s":[15.68,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":217},{"s":[48.62,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.16,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.16,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.16,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.16,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":217},{"s":[19.16,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":217},{"s":[86.37,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":3},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.01,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.01,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.01,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.01,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":217},{"s":[19.01,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":217},{"s":[86.37,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":217},{"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":4},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":5},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.72,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.72,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.72,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.72,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":217},{"s":[14.72,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":217},{"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":6}]},{"nm":"[Asset] Group 961","id":"4","layers":[{"ty":4,"nm":"Ellipse 32","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":217},{"s":[42.5,42.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":1},{"ty":4,"nm":"Ellipse 31","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[32.83,32.83],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[32.83,32.83],"t":217},{"s":[32.83,32.83],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":2},{"ty":4,"nm":"Ellipse 30","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[24.41,24.41],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[24.41,24.41],"t":217},{"s":[24.41,24.41],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":3},{"ty":4,"nm":"Ellipse 29","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[18.15,18.15],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[18.15,18.15],"t":217},{"s":[18.15,18.15],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":4},{"ty":4,"nm":"Ellipse 28","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.44,11.44],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.44,11.44],"t":217},{"s":[11.44,11.44],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":5}]}]} \ No newline at end of file diff --git a/nym-vpn-android/app/src/main/res/raw/splash_animation_light.json b/nym-vpn-android/app/src/main/res/raw/splash_animation_light.json new file mode 100644 index 0000000000..c4722488f5 --- /dev/null +++ b/nym-vpn-android/app/src/main/res/raw/splash_animation_light.json @@ -0,0 +1 @@ +{"nm":"NVPN screen animation light","ddd":0,"h":281,"w":390,"meta":{"g":"LottieFiles Figma v64"},"layers":[{"ty":4,"nm":"Intersect","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,16.5],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[33,16.5],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[33,16.5],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[33,16.5],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[33,16.5],"t":217},{"s":[33,16.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[184.39,116.52],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[184.39,116.52],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[184.39,116.52],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[184.39,116.52],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[184.39,116.52],"t":217},{"s":[184.39,116.52],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[45],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[45],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-14.66,0],[-5.71,-12.44],[12.56,0],[8.92,7.44]],"o":[[5.71,-12.44],[14.66,0],[-8.92,7.44],[-12.56,0],[0,0]],"v":[[0,21.08],[33,0],[66,21.08],[33,33],[0,21.08]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Ellipse 27","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[36,36],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[36,36],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[36,36],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[36,36],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[36,36],"t":217},{"s":[36,36],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,115.39],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0,115.39],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[170.6,130.31],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[170.6,130.31],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[170.6,130.31],"t":217},{"s":[170.6,130.31],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[19.88,0],[0,19.88],[-19.88,0],[0,-19.88]],"o":[[0,19.88],[-19.88,0],[0,-19.88],[19.88,0],[0,0]],"v":[[72,36],[36,72],[0,36],[36,0],[72,36]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9529,0.4275,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9529,0.4275,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9529,0.4275,0.3059],"t":217},{"s":[0.9529,0.4275,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":0,"nm":"Group 962","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100.5,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100.5,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100.5,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100.5,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100.5,14],"t":217},{"s":[100.5,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[199.5,219.41],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[199.5,219.41],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[199.5,219.41],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[199.5,219.41],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[199.5,219.41],"t":217},{"s":[199.5,219.41],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"w":390,"h":281,"refId":"1","ind":3},{"ty":4,"nm":"Ellipse 26","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[51,51],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,51],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[51,51],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[51,51],"t":217},{"s":[51,51],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[390,71.01],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[390,71.01],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[208.79,92.12],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[208.79,92.12],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[208.79,92.12],"t":217},{"s":[208.79,92.12],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[45],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[45],"t":217},{"s":[45],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[28.17,0],[0,28.17],[-28.17,0],[0,-28.17]],"o":[[0,28.17],[-28.17,0],[0,-28.17],[28.17,0],[0,0]],"v":[[102,51],[51,102],[0,51],[51,0],[102,51]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9529,0.4275,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":4},{"ty":4,"nm":"Rectangle 175","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[109.5,2.5],"t":217},{"s":[109.5,2.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[198.5,157.91],"t":217},{"s":[198.5,157.91],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[219,0],[219,5],[0,5],[0,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":217},{"s":[1,1,1],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]}}],"ind":5},{"ty":0,"nm":"Group 961","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":217},{"s":[42.5,42.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[197.5,102.91],"t":217},{"s":[197.5,102.91],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]}},"w":390,"h":281,"refId":"4","ind":6}],"v":"5.7.0","fr":60,"op":235,"ip":0,"assets":[{"nm":"[Asset] Group 962","id":"1","layers":[{"ty":0,"nm":"VPN","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[41.71,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[41.71,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[41.71,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[41.71,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[41.71,14],"t":217},{"s":[41.71,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[159.29,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[159.29,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[159.29,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[159.29,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[159.29,14],"t":217},{"s":[159.29,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"w":390,"h":281,"refId":"2","ind":1},{"ty":0,"nm":"Logo","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":217},{"s":[52.76,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[52.76,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[52.76,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[52.76,14],"t":217},{"s":[52.76,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"w":390,"h":281,"refId":"3","ind":2}]},{"nm":"[Asset] VPN","id":"2","layers":[{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":217},{"s":[13.81,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[13.81,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[13.81,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[13.81,14],"t":217},{"s":[13.81,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-0.34,-0.27],[-0.17,-0.41],[0,0],[-0.24,-0.78],[-0.21,-0.85],[-0.21,0.77],[-0.25,0.65],[0,0],[-0.35,0.28],[-0.52,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0.55,0],[0.34,0.26],[0,0],[0.25,0.65],[0.24,0.77],[0.17,-0.85],[0.22,-0.78],[0,0],[0.14,-0.36],[0.36,-0.29],[0,0],[0,0]],"v":[[27.62,0],[16.67,28],[10.94,28],[0,0],[5.1,0],[6.43,0.4],[7.19,1.4],[12.48,16.39],[13.21,18.55],[13.88,20.97],[14.46,18.55],[15.18,16.39],[20.42,1.4],[21.15,0.44],[22.48,0],[27.62,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[10.3,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[10.3,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[10.3,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[10.3,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[10.3,14],"t":217},{"s":[10.3,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[43.07,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[43.07,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[43.07,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[43.07,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43.07,14],"t":217},{"s":[43.07,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-0.72,0.81],[0,1.45],[0.19,0.53],[0.39,0.37],[0.59,0.2],[0.8,0],[0,0],[0,0],[0,0]],"o":[[1.65,0],[0.72,-0.81],[0,-0.64],[-0.19,-0.53],[-0.37,-0.38],[-0.57,-0.2],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,13.74],[13.19,12.53],[14.28,9.15],[14,7.4],[13.13,6.05],[11.69,5.17],[9.63,4.86],[6.33,4.86],[6.33,13.74],[9.63,13.74]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[-1.37,-0.47],[-0.89,-0.82],[-0.42,-1.11],[0,-1.29],[0.44,-1.17],[0.9,-0.83],[1.39,-0.47],[1.89,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[1.92,0],[1.39,0.46],[0.9,0.82],[0.42,1.11],[0,1.4],[-0.44,1.17],[-0.9,0.83],[-1.37,0.46],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[9.63,0],[14.58,0.71],[17.99,2.63],[19.97,5.53],[20.61,9.15],[19.95,12.99],[17.95,15.99],[14.52,17.95],[9.63,18.64],[6.33,18.64],[6.33,28],[0,28],[0,0],[9.63,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[11.92,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[11.92,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[11.92,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[11.92,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.92,14],"t":217},{"s":[11.92,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[71.5,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[71.5,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[71.5,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[71.5,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[71.5,14],"t":217},{"s":[71.5,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0.34,0.15],[0.32,0.4],[0,0],[-0.01,-0.47],[0,-0.41],[0,0],[0,0],[0,0],[0,0],[-0.19,-0.03],[-0.15,-0.08],[-0.14,-0.13],[-0.17,-0.22],[0,0],[0.03,0.5],[0,0.45],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.49,0],[-0.32,-0.17],[0,0],[0.05,0.5],[0.02,0.46],[0,0],[0,0],[0,0],[0,0],[0.27,0],[0.19,0.03],[0.15,0.06],[0.14,0.13],[0,0],[-0.06,-0.54],[-0.02,-0.51],[0,0],[0,0],[0,0]],"v":[[23.83,0],[23.83,28],[20.53,28],[19.3,27.77],[18.32,26.92],[5.45,10.22],[5.55,11.68],[5.58,12.99],[5.58,28],[0,28],[0,0],[3.33,0],[4.03,0.04],[4.53,0.19],[4.96,0.48],[5.43,1],[18.42,17.81],[18.29,16.26],[18.25,14.82],[18.25,0],[23.83,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0.9843,0.4314,0.3059],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0.9843,0.4314,0.3059],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":3}]},{"nm":"[Asset] Logo","id":"3","layers":[{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.95,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.95,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.95,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.95,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.95,14],"t":217},{"s":[15.95,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":217},{"s":[48.62,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.82,0],[31.9,0],[31.69,0.34],[19.44,21.29],[19.44,28],[12.46,28],[12.46,21.29],[0.21,0.34],[0,0],[8.08,0],[8.14,0.11],[15.97,13.48],[23.76,0.11],[23.82,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0]],"v":[[23.9,0.18],[15.97,13.78],[8,0.18],[7.99,0.15],[0.27,0.15],[0.34,0.26],[12.61,21.25],[12.61,27.85],[19.29,27.85],[19.29,21.25],[31.56,0.26],[31.63,0.15],[23.91,0.15],[23.9,0.18]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":1},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.68,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[15.68,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.68,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[15.68,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[15.68,13.85],"t":217},{"s":[15.68,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[48.62,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[48.62,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[48.62,14],"t":217},{"s":[48.62,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[23.68,0],[23.64,0],[23.62,0.03],[15.7,13.63],[7.73,0.03],[7.72,0],[7.68,0],[0.14,0],[0,0],[0.07,0.11],[12.34,21.1],[12.34,27.63],[12.34,27.7],[12.41,27.7],[18.94,27.7],[19.01,27.7],[19.01,27.63],[19.01,21.1],[31.29,0.11],[31.36,0],[31.22,0],[23.68,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":2},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.16,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.16,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.16,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.16,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.16,14],"t":217},{"s":[19.16,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":217},{"s":[86.37,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[25.45,0],[38.32,0],[38.32,28],[31.34,28],[31.34,5.05],[25.33,27.83],[25.29,28],[13.03,28],[12.99,27.83],[6.97,5.05],[6.97,28],[0,28],[0,0],[12.89,0],[12.93,0.17],[19.18,23.78],[25.41,0.17],[25.45,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[19.18,24.37],[12.79,0.2],[12.77,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.89],[13.13,27.8],[13.15,27.85],[25.17,27.85],[25.18,27.8],[31.49,3.89],[31.49,27.85],[38.16,27.85],[38.16,0.15],[25.57,0.15],[25.56,0.2],[19.18,24.37]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":3},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.01,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[19.01,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.01,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[19.01,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[19.01,13.85],"t":217},{"s":[19.01,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[86.37,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[86.37,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[86.37,14],"t":217},{"s":[86.37,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":217},{"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[37.94,0],[25.49,0],[25.42,0],[25.41,0.06],[19.03,24.22],[12.63,0.06],[12.62,0],[12.56,0],[0.08,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.08,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.74],[12.98,27.65],[13,27.7],[13.07,27.7],[24.96,27.7],[25.02,27.7],[25.03,27.65],[31.34,3.74],[31.34,27.63],[31.34,27.7],[31.41,27.7],[37.94,27.7],[38.01,27.7],[38.01,27.63],[38.01,0.07],[38.01,0],[37.94,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":4},{"ty":4,"nm":"Vector (Stroke)","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0]],"v":[[22.76,0],[29.74,0],[29.74,28],[17.04,28],[16.99,27.86],[6.97,4.43],[6.97,28],[0,28],[0,0],[12.74,0],[12.79,0.14],[22.76,23.52],[22.76,0]]}],"t":235}]}},{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":217},{"s":[{"c":true,"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],[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],[0,0]],"v":[[22.91,24.26],[12.65,0.19],[12.63,0.15],[0.15,0.15],[0.15,27.85],[6.82,27.85],[6.82,3.7],[17.13,27.81],[17.15,27.85],[29.58,27.85],[29.58,0.15],[22.91,0.15],[22.91,24.26]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":2,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":5},{"ty":4,"nm":"Vector","sr":1,"st":0,"op":236,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.72,13.85],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.72,13.85],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.72,13.85],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.72,13.85],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.72,13.85],"t":217},{"s":[14.72,13.85],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100,100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100,100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[14.87,14],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[14.87,14],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[14.87,14],"t":217},{"s":[14.87,14],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[0],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":217},{"s":[{"c":true,"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"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],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[22.84,0],[22.76,0],[22.76,0.07],[22.76,24.11],[12.49,0.04],[12.48,0],[12.43,0],[6.6,0],[0.07,0],[0,0],[0,0.07],[0,27.63],[0,27.7],[0.07,27.7],[6.6,27.7],[6.67,27.7],[6.67,27.63],[6.67,3.55],[16.98,27.66],[16.99,27.7],[17.05,27.7],[22.84,27.7],[29.36,27.7],[29.43,27.7],[29.43,27.63],[29.43,0.07],[29.43,0],[29.36,0],[22.84,0]]}],"t":235}]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[1,1,1],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[1,1,1],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1,1,1],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.1098,0.1059,0.1216],"t":217},{"s":[0.1098,0.1059,0.1216],"t":235}]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":0},{"o":{"x":0.33,"y":1},"i":{"x":0.68,"y":1},"s":[100],"t":48},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":96},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[100],"t":120},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":121},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":145},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}}],"ind":6}]},{"nm":"[Asset] Group 961","id":"4","layers":[{"ty":4,"nm":"Ellipse 32","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[42.5,42.5],"t":217},{"s":[42.5,42.5],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[23.193882352941177,0],[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177]],"o":[[0,23.193882352941177],[-23.193882352941177,0],[0,-23.193882352941177],[23.193882352941177,0],[0,0]],"v":[[84,42],[42,84],[0,42],[42,0],[84,42]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":1},{"ty":4,"nm":"Ellipse 31","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[32.83,32.83],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[32.83,32.83],"t":217},{"s":[32.83,32.83],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[17.853863606943246,0],[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246]],"o":[[0,17.853863606943246],[-17.853863606943246,0],[0,-17.853863606943246],[17.853863606943246,0],[0,0]],"v":[[64.65993846838906,32.32996923419453],[32.32996923419453,64.65993846838906],[0,32.32996923419453],[32.32996923419453,0],[64.65993846838906,32.32996923419453]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":2},{"ty":4,"nm":"Ellipse 30","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[24.41,24.41],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[24.41,24.41],"t":217},{"s":[24.41,24.41],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[13.203856853539856,0],[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856]],"o":[[0,13.203856853539856],[-13.203856853539856,0],[0,-13.203856853539856],[13.203856853539856,0],[0,0]],"v":[[47.81990293692995,23.909951468464975],[23.909951468464975,47.81990293692995],[0,23.909951468464975],[23.909951468464975,0],[47.81990293692995,23.909951468464975]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":3},{"ty":4,"nm":"Ellipse 29","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[18.15,18.15],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[18.15,18.15],"t":217},{"s":[18.15,18.15],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[9.743955738887982,0],[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982]],"o":[[0,9.743955738887982],[-9.743955738887982,0],[0,-9.743955738887982],[9.743955738887982,0],[0,0]],"v":[[35.2999594133367,17.64997970666835],[17.64997970666835,35.2999594133367],[0,17.64997970666835],[17.64997970666835,0],[35.2999594133367,17.64997970666835]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":4},{"ty":4,"nm":"Ellipse 28","sr":1,"st":0,"op":236,"ip":169,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.44,11.44],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[11.44,11.44],"t":217},{"s":[11.44,11.44],"t":235}]},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100,100],"t":217},{"s":[100,100],"t":235}]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[43,43],"t":217},{"s":[43,43],"t":235}]},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0],"t":217},{"s":[0],"t":235}]},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]}},"ef":[],"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":217},{"s":[{"c":true,"i":[[0,0],[6.043673406416648,0],[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648]],"o":[[0,6.043673406416648],[-6.043673406416648,0],[0,-6.043673406416648],[6.043673406416648,0],[0,0]],"v":[[21.87006500075138,10.939813887564311],[10.939813887564311,21.87006500075138],[0,10.939813887564311],[10.939813887564311,0],[21.87006500075138,10.939813887564311]]}],"t":235}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":1,"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[100],"t":217},{"s":[100],"t":235}]},"w":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[1],"t":217},{"s":[1],"t":235}]},"c":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,0],"t":0},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":169},{"o":{"x":0.65,"y":0},"i":{"x":0.35,"y":0},"s":[0.9843,0.4314,0.3059],"t":217},{"s":[0.9843,0.4314,0.3059],"t":235}]}}],"ind":5}]}]} \ No newline at end of file diff --git a/nym-vpn-android/app/src/main/res/values/strings.xml b/nym-vpn-android/app/src/main/res/values/strings.xml index 6ba4b4ee96..ed185ddbe4 100644 --- a/nym-vpn-android/app/src/main/res/values/strings.xml +++ b/nym-vpn-android/app/src/main/res/values/strings.xml @@ -2,7 +2,6 @@ NymVPN net.nymtech.nymvpn.provider - https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/en/prototype/account/signup Settings Connected Disconnected @@ -184,12 +183,11 @@ Log in Log out New to NymVPN? - https://nymvpn.com/account/create Create an account Account - https://nymvpn.com/account/login - https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/en/prototype/account/signin e.g. smoke artefact velvet skull pop palace tortoise damage rough... Enter your 24-word secret recovery phrase below to log in to your account You can only use the recovery phrase created in NymVPN,
not the Nym Wallet. + Dynamic + System wallpaper theme diff --git a/nym-vpn-android/app/src/main/res/values/themes.xml b/nym-vpn-android/app/src/main/res/values/themes.xml index a599b49697..f4624805b2 100644 --- a/nym-vpn-android/app/src/main/res/values/themes.xml +++ b/nym-vpn-android/app/src/main/res/values/themes.xml @@ -3,15 +3,6 @@ - - diff --git a/nym-vpn-android/gradle/libs.versions.toml b/nym-vpn-android/gradle/libs.versions.toml index fe47e3db49..bc9b90e9e9 100644 --- a/nym-vpn-android/gradle/libs.versions.toml +++ b/nym-vpn-android/gradle/libs.versions.toml @@ -1,7 +1,6 @@ [versions] accompanist = "0.36.0" agp = "8.7.1" -coreSplashscreen = "1.0.1" detektRulesCompose = "1.4.0" ipaddress = "5.5.1" jna = "5.15.0" @@ -11,12 +10,13 @@ coreKtx = "1.13.1" junit = "4.13.2" junitVersion = "1.2.1" espressoCore = "3.6.1" -materialIconsExtended = "1.7.3" -navigationCompose = "2.8.2" +lottieCompose = "6.3.0" +materialIconsExtended = "1.7.4" +navigationCompose = "2.8.3" hiltNavigationCompose = "1.2.0" lifecycle-compose = "2.8.6" -activityCompose = "1.9.2" -composeBom = "2024.09.03" +activityCompose = "1.9.3" +composeBom = "2024.10.00" datastorePreferences = "1.1.1" relinker = "1.4.5" securityCrypto = "1.1.0-alpha06" @@ -35,17 +35,16 @@ moshiKotlinCodegen = "1.15.1" converterMoshi = "2.11.0" zxingAndroidEmbedded = "4.3.0" -gradlePlugins-licensee = "1.11.0" +gradlePlugins-licensee = "1.12.0" gradlePlugins-detekt = "1.23.7" gradlePlugins-gross = "0.4.2" -gradlePlugins-sentry = "4.11.0" +gradlePlugins-sentry = "4.12.0" material = "1.12.0" gradlePlugins-ktlint="12.1.1" gradlePlugins-grgit="5.3.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } -androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" } androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" } androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" } androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "uiautomator" } @@ -73,6 +72,7 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3" #retrofit/moshi converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "converterMoshi" } +lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottieCompose" } moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi" } moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshiKotlin" } moshi-kotlin-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshiKotlinCodegen" } diff --git a/nym-vpn-android/nym-vpn-client/build.gradle.kts b/nym-vpn-android/nym-vpn-client/build.gradle.kts index 8583ec15e3..bbe2487c70 100644 --- a/nym-vpn-android/nym-vpn-client/build.gradle.kts +++ b/nym-vpn-android/nym-vpn-client/build.gradle.kts @@ -12,6 +12,10 @@ android { project.tasks.preBuild.dependsOn(Constants.BUILD_LIB_TASK) + lint { + disable.add("UnsafeOptInUsageError") + } + namespace = "${Constants.NAMESPACE}.${Constants.VPN_LIB_NAME}" compileSdk = Constants.COMPILE_SDK diff --git a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/NymBackend.kt b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/NymBackend.kt index a7757716ef..ab04490511 100644 --- a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/NymBackend.kt +++ b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/NymBackend.kt @@ -3,7 +3,6 @@ package net.nymtech.vpn.backend import android.content.Context import android.content.Intent import android.os.Build -import androidx.lifecycle.lifecycleScope import com.getkeepsafe.relinker.ReLinker import com.getkeepsafe.relinker.ReLinker.LoadListener import kotlinx.coroutines.CompletableDeferred @@ -231,9 +230,6 @@ class NymBackend private constructor(val context: Context) : Backend, TunnelStat override fun onDestroy() { Timber.d("Vpn service destroyed") currentTunnelHandle.getAndSet(-1) - lifecycleScope.launch { - stopVpn() - } vpnService = CompletableDeferred() super.onDestroy() } diff --git a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/Tunnel.kt b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/Tunnel.kt index 0cf4346e01..c89f25fe23 100644 --- a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/Tunnel.kt +++ b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/backend/Tunnel.kt @@ -64,29 +64,45 @@ interface Tunnel { * Enum class to represent all possible environments of a [Tunnel]. */ enum class Environment { + CANARY { + override val nymVpnApiUrl: URL? + get() = null + override val apiUrl: URL + get() = URL("https://canary-api.performance.nymte.ch/api") + override val accountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/") + override val createAccountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/account/login") + }, MAINNET { override val nymVpnApiUrl: URL get() = URL("https://nymvpn.com/api") override val apiUrl: URL get() = URL("https://validator.nymtech.net/api/") + override val accountUrl: URL + get() = URL("https://nymvpn.com/account/login") + override val createAccountUrl: URL + get() = URL("https://nymvpn.com/account/create") }, SANDBOX { override val nymVpnApiUrl: URL? get() = null override val apiUrl: URL get() = URL("https://sandbox-nym-api1.nymtech.net/api") - }, - CANARY { - override val nymVpnApiUrl: URL? - get() = null - override val apiUrl: URL - get() = URL("https://canary-api.performance.nymte.ch/api") + override val accountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/") + override val createAccountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-canary-nyx-network-staging.vercel.app/account/login") }, QA { override val nymVpnApiUrl: URL? get() = null override val apiUrl: URL get() = URL("https://qa-nym-api.qa.nymte.ch/api") + override val accountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-qa-nyx-network-staging.vercel.app/en/account/login") + override val createAccountUrl: URL + get() = URL("https://nym-dot-com-git-deploy-qa-nyx-network-staging.vercel.app/en") }, ; /** @@ -114,5 +130,7 @@ interface Tunnel { abstract val nymVpnApiUrl: URL? abstract val apiUrl: URL + abstract val accountUrl: URL + abstract val createAccountUrl: URL } } diff --git a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/util/Constants.kt b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/util/Constants.kt index 8ae8adadd0..dd9a921d26 100644 --- a/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/util/Constants.kt +++ b/nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn/util/Constants.kt @@ -6,7 +6,7 @@ object Constants { const val NYM_VPN_LIB = "nym_vpn_lib" // Add Rust environment vars for lib - const val DEFAULT_COUNTRY_ISO = "FR" + const val DEFAULT_COUNTRY_ISO = "CH" private const val LOG_LEVEL = "info" diff --git a/nym-vpn-android/nym-vpn-client/src/main/scripts/build-libs.sh b/nym-vpn-android/nym-vpn-client/src/main/scripts/build-libs.sh index 8ffdd7d4ea..9e0827b991 100644 --- a/nym-vpn-android/nym-vpn-client/src/main/scripts/build-libs.sh +++ b/nym-vpn-android/nym-vpn-client/src/main/scripts/build-libs.sh @@ -19,11 +19,6 @@ echo "Building nym-vpn-lib dep" (cd $PWD/../../nym-vpn-core; cargo run --bin uniffi-bindgen generate --library ./target/aarch64-linux-android/release/libnym_vpn_lib.so --language kotlin --out-dir ../nym-vpn-android/nym-vpn-client/src/main/java/net/nymtech/vpn -n) cargo license -j --avoid-dev-deps --current-dir ../../nym-vpn-core/crates/nym-vpn-lib --filter-platform aarch64-linux-android --avoid-build-deps > ./src/main/assets/licenses_rust.json -mv $PWD/src/main/jniLibs/arm64-v8a/libnym_vpn_lib.so $PWD/src/main/jniLibs/arm64-v8a/libnym_vpn_lib.so -#mv $PWD/src/main/jniLibs/armeabi-v7a/libnym_vpn_lib.so $PWD/src/main/jniLibs/armeabi-v7a/libnym_vpn_lib.so -#mv $PWD/src/main/jniLibs/x86/libnym_vpn_lib.so $PWD/src/main/jniLibs/x86/libnym_vpn_lib.so -#mv $PWD/src/main/jniLibs/x86_64/libnym_vpn_lib.so $PWD/src/main/jniLibs/x86_64/libnym_vpn_lib.so - mv $PWD/../../android/app/build/extraJni/arm64-v8a/libwg.so $PWD/src/main/jniLibs/arm64-v8a/ #mv $PWD/src/tools/nym-vpn-client/android/app/build/extraJni/armeabi-v7a/libwg.so $PWD/src/main/jniLibs/armeabi-v7a/ #mv $PWD/src/tools/nym-vpn-client/android/app/build/extraJni/x86/libwg.so $PWD/src/main/jniLibs/x86/ diff --git a/nym-vpn-app/src-tauri/src/commands/daemon.rs b/nym-vpn-app/src-tauri/src/commands/daemon.rs index 83cf525539..c838d5d41e 100644 --- a/nym-vpn-app/src-tauri/src/commands/daemon.rs +++ b/nym-vpn-app/src-tauri/src/commands/daemon.rs @@ -51,9 +51,17 @@ pub async fn daemon_info(grpc_client: State<'_, GrpcClient>) -> Result = Lazy::new(|| Country { name: String::from("Germany"), }); -// When the app receives the countries data, the selected countries -// are checked against the available countries, and if needed changed to -// available ones (logic handled by the frontend) -pub static DEFAULT_ENTRY_COUNTRY: Lazy = Lazy::new(|| Country { - code: String::from("CH"), - name: String::from("Switzerland"), -}); - #[derive(Serialize, Deserialize, Debug, Clone, TS, Eq, PartialEq, Hash)] #[ts(export)] pub struct Country { @@ -29,12 +21,6 @@ impl fmt::Display for Country { } } -impl Default for Country { - fn default() -> Self { - DEFAULT_ENTRY_COUNTRY.clone() - } -} - impl Country { pub fn try_new_from_code(code: &str) -> Option { rust_iso3166::from_alpha2(code).map(|country| Country { diff --git a/nym-vpn-app/src-tauri/src/db.rs b/nym-vpn-app/src-tauri/src/db.rs index 2ccb8dae20..2a0531fce7 100644 --- a/nym-vpn-app/src-tauri/src/db.rs +++ b/nym-vpn-app/src-tauri/src/db.rs @@ -21,29 +21,18 @@ pub type JsonValue = Value; #[allow(dead_code)] #[derive(Deserialize, Serialize, AsRefStr, EnumString, EnumIter, Debug, Clone, Copy, TS)] +#[strum(serialize_all = "snake_case")] #[ts(export)] pub enum Key { - #[strum(serialize = "monitoring")] Monitoring, - #[strum(serialize = "autoconnect")] Autoconnect, - #[strum(serialize = "ui_show_entry_select")] - UiShowEntrySelect, - #[strum(serialize = "ui_theme")] UiTheme, - #[strum(serialize = "ui_root_font_size")] UiRootFontSize, - #[strum(serialize = "ui_language")] UiLanguage, - #[strum(serialize = "vpn_mode")] VpnMode, - #[strum(serialize = "entry_node_location")] EntryNodeLocation, - #[strum(serialize = "exit_node_location")] ExitNodeLocation, - #[strum(serialize = "welcome_screen_seen")] WelcomeScreenSeen, - #[strum(serialize = "desktop_notifications")] DesktopNotifications, } diff --git a/nym-vpn-app/src-tauri/src/grpc/client.rs b/nym-vpn-app/src-tauri/src/grpc/client.rs index f9db93335b..2fcdee5927 100644 --- a/nym-vpn-app/src-tauri/src/grpc/client.rs +++ b/nym-vpn-app/src-tauri/src/grpc/client.rs @@ -192,7 +192,13 @@ impl GrpcClient { let d_info = self.vpnd_info().await?; self.user_agent = GrpcClient::user_agent(pkg, Some(&d_info)); info!("vpnd version: {}", d_info.version); - info!("network env: {}", d_info.network_name); + info!( + "network env: {}", + d_info + .nym_network + .map(|n| n.network_name) + .unwrap_or_else(|| "unknown".to_string()) + ); info!("updated user agent: {:?}", self.user_agent); Ok(()) } diff --git a/nym-vpn-app/src/constants.ts b/nym-vpn-app/src/constants.ts index 88bca3960b..a466ec0add 100644 --- a/nym-vpn-app/src/constants.ts +++ b/nym-vpn-app/src/constants.ts @@ -11,9 +11,12 @@ export const DaemonEvent = 'vpnd-status'; export const StatusUpdateEvent = 'status-update'; // ⚠ keep this value in sync with the one declared in `index.html` export const DefaultRootFontSize = 14; // in px -export const DefaultNodeCountry: Country = { - name: 'France', - code: 'FR', +// NOTE: when fresh country data is get from daemon, the selected countries +// are checked against it and if needed it is automatically switched to +// available ones +export const DefaultCountry: Country = { + name: 'Switzerland', + code: 'CH', }; // TODO disabled Fastest location until the backend is ready export const FastestFeatureEnabled = false; diff --git a/nym-vpn-app/src/contexts/main/provider.tsx b/nym-vpn-app/src/contexts/main/provider.tsx index e7f64de009..46f78c3ee9 100644 --- a/nym-vpn-app/src/contexts/main/provider.tsx +++ b/nym-vpn-app/src/contexts/main/provider.tsx @@ -179,11 +179,11 @@ function MainStateProvider({ children }: Props) { isCountry(selected) && !countries.some((c) => c.code === selected.code) ) { - console.info( - `selected ${hop} country [${selected.name}] not in the list, picking a random one`, - ); const location = countries[Math.floor(Math.random() * countries.length)]; + console.info( + `selected ${hop} country [${selected.code}] not available, switching to [${location.code}]`, + ); try { await kvSet( hop === 'entry' ? 'EntryNodeLocation' : 'ExitNodeLocation', diff --git a/nym-vpn-app/src/dev/setup.ts b/nym-vpn-app/src/dev/setup.ts index 326b66ab54..63f7c4b8d3 100644 --- a/nym-vpn-app/src/dev/setup.ts +++ b/nym-vpn-app/src/dev/setup.ts @@ -98,9 +98,6 @@ export function mockTauriIPC() { case 'WelcomeScreenSeen': res = true; break; - case 'UiShowEntrySelect': - res = true; - break; default: return null; } @@ -131,5 +128,13 @@ export function mockTauriIPC() { }), ); } + + if (cmd === 'env') { + return new Promise((resolve) => + resolve({ + NETWORK_ENV_SELECT: true, + }), + ); + } }) as MockIpcFn); } diff --git a/nym-vpn-app/src/i18n/ar/settings.json b/nym-vpn-app/src/i18n/ar/settings.json index 7a2f61eb9f..e35adbbb7e 100644 --- a/nym-vpn-app/src/i18n/ar/settings.json +++ b/nym-vpn-app/src/i18n/ar/settings.json @@ -24,10 +24,6 @@ "title": "اتصال تلقائي", "desc": "الاتصال التلقائي عند تشغيل التطبيق" }, - "entry-selector": { - "title": "محدد موقع الدخول", - "desc": "قم بتحديد نقطة الدخول يدويًا" - }, "error-monitoring": { "title": "تقارير الأخطاء مجهولة المصدر", "desc": "يُطبق عند إعادة تشغيل التطبيق" diff --git a/nym-vpn-app/src/i18n/de/settings.json b/nym-vpn-app/src/i18n/de/settings.json index 8944a8c971..aed297c831 100644 --- a/nym-vpn-app/src/i18n/de/settings.json +++ b/nym-vpn-app/src/i18n/de/settings.json @@ -8,10 +8,6 @@ "title": "Automatisch verbinden", "desc": "Beim Start der App automatisch verbinden" }, - "entry-selector": { - "title": "Auswahl der Eintrittsregion", - "desc": "Wähle deine Eintrittsregion" - }, "error-monitoring": { "title": "Anonymisierte Fehlerprotokolle", "desc": "aktiviert nach Neustart der App" diff --git a/nym-vpn-app/src/i18n/en/settings.json b/nym-vpn-app/src/i18n/en/settings.json index cdea060e07..833eeb3335 100644 --- a/nym-vpn-app/src/i18n/en/settings.json +++ b/nym-vpn-app/src/i18n/en/settings.json @@ -3,10 +3,6 @@ "title": "Auto-connect", "desc": "Auto connect at app startup" }, - "entry-selector": { - "title": "Entry location selector", - "desc": "Manually select your entry hop" - }, "error-monitoring": { "title": "Anonymous error reports", "desc": "applies on app restart" diff --git a/nym-vpn-app/src/i18n/es/errors.json b/nym-vpn-app/src/i18n/es/errors.json index f34791a81f..aab52e91be 100644 --- a/nym-vpn-app/src/i18n/es/errors.json +++ b/nym-vpn-app/src/i18n/es/errors.json @@ -8,7 +8,8 @@ "internal": "Error interno", "daemon": { "not-connected": "No conectado al demonio", - "internal": "Error interno del demonio" + "internal": "Error interno del demonio", + "invalid-network": "Red inválida" }, "grpc": "Error interno gRPC", "connection": { @@ -75,10 +76,18 @@ "out-of-bandwidth": "Fuera del ancho de banda asignado", "exit-node": { "ping": "Falló el ping del nodo de salida para el tráfico {{protocolo}}", - "routing": "El nodo de salida no está enrutando tráfico {{protocolo}}" + "routing": "El nodo de salida no está enrutando tráfico de {{protocolo}}" }, "entry-node-routing": "El nodo de entrada no enruta el tráfico (¿se ha caído la conexión a Internet?)", "account": { - "invalid-recovery-phrase": "Frase de recuperación inválida" + "invalid-recovery-phrase": "Frase de recuperación inválida", + "storage": "Error de backend de almacenamiento", + "device": { + "not-registered": "El dispositivo no está registrado", + "not-active": "El dispositivo no está activo" + }, + "no-account-stored": "No se almacena ninguna frase de recuperación de cuenta", + "not-active": "La cuenta no está activa", + "no-active-subscription": "La cuenta no tiene una suscripción activa" } } diff --git a/nym-vpn-app/src/i18n/es/glossary.json b/nym-vpn-app/src/i18n/es/glossary.json index dfd034efaf..938e7c62d4 100644 --- a/nym-vpn-app/src/i18n/es/glossary.json +++ b/nym-vpn-app/src/i18n/es/glossary.json @@ -2,5 +2,6 @@ "via": "vía", "left": "quedan", "ok": "Ok", - "selected": "seleccionado" + "selected": "seleccionado", + "account": "cuenta" } diff --git a/nym-vpn-app/src/i18n/es/settings.json b/nym-vpn-app/src/i18n/es/settings.json index d7294cb29b..7b04daead1 100644 --- a/nym-vpn-app/src/i18n/es/settings.json +++ b/nym-vpn-app/src/i18n/es/settings.json @@ -30,10 +30,6 @@ }, "display-theme": "Tema", "login-button": "Iniciar sesión", - "entry-selector": { - "desc": "Seleccione manualmente el salto de entrada", - "title": "Selector de ubicación de entrada" - }, "monitoring-alert": "Debes reiniciar la aplicación para que el cambio surta efecto.", "faq": "FAQ", "quit": "Cerrar NymVPN", diff --git a/nym-vpn-app/src/i18n/fa/add-credential.json b/nym-vpn-app/src/i18n/fa/add-credential.json index 4bd6d1f89a..9d3b4a8022 100644 --- a/nym-vpn-app/src/i18n/fa/add-credential.json +++ b/nym-vpn-app/src/i18n/fa/add-credential.json @@ -1,5 +1,5 @@ { - "welcome": "خوش آمدید!", + "welcome": "به NymVPN خوش آمدید!", "description1": "اعتبارنامه خود را برای شروع وارد کنید", "description2": "اعتبارنامه خود را فعال کنید، سپس QR Code را اسکن کنید. اعتبارنامه ندارید؟ در nymvpn.com عضو شوید و بلافاصله آن را دریافت کنید.", "input-label": "اعتبارنامه", diff --git a/nym-vpn-app/src/i18n/fa/glossary.json b/nym-vpn-app/src/i18n/fa/glossary.json index 736e04e443..56e43b8e6e 100644 --- a/nym-vpn-app/src/i18n/fa/glossary.json +++ b/nym-vpn-app/src/i18n/fa/glossary.json @@ -2,5 +2,6 @@ "via": "توسط", "left": "مانده", "ok": "قبول", - "selected": "انتخاب‌شده" + "selected": "انتخاب‌شده", + "account": "اکانت" } diff --git a/nym-vpn-app/src/i18n/fa/settings.json b/nym-vpn-app/src/i18n/fa/settings.json index 2b2d1ae151..08b8e1abef 100644 --- a/nym-vpn-app/src/i18n/fa/settings.json +++ b/nym-vpn-app/src/i18n/fa/settings.json @@ -25,10 +25,6 @@ "desc": "گزارش‌ها را کپی یا پاک کنید" }, "login-button": "افزودن اعتبارنامه برای اتصال", - "entry-selector": { - "title": "گزینش‌گر موقعیت ورودی", - "desc": "به صورت دستی پرش ورودی خود را انتخاب کنید" - }, "error-monitoring": { "title": "گزارش ناشناس خطا", "desc": "با راه‌اندازی مجدد برنامه اعمال می‌شود" diff --git a/nym-vpn-app/src/i18n/fr/settings.json b/nym-vpn-app/src/i18n/fr/settings.json index ec252ec0e9..c8dc73e8ef 100644 --- a/nym-vpn-app/src/i18n/fr/settings.json +++ b/nym-vpn-app/src/i18n/fr/settings.json @@ -30,10 +30,6 @@ }, "display-theme": "Apparence", "login-button": "Ajoutez un identifiant pour vous connecter", - "entry-selector": { - "title": "Sélecteur d'emplacement d'entrée", - "desc": "Choix manuel du nœud d'entrée" - }, "monitoring-alert": "Redémarrez l'application pour que le changement s'applique.", "faq": "F.A.Q.", "quit": "Quitter NymVPN", diff --git a/nym-vpn-app/src/i18n/hi/add-credential.json b/nym-vpn-app/src/i18n/hi/add-credential.json index e86a4b6988..09b1aa20ba 100644 --- a/nym-vpn-app/src/i18n/hi/add-credential.json +++ b/nym-vpn-app/src/i18n/hi/add-credential.json @@ -5,5 +5,9 @@ "description2": "नया क्रेडेंशियल उत्पन्न करने के लिए, कृपया अल्फा चरण के निमंत्रण ईमेल में दिए गए लिंक का उपयोग करें।", "login-button": "क्रेडेंशियल जोड़ें", "error": "अमान्य क्रेडेंशियल", - "added-notification": "क्रेडेंशियल सफलतापूर्वक दर्ज हो गया है!" + "added-notification": "क्रेडेंशियल सफलतापूर्वक दर्ज हो गया है!", + "create-account": { + "text": "NymVPN में नए हैं?", + "link": "खाता बनाएं" + } } diff --git a/nym-vpn-app/src/i18n/hi/errors.json b/nym-vpn-app/src/i18n/hi/errors.json index 05435cbf7b..bd9c49f441 100644 --- a/nym-vpn-app/src/i18n/hi/errors.json +++ b/nym-vpn-app/src/i18n/hi/errors.json @@ -77,5 +77,8 @@ }, "grpc": "अंदरूनी gRPC त्रुटि", "entry-node-routing": "प्रवेश नोड ट्रैफ़िक को रूट नहीं कर रहा है (क्या इंटरनेट कनेक्शन बंद है?)", - "out-of-bandwidth": "निर्धारित बैंडविड्थ समाप्त" + "out-of-bandwidth": "निर्धारित बैंडविड्थ समाप्त", + "account": { + "invalid-recovery-phrase": "अमान्य रिकवरी फ्रेज़" + } } diff --git a/nym-vpn-app/src/i18n/hi/settings.json b/nym-vpn-app/src/i18n/hi/settings.json index bf67c0a723..057efa2413 100644 --- a/nym-vpn-app/src/i18n/hi/settings.json +++ b/nym-vpn-app/src/i18n/hi/settings.json @@ -33,10 +33,6 @@ "title": "लॉग्स", "desc": "लॉग्स कॉपी करें या मिटाएं" }, - "entry-selector": { - "title": "प्रवेश स्थान चयनकर्ता", - "desc": "प्रवेश स्थान का चयन ख़ुद करें" - }, "info": { "client-version": "क्लाइंट वर्शन", "daemon-version": "Daemon वर्शन", diff --git a/nym-vpn-app/src/i18n/it/settings.json b/nym-vpn-app/src/i18n/it/settings.json index 2a4fd4ba3d..09c6035ffe 100644 --- a/nym-vpn-app/src/i18n/it/settings.json +++ b/nym-vpn-app/src/i18n/it/settings.json @@ -23,9 +23,6 @@ "logs": { "title": "Logs" }, - "entry-selector": { - "title": "Selettore della località d'entrata" - }, "error-monitoring": { "title": "Report degli errori anonimo" } diff --git a/nym-vpn-app/src/i18n/ja/add-credential.json b/nym-vpn-app/src/i18n/ja/add-credential.json index 6698c8c35e..02016f7194 100644 --- a/nym-vpn-app/src/i18n/ja/add-credential.json +++ b/nym-vpn-app/src/i18n/ja/add-credential.json @@ -1,13 +1,14 @@ { - "input-label": "認証情報", + "input-label": "リカバリーフレーズ", "login-button": "認証情報を追加", - "error": "無効な認証情報", - "added-notification": "認証情報が追加されました!", - "welcome": "ようこそ!", - "description2": "認証情報を引き換えて貼り付けるか、QRコードをスキャンしてください。まだ認証情報をお持ちでない場合は nymvpn.com に登録することですぐに取得できます。", - "description1": "認証情報を入力", + "error": "無効なリカバリーフレーズ", + "added-notification": "デバイスがアカウントに正常に追加されました", + "welcome": "NymVPNへようこそ!", + "description2": "NymVPNで作成されたリカバリーフレーズのみ使用でき、Nym Walletのものは使えません。", + "description1": "アカウントにログインするには、NymVPNのリカバリーフレーズ(24語)を入力してください", "create-account": { "text": "NymVPNは初めてですか?", "link": "アカウントの作成" - } + }, + "input-placeholder": "例:smoke artefact velvet skull pop palace tortoise damage rough…" } diff --git a/nym-vpn-app/src/i18n/ja/errors.json b/nym-vpn-app/src/i18n/ja/errors.json index c6c9b7a35e..7d1a591532 100644 --- a/nym-vpn-app/src/i18n/ja/errors.json +++ b/nym-vpn-app/src/i18n/ja/errors.json @@ -75,10 +75,19 @@ }, "daemon": { "not-connected": "デーモンに接続されていません", - "internal": "デーモン内部エラー" + "internal": "デーモン内部エラー", + "invalid-network": "無効なネットワーク" }, "entry-node-routing": "エントリーノードがトラフィックをルーティングしていません(インターネット接続がダウンしている可能性があります)", "account": { - "invalid-recovery-phrase": "無効なリカバリーフレーズ" + "invalid-recovery-phrase": "無効なリカバリーフレーズ", + "not-active": "アカウントはアクティブではありません", + "no-active-subscription": "アカウントにはアクティブなサブスクリプションがありません", + "device": { + "not-active": "デバイスはアクティブではありません", + "not-registered": "デバイスが登録されていません" + }, + "storage": "ストレージバックエンドエラー", + "no-account-stored": "アカウントのリカバリーフレーズが保存されていません" } } diff --git a/nym-vpn-app/src/i18n/ja/glossary.json b/nym-vpn-app/src/i18n/ja/glossary.json index 60e8882f37..71914c882a 100644 --- a/nym-vpn-app/src/i18n/ja/glossary.json +++ b/nym-vpn-app/src/i18n/ja/glossary.json @@ -2,5 +2,6 @@ "via": "経由", "left": "残り時間", "ok": "ok", - "selected": "選択済み" + "selected": "選択済み", + "account": "アカウント" } diff --git a/nym-vpn-app/src/i18n/ja/settings.json b/nym-vpn-app/src/i18n/ja/settings.json index 1bb96df788..e196d752c0 100644 --- a/nym-vpn-app/src/i18n/ja/settings.json +++ b/nym-vpn-app/src/i18n/ja/settings.json @@ -3,10 +3,6 @@ "title": "自動接続", "desc": "アプリ起動時に自動で接続" }, - "entry-selector": { - "title": "エントリーロケーションの選択", - "desc": "エントリーホップを手動で選択" - }, "error-monitoring": { "title": "匿名のエラーレポート", "desc": "アプリ再起動時に適用されます" diff --git a/nym-vpn-app/src/i18n/pt-BR/add-credential.json b/nym-vpn-app/src/i18n/pt-BR/add-credential.json index 17922b0402..103678c3d8 100644 --- a/nym-vpn-app/src/i18n/pt-BR/add-credential.json +++ b/nym-vpn-app/src/i18n/pt-BR/add-credential.json @@ -1,13 +1,14 @@ { - "welcome": "Bem vindo!", - "description1": "Digite sua credencial para começar", - "description2": "Resgate sua credencial e cole ou escaneie o código QR. Não tem uma? Registre-se em nymvpn.com para obtê-la instantaneamente.", - "input-label": "Credencial", - "login-button": "Adicionar credencial", - "error": "Credencial inválida", - "added-notification": "Credencial adicionada com sucesso!", + "welcome": "Bem vindo ao NymVPN!", + "description1": "Digite as 24 palavras de sua frase de recuperação do NymVPN para fazer login em sua conta", + "description2": "Você só pode usar a frase de recuperação criada no NymVPN, e não a Nym Wallet.", + "input-label": "Frase de recuperação", + "login-button": "Entrar", + "error": "Frase de recuperação inválida", + "added-notification": "Dispositivo adicionado com sucesso à sua conta", "create-account": { "link": "Criar uma conta", "text": "Novo no NymVPN?" - } + }, + "input-placeholder": "Por exemplo, smoke artefact velvet skull pop palace tortoise damage rough…" } diff --git a/nym-vpn-app/src/i18n/pt-BR/errors.json b/nym-vpn-app/src/i18n/pt-BR/errors.json index e5ce8f06e5..6d18b97774 100644 --- a/nym-vpn-app/src/i18n/pt-BR/errors.json +++ b/nym-vpn-app/src/i18n/pt-BR/errors.json @@ -3,7 +3,8 @@ "internal": "Erro interno", "daemon": { "not-connected": "Não conectado ao daemon", - "internal": "Erro interno do daemon" + "internal": "Erro interno do daemon", + "invalid-network": "Rede inválida" }, "grpc": "Erro interno do gRPC", "connection": { @@ -79,6 +80,14 @@ "out-of-bandwidth": "Fora da largura de banda alocada", "entry-node-routing": "O nó de entrada não está roteando o tráfego (a conexão com a Internet caiu?)", "account": { - "invalid-recovery-phrase": "Frase de recuperação inválida" + "invalid-recovery-phrase": "Frase de recuperação inválida", + "no-account-stored": "Nenhuma frase de recuperação de conta armazenada", + "not-active": "A conta não está ativa", + "no-active-subscription": "A conta não possui uma assinatura ativa", + "storage": "Erro no backend de armazenamento", + "device": { + "not-registered": "O dispositivo não está registrado", + "not-active": "O dispositivo não está ativo" + } } } diff --git a/nym-vpn-app/src/i18n/pt-BR/glossary.json b/nym-vpn-app/src/i18n/pt-BR/glossary.json index 17b971bad0..ae831b0636 100644 --- a/nym-vpn-app/src/i18n/pt-BR/glossary.json +++ b/nym-vpn-app/src/i18n/pt-BR/glossary.json @@ -2,5 +2,6 @@ "via": "via", "left": "restante", "ok": "ok", - "selected": "selecionado" + "selected": "selecionado", + "account": "conta" } diff --git a/nym-vpn-app/src/i18n/pt-BR/settings.json b/nym-vpn-app/src/i18n/pt-BR/settings.json index 9f26b6e1af..4efcdb1cd0 100644 --- a/nym-vpn-app/src/i18n/pt-BR/settings.json +++ b/nym-vpn-app/src/i18n/pt-BR/settings.json @@ -29,11 +29,7 @@ "emptyData": "Não há dados de licença disponíveis" }, "display-theme": "Modo de visualização", - "login-button": "adicionar credencial para conectar", - "entry-selector": { - "title": "Seletor de local de entrada", - "desc": "Selecione manualmente seu salto de entrada" - }, + "login-button": "Entrar", "monitoring-alert": "Você deve reiniciar o aplicativo para que a alteração tenha efeito.", "faq": "Perguntas frequentes", "quit": "Sair da NymVPN", diff --git a/nym-vpn-app/src/i18n/pt-PT/add-credential.json b/nym-vpn-app/src/i18n/pt-PT/add-credential.json index 5842b72ad0..395ca6cec5 100644 --- a/nym-vpn-app/src/i18n/pt-PT/add-credential.json +++ b/nym-vpn-app/src/i18n/pt-PT/add-credential.json @@ -1,13 +1,14 @@ { - "welcome": "Bem Vindo!", - "description1": "Introduza a sua credencial para começar", - "description2": "Resgate a sua credencial e, em seguida, cole ou digitalize o código QR. Não tem um? Registe-se em nymvpn.com para a obter instantaneamente.", - "input-label": "Credencial", - "login-button": "Adicione credencial", - "error": "Credencial Inválida", - "added-notification": "Credencial adicionada com sucesso!", + "welcome": "Bem-vindo ao NymVPN!", + "description1": "Introduza as 24 palavras da sua frase de recuperação NymVPN para iniciar sessão na sua conta", + "description2": "Só pode utilizar a frase de recuperação criada no NymVPN, não a Nym Wallet.", + "input-label": "Frase de recuperação", + "login-button": "Iniciar sessão", + "error": "Frase de recuperação inválida", + "added-notification": "Dispositivo adicionado com sucesso à sua conta", "create-account": { "text": "Novo no NymVPN?", "link": "Criar uma conta" - } + }, + "input-placeholder": "por exemplo, smoke artefact velvet skull pop palace tortoise damage rough…" } diff --git a/nym-vpn-app/src/i18n/pt-PT/errors.json b/nym-vpn-app/src/i18n/pt-PT/errors.json index 9cd7917f1e..09497a01fd 100644 --- a/nym-vpn-app/src/i18n/pt-PT/errors.json +++ b/nym-vpn-app/src/i18n/pt-PT/errors.json @@ -3,7 +3,8 @@ "internal": "Erro interno", "daemon": { "not-connected": "Não está ligado ao daemon", - "internal": "Erro interno do daemon" + "internal": "Erro interno do daemon", + "invalid-network": "Rede inválida" }, "grpc": "Erro interno do gRPC", "connection": { @@ -79,6 +80,14 @@ "ping": "O ping do nó de saída falhou para o {{protocol}}tráfego" }, "account": { - "invalid-recovery-phrase": "Frase de recuperação inválida" + "invalid-recovery-phrase": "Frase de recuperação inválida", + "no-active-subscription": "A conta não tem uma assinatura ativa", + "device": { + "not-registered": "O dispositivo não está registado", + "not-active": "O dispositivo não está ativo" + }, + "storage": "Erro de backend de armazenamento", + "no-account-stored": "Nenhuma frase de recuperação de conta armazenada", + "not-active": "A conta não está ativa" } } diff --git a/nym-vpn-app/src/i18n/pt-PT/glossary.json b/nym-vpn-app/src/i18n/pt-PT/glossary.json index 9e69096855..370e71bc3b 100644 --- a/nym-vpn-app/src/i18n/pt-PT/glossary.json +++ b/nym-vpn-app/src/i18n/pt-PT/glossary.json @@ -2,5 +2,6 @@ "via": "via", "left": "resta", "ok": "ok", - "selected": "selecionado" + "selected": "selecionado", + "account": "conta" } diff --git a/nym-vpn-app/src/i18n/pt-PT/settings.json b/nym-vpn-app/src/i18n/pt-PT/settings.json index b58a8d181d..f18079b2ac 100644 --- a/nym-vpn-app/src/i18n/pt-PT/settings.json +++ b/nym-vpn-app/src/i18n/pt-PT/settings.json @@ -3,10 +3,6 @@ "title": "Ligação Automática", "desc": "Ligação automática ao iniciar a aplicação" }, - "entry-selector": { - "title": "Seletor de local de entrada", - "desc": "Selecionar manualmente o seu salto de entrada" - }, "feedback": { "title": "Feedback", "github": "Abra uma issue no GitHub", @@ -36,7 +32,7 @@ "title": "Logs", "desc": "Copiar ou apagar registos" }, - "login-button": "Adicionar credencial para ligação", + "login-button": "Iniciar sessão", "notifications": { "title": "Notificações no ambiente de trabalho" }, diff --git a/nym-vpn-app/src/i18n/ru/errors.json b/nym-vpn-app/src/i18n/ru/errors.json index 50fe4eba23..a50d1eca7d 100644 --- a/nym-vpn-app/src/i18n/ru/errors.json +++ b/nym-vpn-app/src/i18n/ru/errors.json @@ -1,7 +1,8 @@ { "daemon": { "not-connected": "Нет подключения к службе", - "internal": "Внутренняя ошибка демона" + "internal": "Внутренняя ошибка демона", + "invalid-network": "Ошибка сети" }, "connection": { "no-valid-credential": "Недействительные учётные данные, добавьте сначала учётные данные", @@ -80,6 +81,13 @@ }, "account": { "invalid-recovery-phrase": "Неверная фраза восстановления", - "storage": "Ошибка серверной части хранилища" + "storage": "Ошибка серверной части хранилища", + "no-account-stored": "Фраза для восстановления аккаунта не сохранена", + "not-active": "Аккаунт не активен", + "device": { + "not-registered": "Устройство не зарегистрировано", + "not-active": "Устройство не активно" + }, + "no-active-subscription": "Аккаунт не имеет активной подписки" } } diff --git a/nym-vpn-app/src/i18n/ru/settings.json b/nym-vpn-app/src/i18n/ru/settings.json index 3933b0c1ba..0749fc84f3 100644 --- a/nym-vpn-app/src/i18n/ru/settings.json +++ b/nym-vpn-app/src/i18n/ru/settings.json @@ -30,10 +30,6 @@ "title": "Анонимные отчёты об ошибке", "desc": "активируется при перезапуске приложения" }, - "entry-selector": { - "title": "Выбор точки входа", - "desc": "Выбрать ступень входа вручную" - }, "monitoring-alert": "Для применения изменений требуется перезапуск приложения.", "faq": "FAQ", "quit": "Выйти из NymVPN", diff --git a/nym-vpn-app/src/i18n/tr/errors.json b/nym-vpn-app/src/i18n/tr/errors.json index d804b93dfd..e328beaeed 100644 --- a/nym-vpn-app/src/i18n/tr/errors.json +++ b/nym-vpn-app/src/i18n/tr/errors.json @@ -1,7 +1,8 @@ { "daemon": { "not-connected": "Daemon'a bağlı değil", - "internal": "Daemon dahili hata" + "internal": "Daemon dahili hata", + "invalid-network": "Geçersiz ağ" }, "connection": { "no-valid-credential": "Geçerli anahtar yok, lütfen önce bir anahtar ekleyin", @@ -80,6 +81,13 @@ "entry-node-routing": "Giriş nodeu trafiği iletmiyor (internet bağlantısı mı kesik?)", "account": { "invalid-recovery-phrase": "Geçersiz kurtarma ifadesi", - "storage": "Depolama arka ucu hatası" + "storage": "Depolama arka ucu hatası", + "device": { + "not-registered": "Cihaz kaydedilmemiş", + "not-active": "Cihaz aktif değil" + }, + "no-active-subscription": "Hesapta aktif bir abonelik yok", + "not-active": "Hesap aktif değil", + "no-account-stored": "Hiçbir hesap kurtarma ifadesi saklanmamış" } } diff --git a/nym-vpn-app/src/i18n/tr/settings.json b/nym-vpn-app/src/i18n/tr/settings.json index 8ff57ecf2e..47ddac58ac 100644 --- a/nym-vpn-app/src/i18n/tr/settings.json +++ b/nym-vpn-app/src/i18n/tr/settings.json @@ -30,10 +30,6 @@ "licenses-js": "Lisanslar (JS)", "emptyData": "Lisans verisi bulunmamaktadır" }, - "entry-selector": { - "title": "Entry konumu seçici", - "desc": "Entry'i hop'unu manuel olarak seçin" - }, "monitoring-alert": "Değişikliğin etkili olması için uygulamayı yeniden başlatmalısınız.", "faq": "SSS", "quit": "NymVPN'yi kapat", diff --git a/nym-vpn-app/src/i18n/uk/errors.json b/nym-vpn-app/src/i18n/uk/errors.json index e41d6f9ddd..c096f48973 100644 --- a/nym-vpn-app/src/i18n/uk/errors.json +++ b/nym-vpn-app/src/i18n/uk/errors.json @@ -69,7 +69,8 @@ }, "daemon": { "not-connected": "Не підключено до системи", - "internal": "Внутрішня помилка Daemon" + "internal": "Внутрішня помилка Daemon", + "invalid-network": "Неправильна мережа" }, "unknown": "Невідома помилка", "out-of-bandwidth": "За межами виділеної смуги пропускання", @@ -79,6 +80,14 @@ "ping": "Не вдалося виконати пінг вихідного вузла для трафіку {{protocol}}" }, "account": { - "invalid-recovery-phrase": "Неправильна фраза відновлення" + "invalid-recovery-phrase": "Неправильна фраза відновлення", + "storage": "Помилка бекенда сховища", + "no-account-stored": "Фраза для відновлення облікового запису не збережена", + "not-active": "Обліковий запис не активний", + "no-active-subscription": "Обліковий запис не має активної підписки", + "device": { + "not-registered": "Пристрій не зареєстровано", + "not-active": "Пристрій не активний" + } } } diff --git a/nym-vpn-app/src/i18n/uk/glossary.json b/nym-vpn-app/src/i18n/uk/glossary.json index 532f2dd2fd..bb18142fac 100644 --- a/nym-vpn-app/src/i18n/uk/glossary.json +++ b/nym-vpn-app/src/i18n/uk/glossary.json @@ -2,5 +2,6 @@ "via": "через", "left": "Час до завершення", "ok": "ок", - "selected": "вибрано" + "selected": "вибрано", + "account": "обліковий запис" } diff --git a/nym-vpn-app/src/i18n/uk/settings.json b/nym-vpn-app/src/i18n/uk/settings.json index 51c116b6f6..e7b8f85dc3 100644 --- a/nym-vpn-app/src/i18n/uk/settings.json +++ b/nym-vpn-app/src/i18n/uk/settings.json @@ -30,10 +30,6 @@ }, "display-theme": "Тема", "login-button": "Увійдіть в систему", - "entry-selector": { - "title": "Вибір країни входу", - "desc": "Ручний вибір країни входу" - }, "monitoring-alert": "Щоб зміни набули чинності, потрібно перезапустити програму.", "faq": "ЧаПи", "quit": "Вийти з NymVPN", diff --git a/nym-vpn-app/src/i18n/zh-Hans/settings.json b/nym-vpn-app/src/i18n/zh-Hans/settings.json index 56493a5d5d..3e5401be24 100644 --- a/nym-vpn-app/src/i18n/zh-Hans/settings.json +++ b/nym-vpn-app/src/i18n/zh-Hans/settings.json @@ -3,10 +3,6 @@ "desc": "应用程序启动时自动连接", "title": "自动连接" }, - "entry-selector": { - "title": "输入位置选择器", - "desc": "手动选择进入跳数" - }, "error-monitoring": { "desc": "适用于应用程序重启", "title": "匿名错误报告" diff --git a/nym-vpn-app/src/screens/home/Home.tsx b/nym-vpn-app/src/screens/home/Home.tsx index 3449e90531..63abb65e33 100644 --- a/nym-vpn-app/src/screens/home/Home.tsx +++ b/nym-vpn-app/src/screens/home/Home.tsx @@ -19,7 +19,6 @@ function Home() { loading, entryNodeLocation, exitNodeLocation, - entrySelector, daemonStatus, account, } = useMainState(); @@ -109,16 +108,12 @@ function Home() { {t('select-node-title')}
- {entrySelector && ( - navigate(routes.entryNodeLocation)} - nodeHop="entry" - disabled={ - daemonStatus === 'NotOk' || state !== 'Disconnected' - } - /> - )} + navigate(routes.entryNodeLocation)} + nodeHop="entry" + disabled={daemonStatus === 'NotOk' || state !== 'Disconnected'} + /> navigate(routes.exitNodeLocation)} diff --git a/nym-vpn-app/src/screens/settings/Settings.tsx b/nym-vpn-app/src/screens/settings/Settings.tsx index b2b0fd3aba..58710cb7e9 100644 --- a/nym-vpn-app/src/screens/settings/Settings.tsx +++ b/nym-vpn-app/src/screens/settings/Settings.tsx @@ -18,7 +18,6 @@ const ThrottleDelay = 10000; // ms function Settings() { const { - entrySelector, autoConnect, monitoring, daemonStatus, @@ -48,12 +47,6 @@ function Settings() { checkAccount(); }, [dispatch]); - const handleEntrySelectorChange = () => { - const isChecked = !entrySelector; - dispatch({ type: 'set-entry-selector', entrySelector: isChecked }); - kvSet('UiShowEntrySelect', isChecked); - }; - const handleAutoConnectChanged = () => { const isChecked = !autoConnect; dispatch({ type: 'set-auto-connect', autoConnect: isChecked }); @@ -130,17 +123,6 @@ function Settings() { /> ), }, - { - title: t('entry-selector.title'), - leadingIcon: 'looks_two', - onClick: handleEntrySelectorChange, - trailing: ( - - ), - }, { title: t('logs.title'), desc: t('logs.desc'), diff --git a/nym-vpn-app/src/state/init.ts b/nym-vpn-app/src/state/init.ts index 10b4261541..1e0666935c 100644 --- a/nym-vpn-app/src/state/init.ts +++ b/nym-vpn-app/src/state/init.ts @@ -2,6 +2,7 @@ import { invoke } from '@tauri-apps/api/core'; import { getVersion } from '@tauri-apps/api/app'; import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { + DefaultCountry, DefaultRootFontSize, DefaultThemeMode, DefaultVpnMode, @@ -113,6 +114,8 @@ export async function initFirstBatch(dispatch: StateDispatch) { location: location === 'Fastest' ? 'Fastest' : location, }, }); + } else { + console.info('no entry country saved, using default', DefaultCountry); } }, }; @@ -129,6 +132,8 @@ export async function initFirstBatch(dispatch: StateDispatch) { location: location === 'Fastest' ? 'Fastest' : location, }, }); + } else { + console.info('no exit country saved, using default', DefaultCountry); } }, }; @@ -205,14 +210,6 @@ export async function initFirstBatch(dispatch: StateDispatch) { }, }; - const getEntrySelectorRq: TauriReq<() => Promise> = { - name: 'getEntrySelector', - request: () => kvGet('UiShowEntrySelect'), - onFulfilled: (enabled) => { - dispatch({ type: 'set-entry-selector', entrySelector: enabled || false }); - }, - }; - const getMonitoringRq: TauriReq<() => Promise> = { name: 'getMonitoring', request: () => kvGet('Monitoring'), @@ -256,7 +253,6 @@ export async function initFirstBatch(dispatch: StateDispatch) { getThemeRq, getStoredAccountRq, getRootFontSizeRq, - getEntrySelectorRq, getMonitoringRq, getDepsRustRq, getDepsJsRq, diff --git a/nym-vpn-app/src/state/reducer.ts b/nym-vpn-app/src/state/reducer.ts index deaa2a97ab..56348c4a9f 100644 --- a/nym-vpn-app/src/state/reducer.ts +++ b/nym-vpn-app/src/state/reducer.ts @@ -1,6 +1,6 @@ import dayjs from 'dayjs'; import { - DefaultNodeCountry, + DefaultCountry, DefaultRootFontSize, DefaultThemeMode, DefaultVpnMode, @@ -27,7 +27,6 @@ export type StateAction = | { type: 'set-daemon-status'; status: DaemonStatus } | { type: 'set-daemon-info'; info: DaemonInfo } | { type: 'set-vpn-mode'; mode: VpnMode } - | { type: 'set-entry-selector'; entrySelector: boolean } | { type: 'set-error'; error: AppError } | { type: 'reset-error' } | { type: 'new-progress-message'; message: ConnectProgressMsg } @@ -75,7 +74,6 @@ export const initialState: AppState = { version: null, loading: false, vpnMode: DefaultVpnMode, - entrySelector: false, uiTheme: 'Light', themeMode: DefaultThemeMode, progressMessages: [], @@ -83,10 +81,10 @@ export const initialState: AppState = { monitoring: false, desktopNotifications: true, // TODO ⚠ these should be set to 'Fastest' when the backend is ready - entryNodeLocation: DefaultNodeCountry, + entryNodeLocation: DefaultCountry, // TODO ⚠ these should be set to 'Fastest' when the backend is ready - exitNodeLocation: DefaultNodeCountry, - fastestNodeLocation: DefaultNodeCountry, + exitNodeLocation: DefaultCountry, + fastestNodeLocation: DefaultCountry, entryCountryList: [], exitCountryList: [], entryCountriesLoading: true, @@ -140,11 +138,6 @@ export function reducer(state: AppState, action: StateAction): AppState { ...state, vpnMode: action.mode, }; - case 'set-entry-selector': - return { - ...state, - entrySelector: action.entrySelector, - }; case 'set-auto-connect': return { ...state, diff --git a/nym-vpn-app/src/state/useTauriEvents.ts b/nym-vpn-app/src/state/useTauriEvents.ts index debf2cb394..2b79c1f5ee 100644 --- a/nym-vpn-app/src/state/useTauriEvents.ts +++ b/nym-vpn-app/src/state/useTauriEvents.ts @@ -38,13 +38,15 @@ export function useTauriEvents(dispatch: StateDispatch) { status: event.payload, }); - // refresh daemon info and network env + // refresh daemon info, network env and account status if (event.payload === 'Ok') { try { const info = await invoke('daemon_info'); dispatch({ type: 'set-daemon-info', info }); + const stored = await invoke('is_account_stored'); + dispatch({ type: 'set-account', stored: stored || false }); } catch (e: unknown) { - console.error('failed to get daemon info', e); + console.error('failed to refresh daemon info', e); } } }); diff --git a/nym-vpn-app/src/types/app-state.ts b/nym-vpn-app/src/types/app-state.ts index b6cc2654ae..ee24933b0e 100644 --- a/nym-vpn-app/src/types/app-state.ts +++ b/nym-vpn-app/src/types/app-state.ts @@ -42,7 +42,6 @@ export type AppState = { // `themeMode` is the current user selected mode, could be `System`, `Dark` or `Light` // if `System` is selected, the app will follow the system theme themeMode: ThemeMode; - entrySelector: boolean; autoConnect: boolean; monitoring: boolean; desktopNotifications: boolean; diff --git a/nym-vpn-app/src/types/tauri-ipc.ts b/nym-vpn-app/src/types/tauri-ipc.ts index 8c00e27ea6..8a8cf656d5 100644 --- a/nym-vpn-app/src/types/tauri-ipc.ts +++ b/nym-vpn-app/src/types/tauri-ipc.ts @@ -17,7 +17,6 @@ export type NetworkEnv = 'mainnet' | 'canary' | 'qa' | 'sandbox'; export type DbKey = | 'Monitoring' | 'Autoconnect' - | 'UiShowEntrySelect' | 'UiTheme' | 'UiRootFontSize' | 'UiLanguage' diff --git a/nym-vpn-apple/NymMixnetTunnel/PacketTunnelProvider+TunnelStatusListener.swift b/nym-vpn-apple/NymMixnetTunnel/PacketTunnelProvider+TunnelStatusListener.swift index 40087abf05..e95a24ff7a 100644 --- a/nym-vpn-apple/NymMixnetTunnel/PacketTunnelProvider+TunnelStatusListener.swift +++ b/nym-vpn-apple/NymMixnetTunnel/PacketTunnelProvider+TunnelStatusListener.swift @@ -23,15 +23,7 @@ extension PacketTunnelProvider: TunnelStatusListener { // todo: implement } - func onExitStatusChange(status: ExitStatus) { - switch status { - case .failure(let error): - logger.error("onExitStatus: \(error.localizedDescription) after: \(connectionDuration())") - scheduleDisconnectNotification() - case .stopped: - logger.info("onExitStatus: Tunnel stopped after: \(connectionDuration())") - } - } + func onExitStatusChange(status: ExitStatus) {} func onTunStatusChange(status: TunStatus) { eventContinuation.yield(.statusUpdate(status)) @@ -53,6 +45,7 @@ private extension PacketTunnelProvider { func updateTunnelState(with tunnelState: TunnelState) { switch tunnelState { case let .error(errorStateReason): + scheduleDisconnectNotification() updateLastError(with: errorStateReason) default: break diff --git a/nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager.swift b/nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager.swift index b7673c0eff..a495394bef 100644 --- a/nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager.swift +++ b/nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager.swift @@ -241,6 +241,13 @@ private extension ConnectionManager { } #endif +// MARK: - Reset VPN profile - +public extension ConnectionManager { + func resetVpnProfile() { + tunnelsManager.resetVpnProfile() + } +} + // MARK: - Connection - #if os(iOS) private extension ConnectionManager { @@ -410,20 +417,11 @@ private extension ConnectionManager { func updateCountries() { Task { @MainActor in - if appSettings.isEntryLocationSelectionOn { - updateCountriesEntryExit() - } else { - updateCountriesExitOnly() - } + updateConnectionHops() } } - func updateCountriesEntryExit() { - entryGateway = connectionStorage.entryGateway() - exitRouter = connectionStorage.exitRouter() - } - - func updateCountriesExitOnly() { + func updateConnectionHops() { entryGateway = connectionStorage.entryGateway() exitRouter = connectionStorage.exitRouter() } diff --git a/nym-vpn-apple/Services/Sources/Services/Tunnels/TunnelsManager.swift b/nym-vpn-apple/Services/Sources/Services/Tunnels/TunnelsManager.swift index e42f183857..6986d5c568 100644 --- a/nym-vpn-apple/Services/Sources/Services/Tunnels/TunnelsManager.swift +++ b/nym-vpn-apple/Services/Sources/Services/Tunnels/TunnelsManager.swift @@ -42,6 +42,28 @@ extension TunnelsManager { throw error } } + + public func resetVpnProfile() { + Task { + do { + var tunnelManagers = try await NETunnelProviderManager.loadAllFromPreferences() + for (index, tunnelManager) in tunnelManagers.enumerated().reversed() { + tunnelManager.removeFromPreferences { [weak self] error in + if let error = error { + self?.logger.error("Failed to remove VPN profile: \(error.localizedDescription)") + } else { + self?.logger.info("VPN profile removed successfully.") + } + } + tunnelManagers.remove(at: index) + } + Keychain.deleteReferences(except: []) + try await loadTunnels() + } catch { + logger.error("Failed to reset VPN profile: \(error.localizedDescription)") + } + } + } } // MARK: - Polling - @@ -62,8 +84,8 @@ private extension TunnelsManager { } func pollTunnelLastError() async { - guard let activeTunnel, - let session = activeTunnel.tunnel.connection as? NETunnelProviderSession + guard let tunnel = tunnels.first(where: { $0.tunnel.isEnabled }), + let session = tunnel.tunnel.connection as? NETunnelProviderSession else { logger.log(level: .error, "Failed to access NETunnelProviderSession from the active tunnel.") return diff --git a/nym-vpn-apple/Settings/Package.swift b/nym-vpn-apple/Settings/Package.swift index b5464b15ee..bece99aea9 100644 --- a/nym-vpn-apple/Settings/Package.swift +++ b/nym-vpn-apple/Settings/Package.swift @@ -31,6 +31,7 @@ let package = Package( .product(name: "AppSettings", package: "Services"), .product(name: "AppVersionProvider", package: "ServicesMutual"), .product(name: "Constants", package: "Services"), + .product(name: "ConnectionManager", package: "Services"), .product(name: "CredentialsManager", package: "Services"), .product(name: "Device", package: "Services"), .product(name: "ExternalLinkManager", package: "Services"), diff --git a/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialog.swift b/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialog.swift new file mode 100644 index 0000000000..830afcd73a --- /dev/null +++ b/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialog.swift @@ -0,0 +1,95 @@ +import SwiftUI +import Theme +import UIComponents + +struct ResetVPNProfileDialog: View { + @ObservedObject private var viewModel: ResetVPNProfileDialogViewModel + + init(viewModel: ResetVPNProfileDialogViewModel) { + self.viewModel = viewModel + } + + var body: some View { + ZStack { + Rectangle() + .foregroundColor(.black) + .opacity(0.3) + .background(Color.clear) + .contentShape(Rectangle()) + + HStack { + Spacer() + .frame(width: 40) + + VStack { + Spacer() + .frame(height: 16) + title() + subtitle() + HStack { + Spacer() + yesButton() + + Spacer() + .frame(width: 16) + + noButton() + Spacer() + } + .padding(24) + } + .background(NymColor.modeInfoViewBackground) + .cornerRadius(16) + + Spacer() + .frame(width: 40) + } + } + .edgesIgnoringSafeArea(.all) + } +} + +private extension ResetVPNProfileDialog { + @ViewBuilder + func title() -> some View { + Text(viewModel.resetVpnProfileTitle) + .textStyle(NymTextStyle.Label.Huge.bold) + .foregroundStyle(NymColor.sysOnSurface) + .multilineTextAlignment(.center) + + Spacer() + .frame(height: 16) + } + + @ViewBuilder + func subtitle() -> some View { + Text(viewModel.resetVpnProfileSubtitle) + .foregroundStyle(NymColor.modeInfoViewDescription) + .textStyle(.Body.Medium.regular) + .multilineTextAlignment(.center) + .padding(EdgeInsets(top: 0, leading: 24, bottom: 0, trailing: 24)) + } + + @ViewBuilder + func yesButton() -> some View { + GenericButton(title: viewModel.yesLocalizedString) + .onTapGesture { +#if os(iOS) + viewModel.impactGenerator.success() +#endif + viewModel.action() + viewModel.isDisplayed = false + } + } + + @ViewBuilder + func noButton() -> some View { + GenericButton(title: viewModel.noLocalizedString, borderOnly: true) + .onTapGesture { +#if os(iOS) + viewModel.impactGenerator.impact() +#endif + viewModel.isDisplayed = false + } + } +} diff --git a/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialogViewModel.swift b/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialogViewModel.swift new file mode 100644 index 0000000000..34b6f069b0 --- /dev/null +++ b/nym-vpn-apple/Settings/Sources/Settings/Support/ResetVPNProfileDialogViewModel.swift @@ -0,0 +1,36 @@ +import SwiftUI +#if os(iOS) +import ImpactGenerator +#endif + +final class ResetVPNProfileDialogViewModel: ObservableObject { +#if os(iOS) + let impactGenerator: ImpactGenerator +#endif + let resetVpnProfileTitle = "settings.resetVpnProfileTitle".localizedString + let resetVpnProfileSubtitle = "settings.resetVpnProfileSubtitle".localizedString + let yesLocalizedString = "logs.yes".localizedString + let noLocalizedString = "logs.no".localizedString + + let action: () -> Void + + @Binding var isDisplayed: Bool + +#if os(iOS) + init( + isDisplayed: Binding, + impactGenerator: ImpactGenerator = ImpactGenerator.shared, + action: @escaping () -> Void + ) { + _isDisplayed = isDisplayed + self.impactGenerator = impactGenerator + self.action = action + } +#endif +#if os(macOS) + init(isDisplayed: Binding, action: @escaping () -> Void) { + _isDisplayed = isDisplayed + self.action = action + } +#endif +} diff --git a/nym-vpn-apple/Settings/Sources/Settings/Support/SupportView.swift b/nym-vpn-apple/Settings/Sources/Settings/Support/SupportView.swift index 1d9add9a5a..918c298cc5 100644 --- a/nym-vpn-apple/Settings/Sources/Settings/Support/SupportView.swift +++ b/nym-vpn-apple/Settings/Sources/Settings/Support/SupportView.swift @@ -5,10 +5,10 @@ import Theme import UIComponents struct SupportView: View { - @State private var viewModel: SupportViewModel + @StateObject private var viewModel: SupportViewModel init(viewModel: SupportViewModel) { - _viewModel = State(initialValue: viewModel) + _viewModel = StateObject(wrappedValue: viewModel) } var body: some View { @@ -23,6 +23,18 @@ struct SupportView: View { .navigationBarBackButtonHidden(true) .frame(maxWidth: .infinity, maxHeight: .infinity) .ignoresSafeArea(edges: [.bottom]) + .overlay { + if viewModel.isResetVPNProfileDisplayed { + ResetVPNProfileDialog( + viewModel: ResetVPNProfileDialogViewModel( + isDisplayed: $viewModel.isResetVPNProfileDisplayed, + action: { + viewModel.resetVPNProfile() + } + ) + ) + } + } .background { NymColor.background .ignoresSafeArea() diff --git a/nym-vpn-apple/Settings/Sources/Settings/Support/SupportViewModel.swift b/nym-vpn-apple/Settings/Sources/Settings/Support/SupportViewModel.swift index baff3cdc0a..ddec508a92 100644 --- a/nym-vpn-apple/Settings/Sources/Settings/Support/SupportViewModel.swift +++ b/nym-vpn-apple/Settings/Sources/Settings/Support/SupportViewModel.swift @@ -1,33 +1,53 @@ import SwiftUI import Constants +import ConnectionManager import ExternalLinkManager import UIComponents -struct SupportViewModel { +final class SupportViewModel: ObservableObject { private let externalLinkManager: ExternalLinkManager private let faqLink = Constants.supportURL.rawValue private let emailLink = Constants.emailLink.rawValue private let matrixLink = "https://matrix.to/#/%23NymVPN:nymtech.chat" private let discordLink = Constants.discordLink.rawValue + private let connectionManager: ConnectionManager let title = "support".localizedString @Binding var path: NavigationPath + @Published var isResetVPNProfileDisplayed = false + var sections: [SettingsListItemViewModel] { - [ + var newSections = [ faqSectionViewModel(), emailSectionViewModel(), matrixSectionViewModel(), discordSectionViewModel() ] +#if os(iOS) + newSections.append(resetVPNProfileSectionViewModel()) +#endif + return newSections } - init(path: Binding, externalLinkManager: ExternalLinkManager = ExternalLinkManager.shared) { + init( + path: Binding, + connectionManager: ConnectionManager = ConnectionManager.shared, + externalLinkManager: ExternalLinkManager = ExternalLinkManager.shared + ) { _path = path + self.connectionManager = connectionManager self.externalLinkManager = externalLinkManager } } +// MARK: - Actions - +extension SupportViewModel { + func resetVPNProfile() { + connectionManager.resetVpnProfile() + } +} + // MARK: - Navigation - extension SupportViewModel { func navigateBack() { @@ -37,6 +57,10 @@ extension SupportViewModel { func openExternalURL(urlString: String?) { try? externalLinkManager.openExternalURL(urlString: urlString) } + + func displayResetVPNProfileDialog() { + isResetVPNProfileDisplayed = true + } } // MARK: - Sections - @@ -48,8 +72,8 @@ private extension SupportViewModel { title: "checkFAQ".localizedString, imageName: "faq", position: SettingsListItemPosition(isFirst: true, isLast: true), - action: { - openExternalURL(urlString: faqLink) + action: { [weak self] in + self?.openExternalURL(urlString: self?.faqLink) } ) } @@ -60,8 +84,8 @@ private extension SupportViewModel { title: "sendEmail".localizedString, imageName: "email", position: SettingsListItemPosition(isFirst: true, isLast: true), - action: { - openExternalURL(urlString: emailLink) + action: { [weak self] in + self?.openExternalURL(urlString: self?.emailLink) } ) } @@ -72,8 +96,8 @@ private extension SupportViewModel { title: "joinMatrix".localizedString, imageName: "matrix", position: SettingsListItemPosition(isFirst: true, isLast: true), - action: { - openExternalURL(urlString: matrixLink) + action: { [weak self] in + self?.openExternalURL(urlString: self?.matrixLink) } ) } @@ -84,8 +108,19 @@ private extension SupportViewModel { title: "joinDiscord".localizedString, imageName: "discord", position: SettingsListItemPosition(isFirst: true, isLast: true), - action: { - openExternalURL(urlString: discordLink) + action: { [weak self] in + self?.openExternalURL(urlString: self?.discordLink) + } + ) + } + + func resetVPNProfileSectionViewModel() -> SettingsListItemViewModel { + SettingsListItemViewModel( + accessory: .empty, + title: "settings.support.resetVpnProfile".localizedString, + position: SettingsListItemPosition(isFirst: true, isLast: true), + action: { [weak self] in + self?.displayResetVPNProfileDialog() } ) } diff --git a/nym-vpn-apple/Theme/Sources/Theme/Resources/Localizable.xcstrings b/nym-vpn-apple/Theme/Sources/Theme/Resources/Localizable.xcstrings index 14190661e4..629ba3adac 100644 --- a/nym-vpn-apple/Theme/Sources/Theme/Resources/Localizable.xcstrings +++ b/nym-vpn-apple/Theme/Sources/Theme/Resources/Localizable.xcstrings @@ -1233,6 +1233,39 @@ } } }, + "settings.resetVpnProfileSubtitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "NymVPN profile will be deleted from your device.\n\nIf connected: deleting VPN profile will disconnect you from VPN." + } + } + } + }, + "settings.resetVpnProfileTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset VPN profile?" + } + } + } + }, + "settings.support.resetVpnProfile" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset VPN profile" + } + } + } + }, "stop" : { "extractionState" : "manual", "localizations" : { diff --git a/nym-vpn-apple/UIComponents/Sources/UIComponents/Buttons/HopButton/HopButtonViewModel.swift b/nym-vpn-apple/UIComponents/Sources/UIComponents/Buttons/HopButton/HopButtonViewModel.swift index 0000e28ebb..ad2953be41 100644 --- a/nym-vpn-apple/UIComponents/Sources/UIComponents/Buttons/HopButton/HopButtonViewModel.swift +++ b/nym-vpn-apple/UIComponents/Sources/UIComponents/Buttons/HopButton/HopButtonViewModel.swift @@ -42,6 +42,12 @@ private extension HopButtonViewModel { self?.updateData() } .store(in: &cancellables) + + connectionManager.$connectionType.sink { [weak self] _ in + guard self?.hopType == .exit else { return } + self?.updateData() + } + .store(in: &cancellables) } } diff --git a/nym-vpn-core/Cargo.lock b/nym-vpn-core/Cargo.lock index 457865691f..19e50da430 100644 --- a/nym-vpn-core/Cargo.lock +++ b/nym-vpn-core/Cargo.lock @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" [[package]] name = "arrayref" @@ -220,7 +220,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -257,7 +257,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -268,7 +268,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -442,7 +442,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -463,9 +463,9 @@ dependencies = [ [[package]] name = "bip39" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ "bitcoin_hashes", "rand 0.8.5", @@ -475,11 +475,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + [[package]] name = "bitcoin_hashes" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] [[package]] name = "bitflags" @@ -697,7 +707,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.82", "tempfile", "toml 0.8.19", ] @@ -825,9 +835,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -835,9 +845,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -854,7 +864,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1176,7 +1186,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1566,7 +1576,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1754,9 +1764,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1769,9 +1779,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1779,15 +1789,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1807,38 +1817,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1906,7 +1916,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -2086,6 +2096,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + [[package]] name = "hickory-proto" version = "0.24.1" @@ -2600,9 +2616,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2638,9 +2654,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libdbus-sys" @@ -3552,7 +3568,7 @@ dependencies = [ "triggered", "which", "windows-sys 0.52.0", - "winreg 0.51.0", + "winreg 0.52.0", ] [[package]] @@ -4524,7 +4540,9 @@ dependencies = [ "nym-task", "nym-topology", "nym-validator-client", + "nym-vpn-account-controller", "nym-vpn-api-client", + "nym-vpn-network-config", "nym-vpn-store", "nym-wg-gateway-client", "nym-wg-go", @@ -4550,6 +4568,21 @@ dependencies = [ "vergen", ] +[[package]] +name = "nym-vpn-network-config" +version = "1.0.0-dev" +dependencies = [ + "anyhow", + "nym-config", + "reqwest 0.11.27", + "serde", + "serde_json", + "tokio", + "tokio-util", + "tracing", + "url", +] + [[package]] name = "nym-vpn-proto" version = "1.0.0-dev" @@ -4620,6 +4653,7 @@ dependencies = [ "nym-vpn-account-controller", "nym-vpn-api-client", "nym-vpn-lib", + "nym-vpn-network-config", "nym-vpn-proto", "nym-vpn-store", "parity-tokio-ipc", @@ -4911,7 +4945,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -4952,7 +4986,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5018,7 +5052,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5097,7 +5131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5143,7 +5177,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5197,7 +5231,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.82", "tempfile", ] @@ -5211,7 +5245,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5600,7 +5634,7 @@ dependencies = [ "rust2go-cli", "rust2go-convert", "rust2go-macro", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5623,7 +5657,7 @@ checksum = "c501dad4b73f3fa62258bed2623cb695f69686a8c304d6b90f807f9b19772fb6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5641,7 +5675,7 @@ dependencies = [ "proc-macro2", "quote", "rust2go-common", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5814,7 +5848,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5840,7 +5874,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5902,9 +5936,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -5929,13 +5963,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -5946,14 +5980,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -5969,7 +6003,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -6432,7 +6466,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -6475,9 +6509,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -6691,22 +6725,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -6804,7 +6838,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -6963,7 +6997,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -7072,7 +7106,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -7343,7 +7377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -7374,7 +7408,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.77", + "syn 2.0.82", "toml 0.5.11", "uniffi_meta", ] @@ -7490,7 +7524,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -7575,9 +7609,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -7586,24 +7620,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -7613,9 +7647,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7623,22 +7657,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-utils" @@ -7672,9 +7706,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -7715,14 +7749,14 @@ dependencies = [ [[package]] name = "which" -version = "4.4.2" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "once_cell", "rustix", + "winsafe", ] [[package]] @@ -7830,7 +7864,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -7841,7 +7875,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -8033,23 +8067,19 @@ dependencies = [ [[package]] name = "winreg" -version = "0.51.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] [[package]] -name = "winreg" -version = "0.52.0" +name = "winsafe" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wintun" @@ -8094,7 +8124,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -8114,5 +8144,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] diff --git a/nym-vpn-core/Cargo.toml b/nym-vpn-core/Cargo.toml index 936893c58e..28517941ad 100644 --- a/nym-vpn-core/Cargo.toml +++ b/nym-vpn-core/Cargo.toml @@ -15,6 +15,7 @@ members = [ "crates/nym-vpn-api-client", "crates/nym-vpn-cli", "crates/nym-vpn-lib", + "crates/nym-vpn-network-config", "crates/nym-vpn-proto", "crates/nym-vpn-store", "crates/nym-vpnc", @@ -59,13 +60,13 @@ edition = "2021" license = "GPL-3.0-only" [workspace.dependencies] -anyhow = "1.0.89" +anyhow = "1.0.91" async-trait = "0.1.83" backon = "1.2" base64 = "0.22" base64-url = "3.0.0" bincode = "1.3.3" -bip39 = "2.0" +bip39 = "2.1" bs58 = "0.5.1" bytes = "1.7" chrono = "0.4.38" @@ -73,7 +74,7 @@ clap = "4.5" dbus = "0.9" dirs = "5.0.1" duct = "0.13" -futures = "0.3.30" +futures = "0.3.31" hex = "0.4" hickory-resolver = "0.24.1" http = "0.2.12" # version compatible with tonic @@ -104,7 +105,7 @@ sysinfo = "0.31" system-configuration = "0.6" tap = "1.0.1" tempfile = "3.13" -thiserror = "1.0.64" +thiserror = "1.0.65" time = "0.3.36" tokio = { version = "1.39" } tokio-stream = "0.1.15" diff --git a/nym-vpn-core/crates/nym-dns/Cargo.toml b/nym-vpn-core/crates/nym-dns/Cargo.toml index 1f7a48cfc9..41765941e9 100644 --- a/nym-vpn-core/crates/nym-dns/Cargo.toml +++ b/nym-vpn-core/crates/nym-dns/Cargo.toml @@ -28,14 +28,14 @@ system-configuration.workspace = true duct.workspace = true [target.'cfg(target_os = "linux")'.dependencies] -which = { version = "4.0", default-features = false } +which = { version = "6.0", default-features = false } inotify = "0.10" resolv-conf = "0.7" duct.workspace = true [target.'cfg(windows)'.dependencies] once_cell = "1.16" -winreg = { version = "0.51", features = ["transactions"] } +winreg = { version = "0.52", features = ["transactions"] } nym-windows = { path = "../nym-windows" } nym-common = { path = "../nym-common" } diff --git a/nym-vpn-core/crates/nym-gateway-directory/src/gateway_client.rs b/nym-vpn-core/crates/nym-gateway-directory/src/gateway_client.rs index 97955649bc..93835dee25 100644 --- a/nym-vpn-core/crates/nym-gateway-directory/src/gateway_client.rs +++ b/nym-vpn-core/crates/nym-gateway-directory/src/gateway_client.rs @@ -151,7 +151,7 @@ impl GatewayClient { } async fn lookup_described_gateways(&self) -> Result> { - info!("Fetching described gateways from nym-api..."); + info!("Fetching all described nodes from nym-api..."); self.api_client .get_all_described_nodes() .await @@ -159,7 +159,7 @@ impl GatewayClient { } async fn lookup_skimmed_gateways(&self) -> Result> { - info!("Fetching skimmed gateways from nym-api..."); + info!("Fetching skimmed entry assigned nodes from nym-api..."); self.api_client .get_all_basic_entry_assigned_nodes(None) .await @@ -303,6 +303,7 @@ fn append_performance( gateways: &mut [Gateway], basic_gw: Vec, ) { + info!("Appending mixnet_performance to gateways"); for gateway in gateways.iter_mut() { if let Some(basic_gw) = basic_gw .iter() @@ -310,8 +311,8 @@ fn append_performance( { gateway.mixnet_performance = Some(basic_gw.performance); } else { - error!( - "Failed to find skimmed node for gateway with identity {}", + tracing::warn!( + "Failed to append mixnet_performance, node {} not found among the skimmed nodes", gateway.identity() ); } @@ -324,6 +325,10 @@ fn filter_on_mixnet_min_performance( ) { if let Some(min_performance) = min_gateway_performance { if let Some(mixnet_min_performance) = min_performance.mixnet_min_performance { + tracing::info!( + "Filtering gateways based on mixnet_min_performance: {:?}", + min_performance + ); gateways.retain(|gateway| { gateway.mixnet_performance.unwrap_or_default() >= mixnet_min_performance }); diff --git a/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.mod b/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.mod index 5d338293f8..c72aecd60d 100644 --- a/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.mod +++ b/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.1 require ( github.com/amnezia-vpn/amneziawg-go v0.2.12 - golang.org/x/net v0.21.0 + golang.org/x/net v0.23.0 ) require ( diff --git a/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.sum b/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.sum index 42f90fd40d..3bfc3cb95d 100644 --- a/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.sum +++ b/nym-vpn-core/crates/nym-gateway-probe/netstack_ping/go.sum @@ -6,8 +6,8 @@ github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= diff --git a/nym-vpn-core/crates/nym-gateway-probe/src/lib.rs b/nym-vpn-core/crates/nym-gateway-probe/src/lib.rs index b64985a351..7910f925de 100644 --- a/nym-vpn-core/crates/nym-gateway-probe/src/lib.rs +++ b/nym-vpn-core/crates/nym-gateway-probe/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, sync::Arc, diff --git a/nym-vpn-core/crates/nym-gateway-probe/src/main.rs b/nym-vpn-core/crates/nym-gateway-probe/src/main.rs index 71b7d4821d..fcfb80ef15 100644 --- a/nym-vpn-core/crates/nym-gateway-probe/src/main.rs +++ b/nym-vpn-core/crates/nym-gateway-probe/src/main.rs @@ -1,35 +1,13 @@ -use std::path::PathBuf; +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only -use anyhow::anyhow; -use clap::Parser; -use nym_config::defaults::setup_env; -use nym_gateway_directory::EntryPoint; -use nym_gateway_probe::ProbeResult; -use tracing::*; - -#[derive(Parser)] -#[clap(author, version, about)] -struct CliArgs { - /// Path pointing to an env file describing the network. - #[arg(short, long)] - config_env_file: Option, - - /// The specific gateway specified by ID. - #[arg(long, short)] - gateway: Option, - - /// Disable logging during probe - #[arg(long, short)] - no_log: bool, - - /// Arguments to be appended to the wireguard config enabling amnezia-wg configuration - #[arg(long, short)] - amnezia_args: Option, -} +#[cfg(unix)] +mod run; +#[cfg(unix)] #[tokio::main] async fn main() -> anyhow::Result<()> { - match run().await { + match run::run().await { Ok(ref result) => { let json = serde_json::to_string_pretty(result)?; println!("{}", json); @@ -42,49 +20,9 @@ async fn main() -> anyhow::Result<()> { Ok(()) } -fn setup_logging() { - let filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) - .from_env() - .unwrap() - .add_directive("hyper::proto=info".parse().unwrap()) - .add_directive("netlink_proto=info".parse().unwrap()); - - tracing_subscriber::fmt() - .with_env_filter(filter) - .compact() - .init(); -} - -async fn run() -> anyhow::Result { - let args = CliArgs::parse(); - if !args.no_log { - setup_logging(); - } - debug!("{:?}", nym_bin_common::bin_info_local_vergen!()); - setup_env(args.config_env_file.as_ref()); - - let gateway = if let Some(gateway) = args.gateway { - EntryPoint::from_base58_string(&gateway)? - } else { - fetch_random_gateway_with_ipr().await? - }; - - let mut trial = nym_gateway_probe::Probe::new(gateway); - if let Some(awg_args) = args.amnezia_args { - trial.with_amnezia(&awg_args); - } - trial.probe().await -} - -async fn fetch_random_gateway_with_ipr() -> anyhow::Result { - // We're fetching gateways with IPR, since they are more interesting to ping, but we can probe - // gateways without an IPR as well - let gateways = nym_gateway_probe::fetch_gateways_with_ipr().await?; - let gateway = gateways - .random_gateway() - .ok_or(anyhow!("No gateways returned by nym-api"))?; - Ok(EntryPoint::Gateway { - identity: *gateway.identity(), - }) +#[cfg(not(unix))] +#[tokio::main] +async fn main() -> anyhow::Result<()> { + eprintln!("This tool is only supported on Unix systems"); + std::process::exit(1) } diff --git a/nym-vpn-core/crates/nym-gateway-probe/src/run.rs b/nym-vpn-core/crates/nym-gateway-probe/src/run.rs new file mode 100644 index 0000000000..123b0d8ae8 --- /dev/null +++ b/nym-vpn-core/crates/nym-gateway-probe/src/run.rs @@ -0,0 +1,79 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use std::path::PathBuf; + +use anyhow::anyhow; +use clap::Parser; +use nym_config::defaults::setup_env; +use nym_gateway_directory::EntryPoint; +use nym_gateway_probe::ProbeResult; +use tracing::*; + +#[derive(Parser)] +#[clap(author, version, about)] +struct CliArgs { + /// Path pointing to an env file describing the network. + #[arg(short, long)] + config_env_file: Option, + + /// The specific gateway specified by ID. + #[arg(long, short)] + gateway: Option, + + /// Disable logging during probe + #[arg(long, short)] + no_log: bool, + + /// Arguments to be appended to the wireguard config enabling amnezia-wg configuration + #[arg(long, short)] + amnezia_args: Option, +} + +fn setup_logging() { + let filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env() + .unwrap() + .add_directive("hyper::proto=info".parse().unwrap()) + .add_directive("netlink_proto=info".parse().unwrap()); + + tracing_subscriber::fmt() + .with_env_filter(filter) + .compact() + .init(); +} + +pub(crate) async fn run() -> anyhow::Result { + let args = CliArgs::parse(); + if !args.no_log { + setup_logging(); + } + debug!("{:?}", nym_bin_common::bin_info_local_vergen!()); + setup_env(args.config_env_file.as_ref()); + + let gateway = if let Some(gateway) = args.gateway { + EntryPoint::from_base58_string(&gateway)? + } else { + fetch_random_gateway_with_ipr().await? + }; + + let mut trial = nym_gateway_probe::Probe::new(gateway); + if let Some(awg_args) = args.amnezia_args { + trial.with_amnezia(&awg_args); + } + trial.probe().await +} + +async fn fetch_random_gateway_with_ipr() -> anyhow::Result { + // We're fetching gateways with IPR, since they are more interesting to ping, but we can probe + // gateways without an IPR as well + tracing::info!("Selecting random gateway with IPR enabled"); + let gateways = nym_gateway_probe::fetch_gateways_with_ipr().await?; + let gateway = gateways + .random_gateway() + .ok_or(anyhow!("No gateways returned by nym-api"))?; + Ok(EntryPoint::Gateway { + identity: *gateway.identity(), + }) +} diff --git a/nym-vpn-core/crates/nym-routing/src/unix/mod.rs b/nym-vpn-core/crates/nym-routing/src/unix/mod.rs index a781c4db02..875266dd82 100644 --- a/nym-vpn-core/crates/nym-routing/src/unix/mod.rs +++ b/nym-vpn-core/crates/nym-routing/src/unix/mod.rs @@ -271,13 +271,10 @@ impl RouteManagerHandle { /// Ensure that packets are routed using the correct tables. #[cfg(target_os = "linux")] - pub async fn create_routing_rules(&self, enable_ipv6: bool) -> Result<(), Error> { + pub async fn create_routing_rules(&self) -> Result<(), Error> { let (response_tx, response_rx) = oneshot::channel(); self.tx - .unbounded_send(RouteManagerCommand::CreateRoutingRules( - enable_ipv6, - response_tx, - )) + .unbounded_send(RouteManagerCommand::CreateRoutingRules(true, response_tx)) .map_err(|_| Error::RouteManagerDown)?; response_rx .await diff --git a/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml b/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml index f307f9c3ad..573c0938a9 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml +++ b/nym-vpn-core/crates/nym-vpn-lib/Cargo.toml @@ -68,7 +68,9 @@ nym-authenticator-client = { path = "../nym-authenticator-client" } nym-connection-monitor = { path = "../nym-connection-monitor" } nym-gateway-directory = { path = "../nym-gateway-directory" } nym-ip-packet-client = { path = "../nym-ip-packet-client" } +nym-vpn-account-controller = { path = "../nym-vpn-account-controller" } nym-vpn-api-client = { path = "../nym-vpn-api-client" } +nym-vpn-network-config = { path = "../nym-vpn-network-config" } nym-vpn-store = { path = "../nym-vpn-store" } nym-wg-gateway-client = { path = "../nym-wg-gateway-client" } nym-wg-go = { path = "../nym-wg-go" } diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/platform/account.rs b/nym-vpn-core/crates/nym-vpn-lib/src/platform/account.rs new file mode 100644 index 0000000000..572baad60b --- /dev/null +++ b/nym-vpn-core/crates/nym-vpn-lib/src/platform/account.rs @@ -0,0 +1,205 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use std::{path::PathBuf, str::FromStr, sync::Arc}; + +use nym_vpn_account_controller::{AccountCommand, ReadyToConnect, SharedAccountState}; +use nym_vpn_store::mnemonic::MnemonicStorage; +use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle}; +use tokio_util::sync::CancellationToken; + +use crate::uniffi_custom_impls::AccountStateSummary; + +use super::{error::VpnError, ACCOUNT_CONTROLLER_HANDLE}; + +pub(super) async fn start_account_controller_inner(data_dir: PathBuf) -> Result<(), VpnError> { + let mut guard = ACCOUNT_CONTROLLER_HANDLE.lock().await; + + if guard.is_none() { + let account_controller_handle = start_account_controller(data_dir).await?; + *guard = Some(account_controller_handle); + Ok(()) + } else { + Err(VpnError::InvalidStateError { + details: "Account controller is already running.".to_owned(), + }) + } +} + +pub(super) async fn stop_account_controller_inner() -> Result<(), VpnError> { + let mut guard = ACCOUNT_CONTROLLER_HANDLE.lock().await; + + match guard.take() { + Some(account_controller_handle) => { + account_controller_handle.shutdown_and_wait().await; + Ok(()) + } + None => Err(VpnError::InvalidStateError { + details: "Account controller is not running.".to_owned(), + }), + } +} + +async fn start_account_controller(data_dir: PathBuf) -> Result { + let storage = Arc::new(tokio::sync::Mutex::new( + crate::storage::VpnClientOnDiskStorage::new(data_dir.clone()), + )); + // TODO: pass in as argument + let user_agent = crate::util::construct_user_agent(); + let shutdown_token = CancellationToken::new(); + let account_controller = nym_vpn_account_controller::AccountController::new( + Arc::clone(&storage), + data_dir.clone(), + user_agent, + shutdown_token.child_token(), + ) + .await; + + let shared_account_state = account_controller.shared_state(); + let account_command_tx = account_controller.command_tx(); + let account_controller_handle = tokio::spawn(account_controller.run()); + + Ok(AccountControllerHandle { + command_sender: account_command_tx, + shared_state: shared_account_state, + handle: account_controller_handle, + shutdown_token, + }) +} + +pub(super) struct AccountControllerHandle { + command_sender: UnboundedSender, + shared_state: nym_vpn_account_controller::SharedAccountState, + handle: JoinHandle<()>, + shutdown_token: CancellationToken, +} + +impl AccountControllerHandle { + fn send_command(&self, command: AccountCommand) { + if let Err(e) = self.command_sender.send(command) { + tracing::error!("Failed to send comamnd: {}", e); + } + } + + async fn is_ready_to_connect(&self) -> ReadyToConnect { + self.shared_state.is_ready_to_connect().await + } + + async fn shutdown_and_wait(self) { + self.shutdown_token.cancel(); + + if let Err(e) = self.handle.await { + tracing::error!("Failed to join on account controller handle: {}", e); + } + } +} + +pub(super) async fn send_account_command(command: AccountCommand) -> Result<(), VpnError> { + if let Some(guard) = &*ACCOUNT_CONTROLLER_HANDLE.lock().await { + guard.send_command(command); + Ok(()) + } else { + Err(VpnError::InvalidStateError { + details: "Account controller is not running.".to_owned(), + }) + } +} + +async fn get_shared_account_state() -> Result { + if let Some(guard) = &*ACCOUNT_CONTROLLER_HANDLE.lock().await { + Ok(guard.shared_state.clone()) + } else { + Err(VpnError::InvalidStateError { + details: "Account controller is not running.".to_owned(), + }) + } +} + +async fn is_account_ready_to_connect() -> Result { + if let Some(guard) = &*ACCOUNT_CONTROLLER_HANDLE.lock().await { + Ok(guard.is_ready_to_connect().await) + } else { + Err(VpnError::InvalidStateError { + details: "Account controller is not running.".to_owned(), + }) + } +} + +pub(super) async fn assert_account_ready_to_connect() -> Result<(), VpnError> { + match is_account_ready_to_connect().await? { + ReadyToConnect::Ready => Ok(()), + not_ready_to_connect => { + tracing::warn!("Not ready to connect: {:?}", not_ready_to_connect); + Err(VpnError::Account(not_ready_to_connect.into())) + } + } +} + +fn setup_account_storage(path: &str) -> Result { + let path = PathBuf::from_str(path).map_err(|err| VpnError::InternalError { + details: err.to_string(), + })?; + Ok(crate::storage::VpnClientOnDiskStorage::new(path)) +} + +pub(super) async fn store_account_mnemonic(mnemonic: &str, path: &str) -> Result<(), VpnError> { + // TODO: store the mnemonic by sending a command to the account controller instead of directly + // interacting with the storage. + + let storage = setup_account_storage(path)?; + + let mnemonic = nym_vpn_store::mnemonic::Mnemonic::parse(mnemonic).map_err(|err| { + VpnError::InternalError { + details: err.to_string(), + } + })?; + + storage + .store_mnemonic(mnemonic) + .await + .map_err(|err| VpnError::InternalError { + details: err.to_string(), + })?; + + send_account_command(AccountCommand::UpdateSharedAccountState).await?; + + Ok(()) +} + +pub(super) async fn is_account_mnemonic_stored(path: &str) -> Result { + // TODO: query the mnemonic by sending a command to the account controller instead of directly + // interacting with the storage. + + let storage = setup_account_storage(path)?; + storage + .is_mnemonic_stored() + .await + .map_err(|err| VpnError::InternalError { + details: err.to_string(), + }) +} + +pub(super) async fn remove_account_mnemonic(path: &str) -> Result { + // TODO: remove the mnemonic by sending a command to the account controller instead of directly + // interacting with the storage. + + let storage = setup_account_storage(path)?; + let is_account_removed_success = + storage + .remove_mnemonic() + .await + .map(|_| true) + .map_err(|err| VpnError::InternalError { + details: err.to_string(), + })?; + + send_account_command(AccountCommand::UpdateSharedAccountState).await?; + + Ok(is_account_removed_success) +} + +pub(super) async fn get_account_summary() -> Result { + let shared_account_state = get_shared_account_state().await?; + let account_state_summary = shared_account_state.lock().await.clone(); + Ok(AccountStateSummary::from(account_state_summary)) +} diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/platform/error.rs b/nym-vpn-core/crates/nym-vpn-lib/src/platform/error.rs index f75f41c2d2..649612eeca 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/platform/error.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/platform/error.rs @@ -20,6 +20,42 @@ pub enum VpnError { #[error("{details}")] InvalidStateError { details: String }, + + #[error("{0}")] + Account(AccountError), +} + +#[derive(thiserror::Error, uniffi::Error, Debug, Clone, PartialEq)] +pub enum AccountError { + #[error("account state is ready to connect")] + Ready, + #[error("no account stored")] + NoAccountStored, + #[error("account not active")] + AccountNotActive, + #[error("no active subscription")] + NoActiveSubscription, + #[error("device not registered")] + DeviceNotRegistered, + #[error("device not active")] + DeviceNotActive, +} + +impl From for AccountError { + fn from(value: nym_vpn_account_controller::ReadyToConnect) -> Self { + match value { + nym_vpn_account_controller::ReadyToConnect::Ready => Self::Ready, + nym_vpn_account_controller::ReadyToConnect::NoMnemonicStored => Self::NoAccountStored, + nym_vpn_account_controller::ReadyToConnect::AccountNotActive => Self::AccountNotActive, + nym_vpn_account_controller::ReadyToConnect::NoActiveSubscription => { + Self::NoActiveSubscription + } + nym_vpn_account_controller::ReadyToConnect::DeviceNotRegistered => { + Self::DeviceNotRegistered + } + nym_vpn_account_controller::ReadyToConnect::DeviceNotActive => Self::DeviceNotActive, + } + } } impl From for VpnError { diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/platform/mod.rs b/nym-vpn-core/crates/nym-vpn-lib/src/platform/mod.rs index 76b10b3d93..8287fa8f16 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/platform/mod.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/platform/mod.rs @@ -1,6 +1,6 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -#![cfg_attr(not(target_os = "macos"), allow(dead_code))] +// #![cfg_attr(not(target_os = "macos"), allow(dead_code))] #[cfg(target_os = "android")] pub mod android; @@ -8,8 +8,11 @@ pub(crate) mod error; #[cfg(any(target_os = "ios", target_os = "macos"))] pub mod swift; -use std::{env, path::PathBuf, str::FromStr, sync::Arc}; +mod account; +use std::{env, path::PathBuf, sync::Arc}; + +use account::AccountControllerHandle; use lazy_static::lazy_static; use log::*; use tokio::{ @@ -21,8 +24,6 @@ use tokio_util::sync::CancellationToken; use url::Url; use nym_gateway_directory::Config as GatewayDirectoryConfig; -use nym_vpn_api_client::types::VpnApiAccount; -use nym_vpn_store::mnemonic::MnemonicStorage as _; use self::error::VpnError; #[cfg(target_os = "android")] @@ -37,14 +38,15 @@ use crate::{ TunnelStateMachine, TunnelType, }, uniffi_custom_impls::{ - BandwidthStatus, ConnectionStatus, EntryPoint, ExitPoint, GatewayMinPerformance, - GatewayType, Location, TunStatus, UserAgent, + AccountStateSummary, BandwidthStatus, ConnectionStatus, EntryPoint, ExitPoint, + GatewayMinPerformance, GatewayType, Location, NetworkEnvironment, TunStatus, UserAgent, }, }; lazy_static! { static ref RUNTIME: Runtime = Runtime::new().unwrap(); static ref STATE_MACHINE_HANDLE: Mutex> = Mutex::new(None); + static ref ACCOUNT_CONTROLLER_HANDLE: Mutex> = Mutex::new(None); } #[allow(non_snake_case)] @@ -54,6 +56,12 @@ pub fn startVPN(config: VPNConfig) -> Result<(), VpnError> { } async fn start_vpn_inner(config: VPNConfig) -> Result<(), VpnError> { + // TODO: we do a pre-connect check here. This mirrors the logic in the daemon. + // We want to move this check into the state machine so that it happens during the connecting + // state instead. This would allow us more flexibility in waiting for the account to be ready + // and handle errors in a unified manner. + account::assert_account_ready_to_connect().await?; + let mut guard = STATE_MACHINE_HANDLE.lock().await; if guard.is_none() { @@ -79,6 +87,7 @@ async fn stop_vpn_inner() -> Result<(), VpnError> { match guard.take() { Some(state_machine_handle) => { + // TODO: add timeout state_machine_handle.shutdown_and_wait().await; Ok(()) } @@ -88,6 +97,20 @@ async fn stop_vpn_inner() -> Result<(), VpnError> { } } +#[allow(non_snake_case)] +#[uniffi::export] +pub fn startAccountController(data_dir: String) -> Result<(), VpnError> { + RUNTIME.block_on(account::start_account_controller_inner(PathBuf::from( + data_dir, + ))) +} + +#[allow(non_snake_case)] +#[uniffi::export] +pub fn stopAccountController() -> Result<(), VpnError> { + RUNTIME.block_on(account::stop_account_controller_inner()) +} + #[allow(non_snake_case)] #[uniffi::export] pub fn initLogger() { @@ -99,108 +122,44 @@ pub fn initLogger() { android::init_logs(log_level); } -fn setup_account_storage(path: &str) -> Result { - let path = PathBuf::from_str(path).map_err(|err| VpnError::InternalError { - details: err.to_string(), - })?; - Ok(crate::storage::VpnClientOnDiskStorage::new(path)) -} - +// Fetch the network environment details from the network name. +// TODO: also add the ability to catch this information for subsequent use. #[allow(non_snake_case)] #[uniffi::export] -pub fn storeAccountMnemonic(mnemonic: String, path: String) -> Result<(), VpnError> { - RUNTIME.block_on(store_account_mnemonic(&mnemonic, &path)) +pub fn fetchEnvironment(network_name: &str) -> Result { + RUNTIME.block_on(fetch_environment(network_name)) } -async fn store_account_mnemonic(mnemonic: &str, path: &str) -> Result<(), VpnError> { - let storage = setup_account_storage(path)?; - - let mnemonic = nym_vpn_store::mnemonic::Mnemonic::parse(mnemonic).map_err(|err| { - VpnError::InternalError { - details: err.to_string(), - } - })?; - - storage - .store_mnemonic(mnemonic) - .await +async fn fetch_environment(network_name: &str) -> Result { + nym_vpn_network_config::Network::fetch(network_name) + .map(NetworkEnvironment::from) .map_err(|err| VpnError::InternalError { details: err.to_string(), - })?; - - Ok(()) + }) } #[allow(non_snake_case)] #[uniffi::export] -pub fn isAccountMnemonicStored(path: String) -> Result { - RUNTIME.block_on(is_account_mnemonic_stored(&path)) +pub fn storeAccountMnemonic(mnemonic: String, path: String) -> Result<(), VpnError> { + RUNTIME.block_on(account::store_account_mnemonic(&mnemonic, &path)) } -async fn is_account_mnemonic_stored(path: &str) -> Result { - let storage = setup_account_storage(path)?; - storage - .is_mnemonic_stored() - .await - .map_err(|err| VpnError::InternalError { - details: err.to_string(), - }) +#[allow(non_snake_case)] +#[uniffi::export] +pub fn isAccountMnemonicStored(path: String) -> Result { + RUNTIME.block_on(account::is_account_mnemonic_stored(&path)) } #[allow(non_snake_case)] #[uniffi::export] pub fn removeAccountMnemonic(path: String) -> Result { - RUNTIME.block_on(remove_account_mnemonic(&path)) + RUNTIME.block_on(account::remove_account_mnemonic(&path)) } -async fn remove_account_mnemonic(path: &str) -> Result { - let storage = setup_account_storage(path)?; - storage - .remove_mnemonic() - .await - .map(|_| true) - .map_err(|err| VpnError::InternalError { - details: err.to_string(), - }) -} - -#[allow(non_snake_case, dead_code)] -pub fn getAccountSummary( - path: String, - nym_vpn_api_url: Url, - user_agent: UserAgent, -) -> Result { - RUNTIME.block_on(get_account_summary(path, nym_vpn_api_url, user_agent)) -} - -#[allow(dead_code)] -async fn get_account_summary( - path: String, - nym_vpn_api_url: Url, - user_agent: UserAgent, -) -> Result { - let storage = setup_account_storage(&path)?; - let account = storage - .load_mnemonic() - .await - .map(VpnApiAccount::from) - .map_err(|err| VpnError::InternalError { - details: err.to_string(), - })?; - - let api_client = nym_vpn_api_client::VpnApiClient::new(nym_vpn_api_url, user_agent.into())?; - - api_client - .get_account_summary(&account) - .await - .map_err(|err| VpnError::InternalError { - details: err.to_string(), - }) - .and_then(|summary| { - serde_json::to_string(&summary).map_err(|err| VpnError::InternalError { - details: err.to_string(), - }) - }) +#[allow(non_snake_case)] +#[uniffi::export] +pub fn getAccountSummary() -> Result { + RUNTIME.block_on(account::get_account_summary()) } #[allow(non_snake_case)] @@ -254,25 +213,21 @@ pub fn getLowLatencyEntryCountry( RUNTIME.block_on(get_low_latency_entry_country( api_url, vpn_api_url, - Some(user_agent), + user_agent, )) } async fn get_low_latency_entry_country( api_url: Url, vpn_api_url: Option, - user_agent: Option, + user_agent: UserAgent, ) -> Result { let config = nym_gateway_directory::Config { api_url, nym_vpn_api_url: vpn_api_url, min_gateway_performance: None, }; - let user_agent = user_agent - .map(nym_sdk::UserAgent::from) - .unwrap_or_else(crate::util::construct_user_agent); - - GatewayClient::new(config, user_agent)? + GatewayClient::new(config, user_agent.into())? .lookup_low_latency_entry_gateway() .await .map_err(VpnError::from) diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/route_handler.rs b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/route_handler.rs index 96f59bc43b..18083283bb 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/route_handler.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/route_handler.rs @@ -18,14 +18,12 @@ pub const TUNNEL_FWMARK: u32 = 0x14d; pub enum RoutingConfig { Mixnet { - enable_ipv6: bool, tun_name: String, entry_gateway_address: IpAddr, #[cfg(target_os = "linux")] physical_interface: DefaultInterface, }, Wireguard { - enable_ipv6: bool, entry_tun_name: String, exit_tun_name: String, entry_gateway_address: IpAddr, @@ -35,16 +33,6 @@ pub enum RoutingConfig { }, } -impl RoutingConfig { - #[cfg(target_os = "linux")] - pub fn enable_ipv6(&self) -> bool { - match self { - Self::Mixnet { enable_ipv6, .. } => *enable_ipv6, - Self::Wireguard { enable_ipv6, .. } => *enable_ipv6, - } - } -} - pub struct RouteHandler { route_manager: RouteManagerHandle, } @@ -62,12 +50,10 @@ impl RouteHandler { } pub async fn add_routes(&mut self, routing_config: RoutingConfig) -> Result<()> { - #[cfg(target_os = "linux")] - let enable_ipv6 = routing_config.enable_ipv6(); let routes = Self::get_routes(routing_config); #[cfg(target_os = "linux")] - self.route_manager.create_routing_rules(enable_ipv6).await?; + self.route_manager.create_routing_rules().await?; self.route_manager.add_routes(routes).await?; @@ -101,7 +87,6 @@ impl RouteHandler { match routing_config { RoutingConfig::Mixnet { - enable_ipv6, tun_name, entry_gateway_address, #[cfg(target_os = "linux")] @@ -124,15 +109,12 @@ impl RouteHandler { Node::device(tun_name.to_owned()), )); - if enable_ipv6 { - routes.insert(RequiredRoute::new( - "::0/0".parse().unwrap(), - Node::device(tun_name.to_owned()), - )); - } + routes.insert(RequiredRoute::new( + "::0/0".parse().unwrap(), + Node::device(tun_name.to_owned()), + )); } RoutingConfig::Wireguard { - enable_ipv6, entry_tun_name, exit_tun_name, entry_gateway_address, @@ -162,12 +144,10 @@ impl RouteHandler { Node::device(exit_tun_name.to_owned()), )); - if enable_ipv6 { - routes.insert(RequiredRoute::new( - "::0/0".parse().unwrap(), - Node::device(exit_tun_name.to_owned()), - )); - } + routes.insert(RequiredRoute::new( + "::0/0".parse().unwrap(), + Node::device(exit_tun_name.to_owned()), + )); } } diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/states/connecting_state.rs b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/states/connecting_state.rs index eb561ef7b8..5c23ab5e84 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/states/connecting_state.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/states/connecting_state.rs @@ -3,6 +3,13 @@ #[cfg(any(target_os = "linux", target_os = "macos"))] use std::net::Ipv4Addr; +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "android" +))] +use std::net::Ipv6Addr; #[cfg(any(target_os = "android", target_os = "ios"))] use std::os::fd::{AsRawFd, IntoRawFd}; #[cfg(target_os = "android")] @@ -45,6 +52,22 @@ const DEFAULT_TUN_MTU: u16 = if cfg!(any(target_os = "ios", target_os = "android } else { 1500 }; +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "android", + target_os = "ios" +))] +/// Entry IPv6 address (ULA) used by WireGuard, currently not routable. +const WG_ENTRY_IPV6_ADDR: Ipv6Addr = Ipv6Addr::new( + 0xfdcc, 0x9fc0, 0xe75a, 0x53c3, 0xfa25, 0x241f, 0x21c0, 0x70d0, +); + +#[cfg(any(target_os = "linux", target_os = "macos"))] +/// Exit IPv6 address (ULA) used by WireGuard, currently not routable. +const WG_EXIT_IPV6_ADDR: Ipv6Addr = Ipv6Addr::new( + 0xfdcc, 0x9fc0, 0xe75a, 0x53c3, 0x72a5, 0xf352, 0x5475, 0x4160, +); type ConnectFut = BoxFuture<'static, tunnel::Result>; @@ -202,8 +225,6 @@ impl ConnectingState { .map_err(Error::ConnectMixnetTunnel)?; let assigned_addresses = connected_tunnel.assigned_addresses(); - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] - let enable_ipv6 = true; let mtu: u16 = shared_state .tunnel_settings .mixnet_tunnel_options @@ -211,8 +232,7 @@ impl ConnectingState { .unwrap_or(DEFAULT_TUN_MTU); #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] - let tun_device = - Self::create_mixnet_device(assigned_addresses.interface_addresses, mtu, enable_ipv6)?; + let tun_device = Self::create_mixnet_device(assigned_addresses.interface_addresses, mtu)?; #[cfg(any(target_os = "ios", target_os = "android"))] let tun_device = { @@ -247,7 +267,6 @@ impl ConnectingState { tracing::debug!("Created tun device: {}", tun_name); let routing_config = RoutingConfig::Mixnet { - enable_ipv6, tun_name: tun_name.clone(), entry_gateway_address: assigned_addresses.entry_mixnet_gateway_ip, #[cfg(target_os = "linux")] @@ -279,13 +298,14 @@ impl ConnectingState { .connect_wireguard_tunnel(shared_state.tunnel_settings.enable_credentials_mode) .await .map_err(Error::ConnectWireguardTunnel)?; - - let enable_ipv6 = false; let conn_data = connected_tunnel.connection_data(); #[cfg(unix)] let entry_tun = Self::create_wireguard_device( - conn_data.entry.private_ipv4, + IpPair { + ipv4: conn_data.entry.private_ipv4, + ipv6: WG_ENTRY_IPV6_ADDR, + }, None, connected_tunnel.entry_mtu(), )?; @@ -299,7 +319,10 @@ impl ConnectingState { #[cfg(unix)] let exit_tun = Self::create_wireguard_device( - conn_data.exit.private_ipv4, + IpPair { + ipv4: conn_data.exit.private_ipv4, + ipv6: WG_EXIT_IPV6_ADDR, + }, Some(conn_data.entry.private_ipv4), connected_tunnel.exit_mtu(), )?; @@ -314,7 +337,6 @@ impl ConnectingState { let exit_tun_name = "nym1".to_owned(); let routing_config = RoutingConfig::Wireguard { - enable_ipv6, #[cfg(unix)] entry_tun_name, #[cfg(unix)] @@ -370,9 +392,15 @@ impl ConnectingState { let packet_tunnel_settings = tunnel_provider::tunnel_settings::TunnelSettings { dns_servers: shared_state.tunnel_settings.dns.ip_addresses().to_vec(), - interface_addresses: vec![IpNetwork::V4( - Ipv4Network::new(conn_data.entry.private_ipv4, 32).expect("ipv4 to ipnetwork/32"), - )], + interface_addresses: vec![ + IpNetwork::V4( + Ipv4Network::new(conn_data.entry.private_ipv4, 32) + .expect("ipv4 to ipnetwork/32"), + ), + IpNetwork::V6( + Ipv6Network::new(WG_ENTRY_IPV6_ADDR, 128).expect("ipv6 to ipnetwork/128"), + ), + ], remote_addresses: vec![conn_data.entry.endpoint.ip()], mtu: connected_tunnel.exit_mtu(), }; @@ -426,11 +454,7 @@ impl ConnectingState { } #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] - fn create_mixnet_device( - interface_addresses: IpPair, - mtu: u16, - enable_ipv6: bool, - ) -> Result { + fn create_mixnet_device(interface_addresses: IpPair, mtu: u16) -> Result { let mut tun_config = tun::Configuration::default(); tun_config @@ -445,29 +469,27 @@ impl ConnectingState { let tun_device = tun::create_as_async(&tun_config).map_err(Error::CreateTunDevice)?; - if enable_ipv6 { - let tun_name = tun_device - .get_ref() - .name() - .map_err(Error::GetTunDeviceName)?; + let tun_name = tun_device + .get_ref() + .name() + .map_err(Error::GetTunDeviceName)?; - tun_ipv6::set_ipv6_addr(&tun_name, interface_addresses.ipv6) - .map_err(Error::SetTunDeviceIpv6Addr)?; - } + tun_ipv6::set_ipv6_addr(&tun_name, interface_addresses.ipv6) + .map_err(Error::SetTunDeviceIpv6Addr)?; Ok(tun_device) } #[cfg(any(target_os = "linux", target_os = "macos"))] fn create_wireguard_device( - interface_addr: Ipv4Addr, + interface_addresses: IpPair, destination: Option, mtu: u16, ) -> Result { let mut tun_config = tun::Configuration::default(); tun_config - .address(interface_addr) + .address(interface_addresses.ipv4) .netmask(Ipv4Addr::BROADCAST) .mtu(i32::from(mtu)) .up(); @@ -481,7 +503,17 @@ impl ConnectingState { platform_config.packet_information(false); }); - tun::create_as_async(&tun_config).map_err(Error::CreateTunDevice) + let tun_device = tun::create_as_async(&tun_config).map_err(Error::CreateTunDevice)?; + + let tun_name = tun_device + .get_ref() + .name() + .map_err(Error::GetTunDeviceName)?; + + tun_ipv6::set_ipv6_addr(&tun_name, interface_addresses.ipv6) + .map_err(Error::SetTunDeviceIpv6Addr)?; + + Ok(tun_device) } #[cfg(any(target_os = "ios", target_os = "android"))] diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/tunnel/wireguard/connected_tunnel/desktop.rs b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/tunnel/wireguard/connected_tunnel/desktop.rs index 5ad57ed0b5..a93b9bb687 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/tunnel/wireguard/connected_tunnel/desktop.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/tunnel_state_machine/tunnel/wireguard/connected_tunnel/desktop.rs @@ -47,13 +47,13 @@ impl ConnectedTunnel { } pub fn entry_mtu(&self) -> u16 { - // 1500 - 60 (ipv4+wg header) - 1440 + // 1500 - 80 (ipv6+wg header) + 1420 } pub fn exit_mtu(&self) -> u16 { - // 1440 - 80 (ipv6+wg header) - 1360 + // 1420 - 80 (ipv6+wg header) + 1340 } pub fn run( diff --git a/nym-vpn-core/crates/nym-vpn-lib/src/uniffi_custom_impls.rs b/nym-vpn-core/crates/nym-vpn-lib/src/uniffi_custom_impls.rs index f739e80317..b0422bb4a4 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/src/uniffi_custom_impls.rs +++ b/nym-vpn-core/crates/nym-vpn-lib/src/uniffi_custom_impls.rs @@ -227,6 +227,154 @@ impl UniffiCustomTypeConverter for OffsetDateTime { } } +/// Represents the nym network environment together with the environment specific to nym-vpn. These +/// need to be exported to the environment (for now, until it's refactored internally in the nym +/// crates) so that the client can have access to the necessary information. +/// +/// The list is as of today: +/// +/// NETWORK_NAME = nym_network::network_name +/// +/// BECH32_PREFIX = nym_network::chain_details::bech32_account_prefix +/// MIX_DENOM = nym_network::chain_details::mix_denom::base +/// MIX_DENOM_DISPLAY = nym_network::chain_details::mix_denom::display +/// STAKE_DENOM = nym_network::chain_details::stake_denom::base +/// STAKE_DENOM_DISPLAY = nym_network::chain_details::stake_denom::display +/// DENOMS_EXPONENT = nym_network::chain_details::mix_denom::display_exponent +/// +/// MIXNET_CONTRACT_ADDRESS = nym_network::contracts::mixnet_contract_address +/// VESTING_CONTRACT_ADDRESS = nym_network::contracts::vesting_contract_address +/// GROUP_CONTRACT_ADDRESS = nym_network::contracts::group_contract_address +/// ECASH_CONTRACT_ADDRESS = nym_network::contracts::ecash_contract_address +/// MULTISIG_CONTRACT_ADDRESS = nym_network::contracts::multisig_contract_address +/// COCONUT_DKG_CONTRACT_ADDRESS = nym_network::contracts::coconut_dkg_contract_address +/// +/// NYXD = nym_network::endpoints[0]::nyxd_url +/// NYM_API = nym_network::endpoints[0]::api_url +/// NYXD_WS = nym_network::endpoints[0]::websocket_url +/// +/// NYM_VPN_API = nym_vpn_network::nym_vpn_api_url +#[derive(uniffi::Record)] +pub struct NetworkEnvironment { + pub nym_network: NymNetworkDetails, + pub nym_vpn_network: NymVpnNetwork, +} + +impl From for NetworkEnvironment { + fn from(network: nym_vpn_network_config::Network) -> Self { + NetworkEnvironment { + nym_network: network.nym_network.network.into(), + nym_vpn_network: network.nym_vpn_network.into(), + } + } +} + +#[derive(uniffi::Record)] +pub struct NymNetworkDetails { + pub network_name: String, + pub chain_details: ChainDetails, + pub endpoints: Vec, + pub contracts: NymContracts, +} + +impl From for NymNetworkDetails { + fn from(value: crate::nym_config::defaults::NymNetworkDetails) -> Self { + NymNetworkDetails { + network_name: value.network_name, + chain_details: value.chain_details.into(), + endpoints: value.endpoints.into_iter().map(|e| e.into()).collect(), + contracts: value.contracts.into(), + } + } +} + +#[derive(uniffi::Record)] +pub struct ChainDetails { + pub bech32_account_prefix: String, + pub mix_denom: DenomDetails, + pub stake_denom: DenomDetails, +} + +impl From for ChainDetails { + fn from(value: crate::nym_config::defaults::ChainDetails) -> Self { + ChainDetails { + bech32_account_prefix: value.bech32_account_prefix, + mix_denom: value.mix_denom.into(), + stake_denom: value.stake_denom.into(), + } + } +} + +#[derive(uniffi::Record)] +pub struct DenomDetails { + pub base: String, + pub display: String, + pub display_exponent: u32, +} + +impl From for DenomDetails { + fn from(value: crate::nym_config::defaults::DenomDetailsOwned) -> Self { + DenomDetails { + base: value.base, + display: value.display, + display_exponent: value.display_exponent, + } + } +} + +#[derive(uniffi::Record)] +pub struct ValidatorDetails { + pub nyxd_url: String, + pub websocket_url: Option, + pub api_url: Option, +} + +impl From for ValidatorDetails { + fn from(value: crate::nym_config::defaults::ValidatorDetails) -> Self { + ValidatorDetails { + nyxd_url: value.nyxd_url, + websocket_url: value.websocket_url, + api_url: value.api_url, + } + } +} + +#[derive(uniffi::Record)] +pub struct NymContracts { + pub mixnet_contract_address: Option, + pub vesting_contract_address: Option, + pub ecash_contract_address: Option, + pub group_contract_address: Option, + pub multisig_contract_address: Option, + pub coconut_dkg_contract_address: Option, +} + +impl From for NymContracts { + fn from(value: crate::nym_config::defaults::NymContracts) -> Self { + NymContracts { + mixnet_contract_address: value.mixnet_contract_address, + vesting_contract_address: value.vesting_contract_address, + ecash_contract_address: value.ecash_contract_address, + group_contract_address: value.group_contract_address, + multisig_contract_address: value.multisig_contract_address, + coconut_dkg_contract_address: value.coconut_dkg_contract_address, + } + } +} + +#[derive(uniffi::Record)] +pub struct NymVpnNetwork { + pub nym_vpn_api_url: String, +} + +impl From for NymVpnNetwork { + fn from(value: nym_vpn_network_config::NymVpnNetwork) -> Self { + NymVpnNetwork { + nym_vpn_api_url: value.nym_vpn_api_url.to_string(), + } + } +} + #[derive(uniffi::Record)] pub struct Location { pub two_letter_iso_country_code: String, @@ -474,3 +622,120 @@ impl UniffiCustomTypeConverter for PathBuf { obj.display().to_string() } } + +#[derive(uniffi::Record, Clone, Default, PartialEq)] +pub struct AccountStateSummary { + pub mnemonic: Option, + pub account: Option, + pub subscription: Option, + pub device: Option, + pub pending_zk_nym: bool, +} + +impl From for AccountStateSummary { + fn from(value: nym_vpn_account_controller::AccountStateSummary) -> Self { + AccountStateSummary { + mnemonic: value.mnemonic.map(|m| m.into()), + account: value.account.map(|a| a.into()), + subscription: value.subscription.map(|s| s.into()), + device: value.device.map(|d| d.into()), + pending_zk_nym: value.pending_zk_nym, + } + } +} + +#[derive(uniffi::Enum, Debug, Clone, PartialEq)] +pub enum MnemonicState { + NotStored, + Stored, +} + +impl From for MnemonicState { + fn from(value: nym_vpn_account_controller::shared_state::MnemonicState) -> Self { + match value { + nym_vpn_account_controller::shared_state::MnemonicState::NotStored => { + MnemonicState::NotStored + } + nym_vpn_account_controller::shared_state::MnemonicState::Stored => { + MnemonicState::Stored + } + } + } +} + +#[derive(uniffi::Enum, Debug, Clone, PartialEq)] +pub enum AccountState { + NotRegistered, + Inactive, + Active, + DeleteMe, +} + +impl From for AccountState { + fn from(value: nym_vpn_account_controller::shared_state::AccountState) -> Self { + match value { + nym_vpn_account_controller::shared_state::AccountState::NotRegistered => { + AccountState::NotRegistered + } + nym_vpn_account_controller::shared_state::AccountState::Inactive => { + AccountState::Inactive + } + nym_vpn_account_controller::shared_state::AccountState::Active => AccountState::Active, + nym_vpn_account_controller::shared_state::AccountState::DeleteMe => { + AccountState::DeleteMe + } + } + } +} + +#[derive(uniffi::Enum, Debug, Clone, PartialEq)] +pub enum SubscriptionState { + NotActive, + Pending, + Complete, + Active, +} + +impl From for SubscriptionState { + fn from(value: nym_vpn_account_controller::shared_state::SubscriptionState) -> Self { + match value { + nym_vpn_account_controller::shared_state::SubscriptionState::NotActive => { + SubscriptionState::NotActive + } + nym_vpn_account_controller::shared_state::SubscriptionState::Pending => { + SubscriptionState::Pending + } + nym_vpn_account_controller::shared_state::SubscriptionState::Complete => { + SubscriptionState::Complete + } + nym_vpn_account_controller::shared_state::SubscriptionState::Active => { + SubscriptionState::Active + } + } + } +} + +#[derive(uniffi::Enum, Debug, Clone, PartialEq)] +pub enum DeviceState { + NotRegistered, + Inactive, + Active, + DeleteMe, +} + +impl From for DeviceState { + fn from(value: nym_vpn_account_controller::shared_state::DeviceState) -> Self { + match value { + nym_vpn_account_controller::shared_state::DeviceState::NotRegistered => { + DeviceState::NotRegistered + } + nym_vpn_account_controller::shared_state::DeviceState::Inactive => { + DeviceState::Inactive + } + nym_vpn_account_controller::shared_state::DeviceState::Active => DeviceState::Active, + nym_vpn_account_controller::shared_state::DeviceState::DeleteMe => { + DeviceState::DeleteMe + } + } + } +} diff --git a/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt b/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt index 1c26080ed5..44f34c85ff 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt +++ b/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.kt @@ -756,6 +756,14 @@ internal open class UniffiVTableCallbackInterfaceTunnelStatusListener( + + + + + + + + @@ -804,6 +812,10 @@ internal interface UniffiLib : Library { ): Unit fun uniffi_nym_vpn_lib_fn_method_tunnelstatuslistener_on_event(`ptr`: Pointer,`event`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit + fun uniffi_nym_vpn_lib_fn_func_fetchenvironment(`networkName`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue + fun uniffi_nym_vpn_lib_fn_func_getaccountsummary(uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue fun uniffi_nym_vpn_lib_fn_func_getgatewaycountries(`apiUrl`: RustBuffer.ByValue,`nymVpnApiUrl`: RustBuffer.ByValue,`gwType`: RustBuffer.ByValue,`userAgent`: RustBuffer.ByValue,`minGatewayPerformance`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun uniffi_nym_vpn_lib_fn_func_getlowlatencyentrycountry(`apiUrl`: RustBuffer.ByValue,`vpnApiUrl`: RustBuffer.ByValue,`userAgent`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, @@ -814,8 +826,12 @@ internal interface UniffiLib : Library { ): Byte fun uniffi_nym_vpn_lib_fn_func_removeaccountmnemonic(`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Byte + fun uniffi_nym_vpn_lib_fn_func_startaccountcontroller(`dataDir`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, + ): Unit fun uniffi_nym_vpn_lib_fn_func_startvpn(`config`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit + fun uniffi_nym_vpn_lib_fn_func_stopaccountcontroller(uniffi_out_err: UniffiRustCallStatus, + ): Unit fun uniffi_nym_vpn_lib_fn_func_stopvpn(uniffi_out_err: UniffiRustCallStatus, ): Unit fun uniffi_nym_vpn_lib_fn_func_storeaccountmnemonic(`mnemonic`: RustBuffer.ByValue,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, @@ -932,6 +948,10 @@ internal interface UniffiLib : Library { ): Unit fun ffi_nym_vpn_lib_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit + fun uniffi_nym_vpn_lib_checksum_func_fetchenvironment( + ): Short + fun uniffi_nym_vpn_lib_checksum_func_getaccountsummary( + ): Short fun uniffi_nym_vpn_lib_checksum_func_getgatewaycountries( ): Short fun uniffi_nym_vpn_lib_checksum_func_getlowlatencyentrycountry( @@ -942,8 +962,12 @@ internal interface UniffiLib : Library { ): Short fun uniffi_nym_vpn_lib_checksum_func_removeaccountmnemonic( ): Short + fun uniffi_nym_vpn_lib_checksum_func_startaccountcontroller( + ): Short fun uniffi_nym_vpn_lib_checksum_func_startvpn( ): Short + fun uniffi_nym_vpn_lib_checksum_func_stopaccountcontroller( + ): Short fun uniffi_nym_vpn_lib_checksum_func_stopvpn( ): Short fun uniffi_nym_vpn_lib_checksum_func_storeaccountmnemonic( @@ -971,6 +995,12 @@ private fun uniffiCheckContractApiVersion(lib: UniffiLib) { @Suppress("UNUSED_PARAMETER") private fun uniffiCheckApiChecksums(lib: UniffiLib) { + if (lib.uniffi_nym_vpn_lib_checksum_func_fetchenvironment() != 34561.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_nym_vpn_lib_checksum_func_getaccountsummary() != 13465.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_nym_vpn_lib_checksum_func_getgatewaycountries() != 41607.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -986,9 +1016,15 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_nym_vpn_lib_checksum_func_removeaccountmnemonic() != 51019.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_nym_vpn_lib_checksum_func_startaccountcontroller() != 34257.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_nym_vpn_lib_checksum_func_startvpn() != 55890.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_nym_vpn_lib_checksum_func_stopaccountcontroller() != 64683.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_nym_vpn_lib_checksum_func_stopvpn() != 59823.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1084,6 +1120,26 @@ public object FfiConverterUShort: FfiConverter { } } +public object FfiConverterUInt: FfiConverter { + override fun lift(value: Int): UInt { + return value.toUInt() + } + + override fun read(buf: ByteBuffer): UInt { + return lift(buf.getInt()) + } + + override fun lower(value: UInt): Int { + return value.toInt() + } + + override fun allocationSize(value: UInt) = 4UL + + override fun write(value: UInt, buf: ByteBuffer) { + buf.putInt(value.toInt()) + } +} + public object FfiConverterInt: FfiConverter { override fun lift(value: Int): Int { return value @@ -1872,6 +1928,80 @@ public object FfiConverterTypeTunnelStatusListener: FfiConverter { + override fun read(buf: ByteBuffer): AccountStateSummary { + return AccountStateSummary( + FfiConverterOptionalTypeMnemonicState.read(buf), + FfiConverterOptionalTypeAccountState.read(buf), + FfiConverterOptionalTypeSubscriptionState.read(buf), + FfiConverterOptionalTypeDeviceState.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: AccountStateSummary) = ( + FfiConverterOptionalTypeMnemonicState.allocationSize(value.`mnemonic`) + + FfiConverterOptionalTypeAccountState.allocationSize(value.`account`) + + FfiConverterOptionalTypeSubscriptionState.allocationSize(value.`subscription`) + + FfiConverterOptionalTypeDeviceState.allocationSize(value.`device`) + + FfiConverterBoolean.allocationSize(value.`pendingZkNym`) + ) + + override fun write(value: AccountStateSummary, buf: ByteBuffer) { + FfiConverterOptionalTypeMnemonicState.write(value.`mnemonic`, buf) + FfiConverterOptionalTypeAccountState.write(value.`account`, buf) + FfiConverterOptionalTypeSubscriptionState.write(value.`subscription`, buf) + FfiConverterOptionalTypeDeviceState.write(value.`device`, buf) + FfiConverterBoolean.write(value.`pendingZkNym`, buf) + } +} + + + +data class ChainDetails ( + var `bech32AccountPrefix`: kotlin.String, + var `mixDenom`: DenomDetails, + var `stakeDenom`: DenomDetails +) { + + companion object +} + +public object FfiConverterTypeChainDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChainDetails { + return ChainDetails( + FfiConverterString.read(buf), + FfiConverterTypeDenomDetails.read(buf), + FfiConverterTypeDenomDetails.read(buf), + ) + } + + override fun allocationSize(value: ChainDetails) = ( + FfiConverterString.allocationSize(value.`bech32AccountPrefix`) + + FfiConverterTypeDenomDetails.allocationSize(value.`mixDenom`) + + FfiConverterTypeDenomDetails.allocationSize(value.`stakeDenom`) + ) + + override fun write(value: ChainDetails, buf: ByteBuffer) { + FfiConverterString.write(value.`bech32AccountPrefix`, buf) + FfiConverterTypeDenomDetails.write(value.`mixDenom`, buf) + FfiConverterTypeDenomDetails.write(value.`stakeDenom`, buf) + } +} + + + data class ConnectionData ( /** * Mixnet entry gateway @@ -1921,6 +2051,39 @@ public object FfiConverterTypeConnectionData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): DenomDetails { + return DenomDetails( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: DenomDetails) = ( + FfiConverterString.allocationSize(value.`base`) + + FfiConverterString.allocationSize(value.`display`) + + FfiConverterUInt.allocationSize(value.`displayExponent`) + ) + + override fun write(value: DenomDetails, buf: ByteBuffer) { + FfiConverterString.write(value.`base`, buf) + FfiConverterString.write(value.`display`, buf) + FfiConverterUInt.write(value.`displayExponent`, buf) + } +} + + + data class DnsSettings ( /** * DNS IP addresses. @@ -2200,6 +2363,171 @@ public object FfiConverterTypeMixnetConnectionData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NetworkEnvironment { + return NetworkEnvironment( + FfiConverterTypeNymNetworkDetails.read(buf), + FfiConverterTypeNymVpnNetwork.read(buf), + ) + } + + override fun allocationSize(value: NetworkEnvironment) = ( + FfiConverterTypeNymNetworkDetails.allocationSize(value.`nymNetwork`) + + FfiConverterTypeNymVpnNetwork.allocationSize(value.`nymVpnNetwork`) + ) + + override fun write(value: NetworkEnvironment, buf: ByteBuffer) { + FfiConverterTypeNymNetworkDetails.write(value.`nymNetwork`, buf) + FfiConverterTypeNymVpnNetwork.write(value.`nymVpnNetwork`, buf) + } +} + + + +data class NymContracts ( + var `mixnetContractAddress`: kotlin.String?, + var `vestingContractAddress`: kotlin.String?, + var `ecashContractAddress`: kotlin.String?, + var `groupContractAddress`: kotlin.String?, + var `multisigContractAddress`: kotlin.String?, + var `coconutDkgContractAddress`: kotlin.String? +) { + + companion object +} + +public object FfiConverterTypeNymContracts: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NymContracts { + return NymContracts( + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + } + + override fun allocationSize(value: NymContracts) = ( + FfiConverterOptionalString.allocationSize(value.`mixnetContractAddress`) + + FfiConverterOptionalString.allocationSize(value.`vestingContractAddress`) + + FfiConverterOptionalString.allocationSize(value.`ecashContractAddress`) + + FfiConverterOptionalString.allocationSize(value.`groupContractAddress`) + + FfiConverterOptionalString.allocationSize(value.`multisigContractAddress`) + + FfiConverterOptionalString.allocationSize(value.`coconutDkgContractAddress`) + ) + + override fun write(value: NymContracts, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`mixnetContractAddress`, buf) + FfiConverterOptionalString.write(value.`vestingContractAddress`, buf) + FfiConverterOptionalString.write(value.`ecashContractAddress`, buf) + FfiConverterOptionalString.write(value.`groupContractAddress`, buf) + FfiConverterOptionalString.write(value.`multisigContractAddress`, buf) + FfiConverterOptionalString.write(value.`coconutDkgContractAddress`, buf) + } +} + + + +data class NymNetworkDetails ( + var `networkName`: kotlin.String, + var `chainDetails`: ChainDetails, + var `endpoints`: List, + var `contracts`: NymContracts +) { + + companion object +} + +public object FfiConverterTypeNymNetworkDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NymNetworkDetails { + return NymNetworkDetails( + FfiConverterString.read(buf), + FfiConverterTypeChainDetails.read(buf), + FfiConverterSequenceTypeValidatorDetails.read(buf), + FfiConverterTypeNymContracts.read(buf), + ) + } + + override fun allocationSize(value: NymNetworkDetails) = ( + FfiConverterString.allocationSize(value.`networkName`) + + FfiConverterTypeChainDetails.allocationSize(value.`chainDetails`) + + FfiConverterSequenceTypeValidatorDetails.allocationSize(value.`endpoints`) + + FfiConverterTypeNymContracts.allocationSize(value.`contracts`) + ) + + override fun write(value: NymNetworkDetails, buf: ByteBuffer) { + FfiConverterString.write(value.`networkName`, buf) + FfiConverterTypeChainDetails.write(value.`chainDetails`, buf) + FfiConverterSequenceTypeValidatorDetails.write(value.`endpoints`, buf) + FfiConverterTypeNymContracts.write(value.`contracts`, buf) + } +} + + + +data class NymVpnNetwork ( + var `nymVpnApiUrl`: kotlin.String +) { + + companion object +} + +public object FfiConverterTypeNymVpnNetwork: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NymVpnNetwork { + return NymVpnNetwork( + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: NymVpnNetwork) = ( + FfiConverterString.allocationSize(value.`nymVpnApiUrl`) + ) + + override fun write(value: NymVpnNetwork, buf: ByteBuffer) { + FfiConverterString.write(value.`nymVpnApiUrl`, buf) + } +} + + + /** * Tunnel + network settings */ @@ -2363,6 +2691,39 @@ public object FfiConverterTypeVPNConfig: FfiConverterRustBuffer { +data class ValidatorDetails ( + var `nyxdUrl`: kotlin.String, + var `websocketUrl`: kotlin.String?, + var `apiUrl`: kotlin.String? +) { + + companion object +} + +public object FfiConverterTypeValidatorDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ValidatorDetails { + return ValidatorDetails( + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + } + + override fun allocationSize(value: ValidatorDetails) = ( + FfiConverterString.allocationSize(value.`nyxdUrl`) + + FfiConverterOptionalString.allocationSize(value.`websocketUrl`) + + FfiConverterOptionalString.allocationSize(value.`apiUrl`) + ) + + override fun write(value: ValidatorDetails, buf: ByteBuffer) { + FfiConverterString.write(value.`nyxdUrl`, buf) + FfiConverterOptionalString.write(value.`websocketUrl`, buf) + FfiConverterOptionalString.write(value.`apiUrl`, buf) + } +} + + + data class WireguardConnectionData ( var `entry`: WireguardNode, var `exit`: WireguardNode @@ -2458,6 +2819,146 @@ public object FfiConverterTypeWireguardNode: FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): AccountError { + return when(buf.getInt()) { + 1 -> AccountError.Ready + 2 -> AccountError.NoAccountStored + 3 -> AccountError.AccountNotActive + 4 -> AccountError.NoActiveSubscription + 5 -> AccountError.DeviceNotRegistered + 6 -> AccountError.DeviceNotActive + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: AccountError) = when(value) { + is AccountError.Ready -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is AccountError.NoAccountStored -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is AccountError.AccountNotActive -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is AccountError.NoActiveSubscription -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is AccountError.DeviceNotRegistered -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is AccountError.DeviceNotActive -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + } + + override fun write(value: AccountError, buf: ByteBuffer) { + when(value) { + is AccountError.Ready -> { + buf.putInt(1) + Unit + } + is AccountError.NoAccountStored -> { + buf.putInt(2) + Unit + } + is AccountError.AccountNotActive -> { + buf.putInt(3) + Unit + } + is AccountError.NoActiveSubscription -> { + buf.putInt(4) + Unit + } + is AccountError.DeviceNotRegistered -> { + buf.putInt(5) + Unit + } + is AccountError.DeviceNotActive -> { + buf.putInt(6) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + + +enum class AccountState { + + NOT_REGISTERED, + INACTIVE, + ACTIVE, + DELETE_ME; + companion object +} + + +public object FfiConverterTypeAccountState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + AccountState.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AccountState) = 4UL + + override fun write(value: AccountState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + sealed class ActionAfterDisconnect { object Nothing : ActionAfterDisconnect() @@ -2719,6 +3220,35 @@ public object FfiConverterTypeConnectionStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + DeviceState.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: DeviceState) = 4UL + + override fun write(value: DeviceState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + sealed class EntryPoint { data class Gateway( @@ -3268,6 +3798,33 @@ public object FfiConverterTypeMixnetEvent : FfiConverterRustBuffer{ + +enum class MnemonicState { + + NOT_STORED, + STORED; + companion object +} + + +public object FfiConverterTypeMnemonicState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + MnemonicState.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: MnemonicState) = 4UL + + override fun write(value: MnemonicState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + sealed class NymVpnStatus { data class MixConnectInfo( @@ -3344,6 +3901,35 @@ public object FfiConverterTypeNymVpnStatus : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + SubscriptionState.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: SubscriptionState) = 4UL + + override fun write(value: SubscriptionState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + enum class TunStatus { UP, @@ -3699,6 +4285,14 @@ sealed class VpnException: Exception() { get() = "details=${ `details` }" } + class Account( + + val ``: AccountError + ) : VpnException() { + override val message + get() = "=${ `` }" + } + companion object ErrorHandler : UniffiRustCallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): VpnException = FfiConverterTypeVpnError.lift(error_buf) @@ -3728,6 +4322,9 @@ public object FfiConverterTypeVpnError : FfiConverterRustBuffer { 6 -> VpnException.InvalidStateException( FfiConverterString.read(buf), ) + 7 -> VpnException.Account( + FfiConverterTypeAccountError.read(buf), + ) else -> throw RuntimeException("invalid error enum value, something is very wrong!!") } } @@ -3763,6 +4360,11 @@ public object FfiConverterTypeVpnError : FfiConverterRustBuffer { 4UL + FfiConverterString.allocationSize(value.`details`) ) + is VpnException.Account -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterTypeAccountError.allocationSize(value.``) + ) } } @@ -3797,6 +4399,11 @@ public object FfiConverterTypeVpnError : FfiConverterRustBuffer { FfiConverterString.write(value.`details`, buf) Unit } + is VpnException.Account -> { + buf.putInt(7) + FfiConverterTypeAccountError.write(value.``, buf) + Unit + } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } @@ -3834,6 +4441,35 @@ public object FfiConverterOptionalULong: FfiConverterRustBuffer { +public object FfiConverterOptionalString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.String? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterString.read(buf) + } + + override fun allocationSize(value: kotlin.String?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterString.allocationSize(value) + } + } + + override fun write(value: kotlin.String?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterString.write(value, buf) + } + } +} + + + + public object FfiConverterOptionalTypeTunnelStatusListener: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): TunnelStatusListener? { if (buf.get().toInt() == 0) { @@ -4008,6 +4644,122 @@ public object FfiConverterOptionalTypeUserAgent: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AccountState? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAccountState.read(buf) + } + + override fun allocationSize(value: AccountState?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAccountState.allocationSize(value) + } + } + + override fun write(value: AccountState?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAccountState.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeDeviceState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): DeviceState? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeDeviceState.read(buf) + } + + override fun allocationSize(value: DeviceState?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeDeviceState.allocationSize(value) + } + } + + override fun write(value: DeviceState?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeDeviceState.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeMnemonicState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): MnemonicState? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeMnemonicState.read(buf) + } + + override fun allocationSize(value: MnemonicState?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeMnemonicState.allocationSize(value) + } + } + + override fun write(value: MnemonicState?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeMnemonicState.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeSubscriptionState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SubscriptionState? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeSubscriptionState.read(buf) + } + + override fun allocationSize(value: SubscriptionState?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeSubscriptionState.allocationSize(value) + } + } + + override fun write(value: SubscriptionState?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeSubscriptionState.write(value, buf) + } + } +} + + + + public object FfiConverterOptionalSequenceString: FfiConverterRustBuffer?> { override fun read(buf: ByteBuffer): List? { if (buf.get().toInt() == 0) { @@ -4261,6 +5013,31 @@ public object FfiConverterSequenceTypeLocation: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeValidatorDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeValidatorDetails.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeValidatorDetails.write(it, buf) + } + } +} + + + + public object FfiConverterSequenceTypeIpv4Route: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() @@ -4562,6 +5339,26 @@ public object FfiConverterTypeUrl: FfiConverter { FfiConverterString.write(builtinValue, buf) } } + @Throws(VpnException::class) fun `fetchEnvironment`(`networkName`: kotlin.String): NetworkEnvironment { + return FfiConverterTypeNetworkEnvironment.lift( + uniffiRustCallWithError(VpnException) { _status -> + UniffiLib.INSTANCE.uniffi_nym_vpn_lib_fn_func_fetchenvironment( + FfiConverterString.lower(`networkName`),_status) +} + ) + } + + + @Throws(VpnException::class) fun `getAccountSummary`(): AccountStateSummary { + return FfiConverterTypeAccountStateSummary.lift( + uniffiRustCallWithError(VpnException) { _status -> + UniffiLib.INSTANCE.uniffi_nym_vpn_lib_fn_func_getaccountsummary( + _status) +} + ) + } + + @Throws(VpnException::class) fun `getGatewayCountries`(`apiUrl`: Url, `nymVpnApiUrl`: Url?, `gwType`: GatewayType, `userAgent`: UserAgent?, `minGatewayPerformance`: GatewayMinPerformance?): List { return FfiConverterSequenceTypeLocation.lift( uniffiRustCallWithError(VpnException) { _status -> @@ -4610,6 +5407,15 @@ public object FfiConverterTypeUrl: FfiConverter { } + @Throws(VpnException::class) fun `startAccountController`(`dataDir`: kotlin.String) + = + uniffiRustCallWithError(VpnException) { _status -> + UniffiLib.INSTANCE.uniffi_nym_vpn_lib_fn_func_startaccountcontroller( + FfiConverterString.lower(`dataDir`),_status) +} + + + @Throws(VpnException::class) fun `startVpn`(`config`: VpnConfig) = uniffiRustCallWithError(VpnException) { _status -> @@ -4619,6 +5425,15 @@ public object FfiConverterTypeUrl: FfiConverter { + @Throws(VpnException::class) fun `stopAccountController`() + = + uniffiRustCallWithError(VpnException) { _status -> + UniffiLib.INSTANCE.uniffi_nym_vpn_lib_fn_func_stopaccountcontroller( + _status) +} + + + @Throws(VpnException::class) fun `stopVpn`() = uniffiRustCallWithError(VpnException) { _status -> diff --git a/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift b/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift index 8540406626..12fb000b6c 100644 --- a/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift +++ b/nym-vpn-core/crates/nym-vpn-lib/uniffi/nym_vpn_lib.swift @@ -408,6 +408,19 @@ fileprivate struct FfiConverterUInt16: FfiConverterPrimitive { } } +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { + typealias FfiType = UInt32 + typealias SwiftType = UInt32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + fileprivate struct FfiConverterUInt64: FfiConverterPrimitive { typealias FfiType = UInt64 typealias SwiftType = UInt64 @@ -1029,6 +1042,152 @@ public func FfiConverterTypeTunnelStatusListener_lower(_ value: TunnelStatusList } +public struct AccountStateSummary { + public var mnemonic: MnemonicState? + public var account: AccountState? + public var subscription: SubscriptionState? + public var device: DeviceState? + public var pendingZkNym: Bool + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(mnemonic: MnemonicState?, account: AccountState?, subscription: SubscriptionState?, device: DeviceState?, pendingZkNym: Bool) { + self.mnemonic = mnemonic + self.account = account + self.subscription = subscription + self.device = device + self.pendingZkNym = pendingZkNym + } +} + + + +extension AccountStateSummary: Equatable, Hashable { + public static func ==(lhs: AccountStateSummary, rhs: AccountStateSummary) -> Bool { + if lhs.mnemonic != rhs.mnemonic { + return false + } + if lhs.account != rhs.account { + return false + } + if lhs.subscription != rhs.subscription { + return false + } + if lhs.device != rhs.device { + return false + } + if lhs.pendingZkNym != rhs.pendingZkNym { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(mnemonic) + hasher.combine(account) + hasher.combine(subscription) + hasher.combine(device) + hasher.combine(pendingZkNym) + } +} + + +public struct FfiConverterTypeAccountStateSummary: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountStateSummary { + return + try AccountStateSummary( + mnemonic: FfiConverterOptionTypeMnemonicState.read(from: &buf), + account: FfiConverterOptionTypeAccountState.read(from: &buf), + subscription: FfiConverterOptionTypeSubscriptionState.read(from: &buf), + device: FfiConverterOptionTypeDeviceState.read(from: &buf), + pendingZkNym: FfiConverterBool.read(from: &buf) + ) + } + + public static func write(_ value: AccountStateSummary, into buf: inout [UInt8]) { + FfiConverterOptionTypeMnemonicState.write(value.mnemonic, into: &buf) + FfiConverterOptionTypeAccountState.write(value.account, into: &buf) + FfiConverterOptionTypeSubscriptionState.write(value.subscription, into: &buf) + FfiConverterOptionTypeDeviceState.write(value.device, into: &buf) + FfiConverterBool.write(value.pendingZkNym, into: &buf) + } +} + + +public func FfiConverterTypeAccountStateSummary_lift(_ buf: RustBuffer) throws -> AccountStateSummary { + return try FfiConverterTypeAccountStateSummary.lift(buf) +} + +public func FfiConverterTypeAccountStateSummary_lower(_ value: AccountStateSummary) -> RustBuffer { + return FfiConverterTypeAccountStateSummary.lower(value) +} + + +public struct ChainDetails { + public var bech32AccountPrefix: String + public var mixDenom: DenomDetails + public var stakeDenom: DenomDetails + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(bech32AccountPrefix: String, mixDenom: DenomDetails, stakeDenom: DenomDetails) { + self.bech32AccountPrefix = bech32AccountPrefix + self.mixDenom = mixDenom + self.stakeDenom = stakeDenom + } +} + + + +extension ChainDetails: Equatable, Hashable { + public static func ==(lhs: ChainDetails, rhs: ChainDetails) -> Bool { + if lhs.bech32AccountPrefix != rhs.bech32AccountPrefix { + return false + } + if lhs.mixDenom != rhs.mixDenom { + return false + } + if lhs.stakeDenom != rhs.stakeDenom { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(bech32AccountPrefix) + hasher.combine(mixDenom) + hasher.combine(stakeDenom) + } +} + + +public struct FfiConverterTypeChainDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChainDetails { + return + try ChainDetails( + bech32AccountPrefix: FfiConverterString.read(from: &buf), + mixDenom: FfiConverterTypeDenomDetails.read(from: &buf), + stakeDenom: FfiConverterTypeDenomDetails.read(from: &buf) + ) + } + + public static func write(_ value: ChainDetails, into buf: inout [UInt8]) { + FfiConverterString.write(value.bech32AccountPrefix, into: &buf) + FfiConverterTypeDenomDetails.write(value.mixDenom, into: &buf) + FfiConverterTypeDenomDetails.write(value.stakeDenom, into: &buf) + } +} + + +public func FfiConverterTypeChainDetails_lift(_ buf: RustBuffer) throws -> ChainDetails { + return try FfiConverterTypeChainDetails.lift(buf) +} + +public func FfiConverterTypeChainDetails_lower(_ value: ChainDetails) -> RustBuffer { + return FfiConverterTypeChainDetails.lower(value) +} + + public struct ConnectionData { /** * Mixnet entry gateway @@ -1126,6 +1285,71 @@ public func FfiConverterTypeConnectionData_lower(_ value: ConnectionData) -> Rus } +public struct DenomDetails { + public var base: String + public var display: String + public var displayExponent: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(base: String, display: String, displayExponent: UInt32) { + self.base = base + self.display = display + self.displayExponent = displayExponent + } +} + + + +extension DenomDetails: Equatable, Hashable { + public static func ==(lhs: DenomDetails, rhs: DenomDetails) -> Bool { + if lhs.base != rhs.base { + return false + } + if lhs.display != rhs.display { + return false + } + if lhs.displayExponent != rhs.displayExponent { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(base) + hasher.combine(display) + hasher.combine(displayExponent) + } +} + + +public struct FfiConverterTypeDenomDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DenomDetails { + return + try DenomDetails( + base: FfiConverterString.read(from: &buf), + display: FfiConverterString.read(from: &buf), + displayExponent: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: DenomDetails, into buf: inout [UInt8]) { + FfiConverterString.write(value.base, into: &buf) + FfiConverterString.write(value.display, into: &buf) + FfiConverterUInt32.write(value.displayExponent, into: &buf) + } +} + + +public func FfiConverterTypeDenomDetails_lift(_ buf: RustBuffer) throws -> DenomDetails { + return try FfiConverterTypeDenomDetails.lift(buf) +} + +public func FfiConverterTypeDenomDetails_lower(_ value: DenomDetails) -> RustBuffer { + return FfiConverterTypeDenomDetails.lower(value) +} + + public struct DnsSettings { /** * DNS IP addresses. @@ -1676,6 +1900,303 @@ public func FfiConverterTypeMixnetConnectionData_lower(_ value: MixnetConnection } +/** + * Represents the nym network environment together with the environment specific to nym-vpn. These + * need to be exported to the environment (for now, until it's refactored internally in the nym + * crates) so that the client can have access to the necessary information. + * + * The list is as of today: + * + * NETWORK_NAME = nym_network::network_name + * + * BECH32_PREFIX = nym_network::chain_details::bech32_account_prefix + * MIX_DENOM = nym_network::chain_details::mix_denom::base + * MIX_DENOM_DISPLAY = nym_network::chain_details::mix_denom::display + * STAKE_DENOM = nym_network::chain_details::stake_denom::base + * STAKE_DENOM_DISPLAY = nym_network::chain_details::stake_denom::display + * DENOMS_EXPONENT = nym_network::chain_details::mix_denom::display_exponent + * + * MIXNET_CONTRACT_ADDRESS = nym_network::contracts::mixnet_contract_address + * VESTING_CONTRACT_ADDRESS = nym_network::contracts::vesting_contract_address + * GROUP_CONTRACT_ADDRESS = nym_network::contracts::group_contract_address + * ECASH_CONTRACT_ADDRESS = nym_network::contracts::ecash_contract_address + * MULTISIG_CONTRACT_ADDRESS = nym_network::contracts::multisig_contract_address + * COCONUT_DKG_CONTRACT_ADDRESS = nym_network::contracts::coconut_dkg_contract_address + * + * NYXD = nym_network::endpoints[0]::nyxd_url + * NYM_API = nym_network::endpoints[0]::api_url + * NYXD_WS = nym_network::endpoints[0]::websocket_url + * + * NYM_VPN_API = nym_vpn_network::nym_vpn_api_url + */ +public struct NetworkEnvironment { + public var nymNetwork: NymNetworkDetails + public var nymVpnNetwork: NymVpnNetwork + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(nymNetwork: NymNetworkDetails, nymVpnNetwork: NymVpnNetwork) { + self.nymNetwork = nymNetwork + self.nymVpnNetwork = nymVpnNetwork + } +} + + + +extension NetworkEnvironment: Equatable, Hashable { + public static func ==(lhs: NetworkEnvironment, rhs: NetworkEnvironment) -> Bool { + if lhs.nymNetwork != rhs.nymNetwork { + return false + } + if lhs.nymVpnNetwork != rhs.nymVpnNetwork { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(nymNetwork) + hasher.combine(nymVpnNetwork) + } +} + + +public struct FfiConverterTypeNetworkEnvironment: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NetworkEnvironment { + return + try NetworkEnvironment( + nymNetwork: FfiConverterTypeNymNetworkDetails.read(from: &buf), + nymVpnNetwork: FfiConverterTypeNymVpnNetwork.read(from: &buf) + ) + } + + public static func write(_ value: NetworkEnvironment, into buf: inout [UInt8]) { + FfiConverterTypeNymNetworkDetails.write(value.nymNetwork, into: &buf) + FfiConverterTypeNymVpnNetwork.write(value.nymVpnNetwork, into: &buf) + } +} + + +public func FfiConverterTypeNetworkEnvironment_lift(_ buf: RustBuffer) throws -> NetworkEnvironment { + return try FfiConverterTypeNetworkEnvironment.lift(buf) +} + +public func FfiConverterTypeNetworkEnvironment_lower(_ value: NetworkEnvironment) -> RustBuffer { + return FfiConverterTypeNetworkEnvironment.lower(value) +} + + +public struct NymContracts { + public var mixnetContractAddress: String? + public var vestingContractAddress: String? + public var ecashContractAddress: String? + public var groupContractAddress: String? + public var multisigContractAddress: String? + public var coconutDkgContractAddress: String? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(mixnetContractAddress: String?, vestingContractAddress: String?, ecashContractAddress: String?, groupContractAddress: String?, multisigContractAddress: String?, coconutDkgContractAddress: String?) { + self.mixnetContractAddress = mixnetContractAddress + self.vestingContractAddress = vestingContractAddress + self.ecashContractAddress = ecashContractAddress + self.groupContractAddress = groupContractAddress + self.multisigContractAddress = multisigContractAddress + self.coconutDkgContractAddress = coconutDkgContractAddress + } +} + + + +extension NymContracts: Equatable, Hashable { + public static func ==(lhs: NymContracts, rhs: NymContracts) -> Bool { + if lhs.mixnetContractAddress != rhs.mixnetContractAddress { + return false + } + if lhs.vestingContractAddress != rhs.vestingContractAddress { + return false + } + if lhs.ecashContractAddress != rhs.ecashContractAddress { + return false + } + if lhs.groupContractAddress != rhs.groupContractAddress { + return false + } + if lhs.multisigContractAddress != rhs.multisigContractAddress { + return false + } + if lhs.coconutDkgContractAddress != rhs.coconutDkgContractAddress { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(mixnetContractAddress) + hasher.combine(vestingContractAddress) + hasher.combine(ecashContractAddress) + hasher.combine(groupContractAddress) + hasher.combine(multisigContractAddress) + hasher.combine(coconutDkgContractAddress) + } +} + + +public struct FfiConverterTypeNymContracts: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NymContracts { + return + try NymContracts( + mixnetContractAddress: FfiConverterOptionString.read(from: &buf), + vestingContractAddress: FfiConverterOptionString.read(from: &buf), + ecashContractAddress: FfiConverterOptionString.read(from: &buf), + groupContractAddress: FfiConverterOptionString.read(from: &buf), + multisigContractAddress: FfiConverterOptionString.read(from: &buf), + coconutDkgContractAddress: FfiConverterOptionString.read(from: &buf) + ) + } + + public static func write(_ value: NymContracts, into buf: inout [UInt8]) { + FfiConverterOptionString.write(value.mixnetContractAddress, into: &buf) + FfiConverterOptionString.write(value.vestingContractAddress, into: &buf) + FfiConverterOptionString.write(value.ecashContractAddress, into: &buf) + FfiConverterOptionString.write(value.groupContractAddress, into: &buf) + FfiConverterOptionString.write(value.multisigContractAddress, into: &buf) + FfiConverterOptionString.write(value.coconutDkgContractAddress, into: &buf) + } +} + + +public func FfiConverterTypeNymContracts_lift(_ buf: RustBuffer) throws -> NymContracts { + return try FfiConverterTypeNymContracts.lift(buf) +} + +public func FfiConverterTypeNymContracts_lower(_ value: NymContracts) -> RustBuffer { + return FfiConverterTypeNymContracts.lower(value) +} + + +public struct NymNetworkDetails { + public var networkName: String + public var chainDetails: ChainDetails + public var endpoints: [ValidatorDetails] + public var contracts: NymContracts + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(networkName: String, chainDetails: ChainDetails, endpoints: [ValidatorDetails], contracts: NymContracts) { + self.networkName = networkName + self.chainDetails = chainDetails + self.endpoints = endpoints + self.contracts = contracts + } +} + + + +extension NymNetworkDetails: Equatable, Hashable { + public static func ==(lhs: NymNetworkDetails, rhs: NymNetworkDetails) -> Bool { + if lhs.networkName != rhs.networkName { + return false + } + if lhs.chainDetails != rhs.chainDetails { + return false + } + if lhs.endpoints != rhs.endpoints { + return false + } + if lhs.contracts != rhs.contracts { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(networkName) + hasher.combine(chainDetails) + hasher.combine(endpoints) + hasher.combine(contracts) + } +} + + +public struct FfiConverterTypeNymNetworkDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NymNetworkDetails { + return + try NymNetworkDetails( + networkName: FfiConverterString.read(from: &buf), + chainDetails: FfiConverterTypeChainDetails.read(from: &buf), + endpoints: FfiConverterSequenceTypeValidatorDetails.read(from: &buf), + contracts: FfiConverterTypeNymContracts.read(from: &buf) + ) + } + + public static func write(_ value: NymNetworkDetails, into buf: inout [UInt8]) { + FfiConverterString.write(value.networkName, into: &buf) + FfiConverterTypeChainDetails.write(value.chainDetails, into: &buf) + FfiConverterSequenceTypeValidatorDetails.write(value.endpoints, into: &buf) + FfiConverterTypeNymContracts.write(value.contracts, into: &buf) + } +} + + +public func FfiConverterTypeNymNetworkDetails_lift(_ buf: RustBuffer) throws -> NymNetworkDetails { + return try FfiConverterTypeNymNetworkDetails.lift(buf) +} + +public func FfiConverterTypeNymNetworkDetails_lower(_ value: NymNetworkDetails) -> RustBuffer { + return FfiConverterTypeNymNetworkDetails.lower(value) +} + + +public struct NymVpnNetwork { + public var nymVpnApiUrl: String + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(nymVpnApiUrl: String) { + self.nymVpnApiUrl = nymVpnApiUrl + } +} + + + +extension NymVpnNetwork: Equatable, Hashable { + public static func ==(lhs: NymVpnNetwork, rhs: NymVpnNetwork) -> Bool { + if lhs.nymVpnApiUrl != rhs.nymVpnApiUrl { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(nymVpnApiUrl) + } +} + + +public struct FfiConverterTypeNymVpnNetwork: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NymVpnNetwork { + return + try NymVpnNetwork( + nymVpnApiUrl: FfiConverterString.read(from: &buf) + ) + } + + public static func write(_ value: NymVpnNetwork, into buf: inout [UInt8]) { + FfiConverterString.write(value.nymVpnApiUrl, into: &buf) + } +} + + +public func FfiConverterTypeNymVpnNetwork_lift(_ buf: RustBuffer) throws -> NymVpnNetwork { + return try FfiConverterTypeNymVpnNetwork.lift(buf) +} + +public func FfiConverterTypeNymVpnNetwork_lower(_ value: NymVpnNetwork) -> RustBuffer { + return FfiConverterTypeNymVpnNetwork.lower(value) +} + + /** * Represents a default network route used by the system. */ @@ -2012,6 +2533,71 @@ public func FfiConverterTypeVPNConfig_lower(_ value: VpnConfig) -> RustBuffer { } +public struct ValidatorDetails { + public var nyxdUrl: String + public var websocketUrl: String? + public var apiUrl: String? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(nyxdUrl: String, websocketUrl: String?, apiUrl: String?) { + self.nyxdUrl = nyxdUrl + self.websocketUrl = websocketUrl + self.apiUrl = apiUrl + } +} + + + +extension ValidatorDetails: Equatable, Hashable { + public static func ==(lhs: ValidatorDetails, rhs: ValidatorDetails) -> Bool { + if lhs.nyxdUrl != rhs.nyxdUrl { + return false + } + if lhs.websocketUrl != rhs.websocketUrl { + return false + } + if lhs.apiUrl != rhs.apiUrl { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(nyxdUrl) + hasher.combine(websocketUrl) + hasher.combine(apiUrl) + } +} + + +public struct FfiConverterTypeValidatorDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ValidatorDetails { + return + try ValidatorDetails( + nyxdUrl: FfiConverterString.read(from: &buf), + websocketUrl: FfiConverterOptionString.read(from: &buf), + apiUrl: FfiConverterOptionString.read(from: &buf) + ) + } + + public static func write(_ value: ValidatorDetails, into buf: inout [UInt8]) { + FfiConverterString.write(value.nyxdUrl, into: &buf) + FfiConverterOptionString.write(value.websocketUrl, into: &buf) + FfiConverterOptionString.write(value.apiUrl, into: &buf) + } +} + + +public func FfiConverterTypeValidatorDetails_lift(_ buf: RustBuffer) throws -> ValidatorDetails { + return try FfiConverterTypeValidatorDetails.lift(buf) +} + +public func FfiConverterTypeValidatorDetails_lower(_ value: ValidatorDetails) -> RustBuffer { + return FfiConverterTypeValidatorDetails.lower(value) +} + + public struct WireguardConnectionData { public var entry: WireguardNode public var exit: WireguardNode @@ -2198,6 +2784,158 @@ public func FfiConverterTypeWireguardNode_lower(_ value: WireguardNode) -> RustB return FfiConverterTypeWireguardNode.lower(value) } +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum AccountError { + + case ready + case noAccountStored + case accountNotActive + case noActiveSubscription + case deviceNotRegistered + case deviceNotActive +} + + +public struct FfiConverterTypeAccountError: FfiConverterRustBuffer { + typealias SwiftType = AccountError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountError { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .ready + + case 2: return .noAccountStored + + case 3: return .accountNotActive + + case 4: return .noActiveSubscription + + case 5: return .deviceNotRegistered + + case 6: return .deviceNotActive + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AccountError, into buf: inout [UInt8]) { + switch value { + + + case .ready: + writeInt(&buf, Int32(1)) + + + case .noAccountStored: + writeInt(&buf, Int32(2)) + + + case .accountNotActive: + writeInt(&buf, Int32(3)) + + + case .noActiveSubscription: + writeInt(&buf, Int32(4)) + + + case .deviceNotRegistered: + writeInt(&buf, Int32(5)) + + + case .deviceNotActive: + writeInt(&buf, Int32(6)) + + } + } +} + + +public func FfiConverterTypeAccountError_lift(_ buf: RustBuffer) throws -> AccountError { + return try FfiConverterTypeAccountError.lift(buf) +} + +public func FfiConverterTypeAccountError_lower(_ value: AccountError) -> RustBuffer { + return FfiConverterTypeAccountError.lower(value) +} + + + +extension AccountError: Equatable, Hashable {} + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum AccountState { + + case notRegistered + case inactive + case active + case deleteMe +} + + +public struct FfiConverterTypeAccountState: FfiConverterRustBuffer { + typealias SwiftType = AccountState + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountState { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .notRegistered + + case 2: return .inactive + + case 3: return .active + + case 4: return .deleteMe + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AccountState, into buf: inout [UInt8]) { + switch value { + + + case .notRegistered: + writeInt(&buf, Int32(1)) + + + case .inactive: + writeInt(&buf, Int32(2)) + + + case .active: + writeInt(&buf, Int32(3)) + + + case .deleteMe: + writeInt(&buf, Int32(4)) + + } + } +} + + +public func FfiConverterTypeAccountState_lift(_ buf: RustBuffer) throws -> AccountState { + return try FfiConverterTypeAccountState.lift(buf) +} + +public func FfiConverterTypeAccountState_lower(_ value: AccountState) -> RustBuffer { + return FfiConverterTypeAccountState.lower(value) +} + + + +extension AccountState: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -2465,97 +3203,166 @@ public func FfiConverterTypeConnectionEvent_lower(_ value: ConnectionEvent) -> R -extension ConnectionEvent: Equatable, Hashable {} +extension ConnectionEvent: Equatable, Hashable {} + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum ConnectionStatus { + + case entryGatewayDown + case exitGatewayDownIpv4 + case exitGatewayDownIpv6 + case exitGatewayRoutingErrorIpv4 + case exitGatewayRoutingErrorIpv6 + case connectedIpv4 + case connectedIpv6 +} + + +public struct FfiConverterTypeConnectionStatus: FfiConverterRustBuffer { + typealias SwiftType = ConnectionStatus + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ConnectionStatus { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .entryGatewayDown + + case 2: return .exitGatewayDownIpv4 + + case 3: return .exitGatewayDownIpv6 + + case 4: return .exitGatewayRoutingErrorIpv4 + + case 5: return .exitGatewayRoutingErrorIpv6 + + case 6: return .connectedIpv4 + + case 7: return .connectedIpv6 + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ConnectionStatus, into buf: inout [UInt8]) { + switch value { + + + case .entryGatewayDown: + writeInt(&buf, Int32(1)) + + + case .exitGatewayDownIpv4: + writeInt(&buf, Int32(2)) + + + case .exitGatewayDownIpv6: + writeInt(&buf, Int32(3)) + + + case .exitGatewayRoutingErrorIpv4: + writeInt(&buf, Int32(4)) + + + case .exitGatewayRoutingErrorIpv6: + writeInt(&buf, Int32(5)) + + + case .connectedIpv4: + writeInt(&buf, Int32(6)) + + + case .connectedIpv6: + writeInt(&buf, Int32(7)) + + } + } +} + + +public func FfiConverterTypeConnectionStatus_lift(_ buf: RustBuffer) throws -> ConnectionStatus { + return try FfiConverterTypeConnectionStatus.lift(buf) +} + +public func FfiConverterTypeConnectionStatus_lower(_ value: ConnectionStatus) -> RustBuffer { + return FfiConverterTypeConnectionStatus.lower(value) +} + + + +extension ConnectionStatus: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum ConnectionStatus { +public enum DeviceState { - case entryGatewayDown - case exitGatewayDownIpv4 - case exitGatewayDownIpv6 - case exitGatewayRoutingErrorIpv4 - case exitGatewayRoutingErrorIpv6 - case connectedIpv4 - case connectedIpv6 + case notRegistered + case inactive + case active + case deleteMe } -public struct FfiConverterTypeConnectionStatus: FfiConverterRustBuffer { - typealias SwiftType = ConnectionStatus +public struct FfiConverterTypeDeviceState: FfiConverterRustBuffer { + typealias SwiftType = DeviceState - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ConnectionStatus { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DeviceState { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .entryGatewayDown - - case 2: return .exitGatewayDownIpv4 - - case 3: return .exitGatewayDownIpv6 - - case 4: return .exitGatewayRoutingErrorIpv4 + case 1: return .notRegistered - case 5: return .exitGatewayRoutingErrorIpv6 + case 2: return .inactive - case 6: return .connectedIpv4 + case 3: return .active - case 7: return .connectedIpv6 + case 4: return .deleteMe default: throw UniffiInternalError.unexpectedEnumCase } } - public static func write(_ value: ConnectionStatus, into buf: inout [UInt8]) { + public static func write(_ value: DeviceState, into buf: inout [UInt8]) { switch value { - case .entryGatewayDown: + case .notRegistered: writeInt(&buf, Int32(1)) - case .exitGatewayDownIpv4: + case .inactive: writeInt(&buf, Int32(2)) - case .exitGatewayDownIpv6: + case .active: writeInt(&buf, Int32(3)) - case .exitGatewayRoutingErrorIpv4: + case .deleteMe: writeInt(&buf, Int32(4)) - - case .exitGatewayRoutingErrorIpv6: - writeInt(&buf, Int32(5)) - - - case .connectedIpv4: - writeInt(&buf, Int32(6)) - - - case .connectedIpv6: - writeInt(&buf, Int32(7)) - } } } -public func FfiConverterTypeConnectionStatus_lift(_ buf: RustBuffer) throws -> ConnectionStatus { - return try FfiConverterTypeConnectionStatus.lift(buf) +public func FfiConverterTypeDeviceState_lift(_ buf: RustBuffer) throws -> DeviceState { + return try FfiConverterTypeDeviceState.lift(buf) } -public func FfiConverterTypeConnectionStatus_lower(_ value: ConnectionStatus) -> RustBuffer { - return FfiConverterTypeConnectionStatus.lower(value) +public func FfiConverterTypeDeviceState_lower(_ value: DeviceState) -> RustBuffer { + return FfiConverterTypeDeviceState.lower(value) } -extension ConnectionStatus: Equatable, Hashable {} +extension DeviceState: Equatable, Hashable {} @@ -3149,6 +3956,61 @@ extension MixnetEvent: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum MnemonicState { + + case notStored + case stored +} + + +public struct FfiConverterTypeMnemonicState: FfiConverterRustBuffer { + typealias SwiftType = MnemonicState + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MnemonicState { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .notStored + + case 2: return .stored + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: MnemonicState, into buf: inout [UInt8]) { + switch value { + + + case .notStored: + writeInt(&buf, Int32(1)) + + + case .stored: + writeInt(&buf, Int32(2)) + + } + } +} + + +public func FfiConverterTypeMnemonicState_lift(_ buf: RustBuffer) throws -> MnemonicState { + return try FfiConverterTypeMnemonicState.lift(buf) +} + +public func FfiConverterTypeMnemonicState_lower(_ value: MnemonicState) -> RustBuffer { + return FfiConverterTypeMnemonicState.lower(value) +} + + + +extension MnemonicState: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -3309,6 +4171,75 @@ extension OsPathStatus: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum SubscriptionState { + + case notActive + case pending + case complete + case active +} + + +public struct FfiConverterTypeSubscriptionState: FfiConverterRustBuffer { + typealias SwiftType = SubscriptionState + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SubscriptionState { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .notActive + + case 2: return .pending + + case 3: return .complete + + case 4: return .active + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: SubscriptionState, into buf: inout [UInt8]) { + switch value { + + + case .notActive: + writeInt(&buf, Int32(1)) + + + case .pending: + writeInt(&buf, Int32(2)) + + + case .complete: + writeInt(&buf, Int32(3)) + + + case .active: + writeInt(&buf, Int32(4)) + + } + } +} + + +public func FfiConverterTypeSubscriptionState_lift(_ buf: RustBuffer) throws -> SubscriptionState { + return try FfiConverterTypeSubscriptionState.lift(buf) +} + +public func FfiConverterTypeSubscriptionState_lower(_ value: SubscriptionState) -> RustBuffer { + return FfiConverterTypeSubscriptionState.lower(value) +} + + + +extension SubscriptionState: Equatable, Hashable {} + + + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. @@ -3663,6 +4594,8 @@ public enum VpnError { case OutOfBandwidth case InvalidStateError(details: String ) + case Account(AccountError + ) } @@ -3692,6 +4625,9 @@ public struct FfiConverterTypeVpnError: FfiConverterRustBuffer { case 6: return .InvalidStateError( details: try FfiConverterString.read(from: &buf) ) + case 7: return .Account( + : try FfiConverterTypeAccountError.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -3732,6 +4668,11 @@ public struct FfiConverterTypeVpnError: FfiConverterRustBuffer { writeInt(&buf, Int32(6)) FfiConverterString.write(details, into: &buf) + + case let .Account(): + writeInt(&buf, Int32(7)) + FfiConverterTypeAccountError.write(, into: &buf) + } } } @@ -3762,6 +4703,27 @@ fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { + typealias SwiftType = String? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterString.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterString.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionTypeOSDefaultPathObserver: FfiConverterRustBuffer { typealias SwiftType = OsDefaultPathObserver? @@ -3909,6 +4871,90 @@ fileprivate struct FfiConverterOptionTypeUserAgent: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterOptionTypeAccountState: FfiConverterRustBuffer { + typealias SwiftType = AccountState? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeAccountState.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeAccountState.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeDeviceState: FfiConverterRustBuffer { + typealias SwiftType = DeviceState? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeDeviceState.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeDeviceState.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeMnemonicState: FfiConverterRustBuffer { + typealias SwiftType = MnemonicState? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeMnemonicState.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeMnemonicState.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +fileprivate struct FfiConverterOptionTypeSubscriptionState: FfiConverterRustBuffer { + typealias SwiftType = SubscriptionState? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeSubscriptionState.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeSubscriptionState.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + fileprivate struct FfiConverterOptionSequenceString: FfiConverterRustBuffer { typealias SwiftType = [String]? @@ -4100,6 +5146,28 @@ fileprivate struct FfiConverterSequenceTypeLocation: FfiConverterRustBuffer { } } +fileprivate struct FfiConverterSequenceTypeValidatorDetails: FfiConverterRustBuffer { + typealias SwiftType = [ValidatorDetails] + + public static func write(_ value: [ValidatorDetails], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeValidatorDetails.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ValidatorDetails] { + let len: Int32 = try readInt(&buf) + var seq = [ValidatorDetails]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeValidatorDetails.read(from: &buf)) + } + return seq + } +} + fileprivate struct FfiConverterSequenceTypeIpv4Route: FfiConverterRustBuffer { typealias SwiftType = [Ipv4Route] @@ -4840,6 +5908,19 @@ private func uniffiForeignFutureFree(handle: UInt64) { public func uniffiForeignFutureHandleCountNymVpnLib() -> Int { UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.count } +public func fetchEnvironment(networkName: String)throws -> NetworkEnvironment { + return try FfiConverterTypeNetworkEnvironment.lift(try rustCallWithError(FfiConverterTypeVpnError.lift) { + uniffi_nym_vpn_lib_fn_func_fetchenvironment( + FfiConverterString.lower(networkName),$0 + ) +}) +} +public func getAccountSummary()throws -> AccountStateSummary { + return try FfiConverterTypeAccountStateSummary.lift(try rustCallWithError(FfiConverterTypeVpnError.lift) { + uniffi_nym_vpn_lib_fn_func_getaccountsummary($0 + ) +}) +} public func getGatewayCountries(apiUrl: Url, nymVpnApiUrl: Url?, gwType: GatewayType, userAgent: UserAgent?, minGatewayPerformance: GatewayMinPerformance?)throws -> [Location] { return try FfiConverterSequenceTypeLocation.lift(try rustCallWithError(FfiConverterTypeVpnError.lift) { uniffi_nym_vpn_lib_fn_func_getgatewaycountries( @@ -4879,12 +5960,23 @@ public func removeAccountMnemonic(path: String)throws -> Bool { ) }) } +public func startAccountController(dataDir: String)throws {try rustCallWithError(FfiConverterTypeVpnError.lift) { + uniffi_nym_vpn_lib_fn_func_startaccountcontroller( + FfiConverterString.lower(dataDir),$0 + ) +} +} public func startVpn(config: VpnConfig)throws {try rustCallWithError(FfiConverterTypeVpnError.lift) { uniffi_nym_vpn_lib_fn_func_startvpn( FfiConverterTypeVPNConfig.lower(config),$0 ) } } +public func stopAccountController()throws {try rustCallWithError(FfiConverterTypeVpnError.lift) { + uniffi_nym_vpn_lib_fn_func_stopaccountcontroller($0 + ) +} +} public func stopVpn()throws {try rustCallWithError(FfiConverterTypeVpnError.lift) { uniffi_nym_vpn_lib_fn_func_stopvpn($0 ) @@ -4913,6 +6005,12 @@ private var initializationResult: InitializationResult { if bindings_contract_version != scaffolding_contract_version { return InitializationResult.contractVersionMismatch } + if (uniffi_nym_vpn_lib_checksum_func_fetchenvironment() != 34561) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_nym_vpn_lib_checksum_func_getaccountsummary() != 13465) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_nym_vpn_lib_checksum_func_getgatewaycountries() != 41607) { return InitializationResult.apiChecksumMismatch } @@ -4928,9 +6026,15 @@ private var initializationResult: InitializationResult { if (uniffi_nym_vpn_lib_checksum_func_removeaccountmnemonic() != 51019) { return InitializationResult.apiChecksumMismatch } + if (uniffi_nym_vpn_lib_checksum_func_startaccountcontroller() != 34257) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_nym_vpn_lib_checksum_func_startvpn() != 55890) { return InitializationResult.apiChecksumMismatch } + if (uniffi_nym_vpn_lib_checksum_func_stopaccountcontroller() != 64683) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_nym_vpn_lib_checksum_func_stopvpn() != 59823) { return InitializationResult.apiChecksumMismatch } diff --git a/nym-vpn-core/crates/nym-vpn-network-config/Cargo.toml b/nym-vpn-core/crates/nym-vpn-network-config/Cargo.toml new file mode 100644 index 0000000000..636a241ee7 --- /dev/null +++ b/nym-vpn-core/crates/nym-vpn-network-config/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "nym-vpn-network-config" +version.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +anyhow.workspace = true +reqwest = { workspace = true, default-features = false, features = [ + "blocking", + "rustls-tls", + "json", +] } +nym-config.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio = { workspace = true, features = ["time", "macros"] } +tokio-util.workspace = true +tracing.workspace = true +url = { workspace = true, features = ["serde"] } diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/bootstrap.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/bootstrap.rs similarity index 83% rename from nym-vpn-core/crates/nym-vpnd/src/discovery/bootstrap.rs rename to nym-vpn-core/crates/nym-vpn-network-config/src/bootstrap.rs index ed771167d8..1f86689ad6 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/discovery/bootstrap.rs +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/bootstrap.rs @@ -1,10 +1,10 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use anyhow::Context; -use nym_vpn_lib::nym_config::defaults::NymNetworkDetails; +use nym_config::defaults::NymNetworkDetails; use url::Url; use super::{nym_network::NymNetwork, MAX_FILE_AGE, NETWORKS_SUBDIR}; @@ -15,21 +15,21 @@ const DISCOVERY_FILE: &str = "discovery.json"; const DISCOVERY_WELLKNOWN: &str = "https://nymvpn.com/api/public/v1/.wellknown"; #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] -pub(super) struct Discovery { +pub struct Discovery { pub(super) network_name: String, pub(super) nym_api_url: Url, pub(super) nym_vpn_api_url: Url, } impl Discovery { - fn path(network_name: &str) -> PathBuf { - crate::service::config_dir() + fn path(config_dir: &Path, network_name: &str) -> PathBuf { + config_dir .join(NETWORKS_SUBDIR) .join(format!("{}_{}", network_name, DISCOVERY_FILE)) } - pub(super) fn path_is_stale(network_name: &str) -> anyhow::Result { - if let Some(age) = crate::util::get_age_of_file(&Self::path(network_name))? { + pub(super) fn path_is_stale(config_dir: &Path, network_name: &str) -> anyhow::Result { + if let Some(age) = crate::util::get_age_of_file(&Self::path(config_dir, network_name))? { Ok(age > MAX_FILE_AGE) } else { Ok(true) @@ -45,7 +45,7 @@ impl Discovery { .map_err(Into::into) } - pub(super) fn fetch(network_name: &str) -> anyhow::Result { + pub fn fetch(network_name: &str) -> anyhow::Result { let discovery: DiscoveryResponse = { let url = Self::endpoint(network_name)?; tracing::info!("Fetching nym network discovery from: {}", url); @@ -60,8 +60,8 @@ impl Discovery { discovery.try_into() } - pub(super) fn read_from_file(network_name: &str) -> anyhow::Result { - let path = Self::path(network_name); + pub(super) fn read_from_file(config_dir: &Path, network_name: &str) -> anyhow::Result { + let path = Self::path(config_dir, network_name); tracing::info!("Reading discovery file from: {}", path.display()); let file_str = std::fs::read_to_string(path)?; @@ -69,8 +69,8 @@ impl Discovery { Ok(network) } - pub(super) fn write_to_file(&self) -> anyhow::Result<()> { - let path = Self::path(&self.network_name); + pub(super) fn write_to_file(&self, config_dir: &Path) -> anyhow::Result<()> { + let path = Self::path(config_dir, &self.network_name); tracing::info!("Writing discovery file to: {}", path.display()); // Create parent directories if they don't exist @@ -92,18 +92,18 @@ impl Discovery { Ok(()) } - pub(super) fn ensure_exists(network_name: &str) -> anyhow::Result { + pub(super) fn ensure_exists(config_dir: &Path, network_name: &str) -> anyhow::Result { // Download the file if it doesn't exists, or if the file is too old, refresh it. // TODO: in the future, we should only refresh the discovery file when the tunnel is up. // Probably in a background task. - if Self::path_is_stale(network_name)? { - Self::fetch(network_name)?.write_to_file()?; + if Self::path_is_stale(config_dir, network_name)? { + Self::fetch(network_name)?.write_to_file(config_dir)?; } - Self::read_from_file(network_name) + Self::read_from_file(config_dir, network_name) } - pub(crate) fn fetch_nym_network_details(&self) -> anyhow::Result { + pub fn fetch_nym_network_details(&self) -> anyhow::Result { let url = format!("{}/v1/network/details", self.nym_api_url); tracing::info!("Fetching nym network details from: {}", url); let network_details: NymNetworkDetailsResponse = reqwest::blocking::get(&url) diff --git a/nym-vpn-core/crates/nym-vpn-network-config/src/lib.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/lib.rs new file mode 100644 index 0000000000..4ba86c0c2c --- /dev/null +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/lib.rs @@ -0,0 +1,75 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +mod bootstrap; +mod nym_network; +mod nym_vpn_network; +mod refresh; +mod util; + +pub use nym_network::NymNetwork; +pub use nym_vpn_network::NymVpnNetwork; + +use bootstrap::Discovery; +use nym_config::defaults::NymNetworkDetails; + +use std::{path::Path, time::Duration}; + +const NETWORKS_SUBDIR: &str = "networks"; + +// Refresh the discovery and network details files periodically +const MAX_FILE_AGE: Duration = Duration::from_secs(60 * 60 * 24); + +#[derive(Clone, Debug)] +pub struct Network { + pub nym_network: NymNetwork, + pub nym_vpn_network: NymVpnNetwork, +} + +impl Network { + pub fn nym_network_details(&self) -> &NymNetworkDetails { + &self.nym_network.network + } + + pub fn export_to_env(&self) { + self.nym_network.export_to_env(); + self.nym_vpn_network.export_to_env(); + } + + pub fn fetch(network_name: &str) -> anyhow::Result { + let discovery = Discovery::fetch(network_name)?; + let nym_network = discovery.fetch_nym_network_details()?; + let nym_vpn_network = NymVpnNetwork::from(discovery); + + Ok(Network { + nym_network, + nym_vpn_network, + }) + } +} + +pub fn discover_env(config_path: &Path, network_name: &str) -> anyhow::Result { + // Lookup network discovery to bootstrap + let discovery = Discovery::ensure_exists(config_path, network_name)?; + + // Using discovery, fetch and setup nym network details + let nym_network = NymNetwork::ensure_exists(config_path, &discovery)?; + + // Using discovery, setup nym vpn network details + let nym_vpn_network = NymVpnNetwork::from(discovery); + + Ok(Network { + nym_network, + nym_vpn_network, + }) +} + +pub fn manual_env(network_details: &NymNetworkDetails) -> anyhow::Result { + let nym_network = NymNetwork::from(network_details.clone()); + let nym_vpn_network = NymVpnNetwork::try_from(network_details)?; + + Ok(Network { + nym_network, + nym_vpn_network, + }) +} diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/nym_network.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/nym_network.rs similarity index 80% rename from nym-vpn-core/crates/nym-vpnd/src/discovery/nym_network.rs rename to nym-vpn-core/crates/nym-vpn-network-config/src/nym_network.rs index 28905a198e..abb64cdc8d 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/discovery/nym_network.rs +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/nym_network.rs @@ -1,44 +1,47 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use std::{env, path::PathBuf}; +use std::{ + env, + path::{Path, PathBuf}, +}; use anyhow::Context; -use nym_vpn_lib::nym_config::defaults::{var_names, NymNetworkDetails}; +use nym_config::defaults::{var_names, NymNetworkDetails}; use super::{bootstrap::Discovery, MAX_FILE_AGE, NETWORKS_SUBDIR}; #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] -pub(crate) struct NymNetwork { - pub(crate) network: NymNetworkDetails, +pub struct NymNetwork { + pub network: NymNetworkDetails, } impl NymNetwork { - fn path(network_name: &str) -> PathBuf { - crate::service::config_dir() + fn path(config_dir: &Path, network_name: &str) -> PathBuf { + config_dir .join(NETWORKS_SUBDIR) .join(format!("{}.json", network_name)) } - fn path_is_stale(network_name: &str) -> anyhow::Result { - if let Some(age) = crate::util::get_age_of_file(&Self::path(network_name))? { + fn path_is_stale(config_dir: &Path, network_name: &str) -> anyhow::Result { + if let Some(age) = crate::util::get_age_of_file(&Self::path(config_dir, network_name))? { Ok(age > MAX_FILE_AGE) } else { Ok(true) } } - pub(super) fn read_from_file(network_name: &str) -> anyhow::Result { - let path = Self::path(network_name); + pub(super) fn read_from_file(config_dir: &Path, network_name: &str) -> anyhow::Result { + let path = Self::path(config_dir, network_name); tracing::info!("Reading network details from: {}", path.display()); let file_str = std::fs::read_to_string(path)?; let network: NymNetworkDetails = serde_json::from_str(&file_str)?; Ok(Self { network }) } - pub(super) fn write_to_file(&self) -> anyhow::Result<()> { + pub(super) fn write_to_file(&self, config_dir: &Path) -> anyhow::Result<()> { let network = &self.network; - let path = Self::path(&network.network_name); + let path = Self::path(config_dir, &network.network_name); // Create parent directories if they don't exist if let Some(parent) = path.parent() { @@ -59,11 +62,13 @@ impl NymNetwork { Ok(()) } - pub(super) fn ensure_exists(discovery: &Discovery) -> anyhow::Result { - if Self::path_is_stale(&discovery.network_name)? { - discovery.fetch_nym_network_details()?.write_to_file()?; + pub(super) fn ensure_exists(config_dir: &Path, discovery: &Discovery) -> anyhow::Result { + if Self::path_is_stale(config_dir, &discovery.network_name)? { + discovery + .fetch_nym_network_details()? + .write_to_file(config_dir)?; } - Self::read_from_file(&discovery.network_name) + Self::read_from_file(config_dir, &discovery.network_name) } pub(super) fn export_to_env(&self) { diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/nym_vpn_network.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/nym_vpn_network.rs similarity index 87% rename from nym-vpn-core/crates/nym-vpnd/src/discovery/nym_vpn_network.rs rename to nym-vpn-core/crates/nym-vpn-network-config/src/nym_vpn_network.rs index 62797b0376..db2e84b570 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/discovery/nym_vpn_network.rs +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/nym_vpn_network.rs @@ -3,14 +3,14 @@ use std::env; -use nym_vpn_lib::nym_config::defaults::{var_names, NymNetworkDetails}; +use nym_config::defaults::{var_names, NymNetworkDetails}; use url::Url; use super::bootstrap::Discovery; #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] -pub(crate) struct NymVpnNetwork { - pub(super) nym_vpn_api_url: Url, +pub struct NymVpnNetwork { + pub nym_vpn_api_url: Url, } impl NymVpnNetwork { diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/refresh.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/refresh.rs similarity index 71% rename from nym-vpn-core/crates/nym-vpnd/src/discovery/refresh.rs rename to nym-vpn-core/crates/nym-vpn-network-config/src/refresh.rs index cb3fa7f409..517b9b49b3 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/discovery/refresh.rs +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/refresh.rs @@ -1,24 +1,28 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use std::time::Duration; +use std::{ + path::{Path, PathBuf}, + time::Duration, +}; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; use super::bootstrap::Discovery; -fn refresh_discovery_file(network_name: &str) -> anyhow::Result<()> { - if !Discovery::path_is_stale(network_name)? { +fn refresh_discovery_file(config_dir: &Path, network_name: &str) -> anyhow::Result<()> { + if !Discovery::path_is_stale(config_dir, network_name)? { return Ok(()); } - Discovery::fetch(network_name)?.write_to_file()?; + Discovery::fetch(network_name)?.write_to_file(config_dir)?; Ok(()) } // Ideally we only refresh the discovery file when the tunnel is up #[allow(unused)] pub(crate) async fn start_background_discovery_refresh( + config_path: PathBuf, network_name: String, cancel_token: CancellationToken, ) -> JoinHandle<()> { @@ -30,7 +34,7 @@ pub(crate) async fn start_background_discovery_refresh( loop { tokio::select! { _ = interval.tick() => { - if let Err(err) = refresh_discovery_file(&network_name) { + if let Err(err) = refresh_discovery_file(&config_path, &network_name) { tracing::error!("Failed to refresh discovery file: {:?}", err); } } diff --git a/nym-vpn-core/crates/nym-vpn-network-config/src/util.rs b/nym-vpn-core/crates/nym-vpn-network-config/src/util.rs new file mode 100644 index 0000000000..5a8c6a4c05 --- /dev/null +++ b/nym-vpn-core/crates/nym-vpn-network-config/src/util.rs @@ -0,0 +1,12 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use std::{path::PathBuf, time::Duration}; + +pub(crate) fn get_age_of_file(file_path: &PathBuf) -> anyhow::Result> { + if !file_path.exists() { + return Ok(None); + } + let metadata = std::fs::metadata(file_path)?; + Ok(Some(metadata.modified()?.elapsed()?)) +} diff --git a/nym-vpn-core/crates/nym-vpnd/Cargo.toml b/nym-vpn-core/crates/nym-vpnd/Cargo.toml index 0ed2233fb7..42c7b957ac 100644 --- a/nym-vpn-core/crates/nym-vpnd/Cargo.toml +++ b/nym-vpn-core/crates/nym-vpnd/Cargo.toml @@ -52,6 +52,7 @@ nym-validator-client.workspace = true nym-vpn-account-controller = { path = "../nym-vpn-account-controller" } nym-vpn-api-client = { path = "../nym-vpn-api-client" } nym-vpn-lib = { path = "../nym-vpn-lib" } +nym-vpn-network-config = { path = "../nym-vpn-network-config" } nym-vpn-proto = { path = "../nym-vpn-proto" } nym-vpn-store = { path = "../nym-vpn-store" } diff --git a/nym-vpn-core/crates/nym-vpnd/src/command_interface/protobuf/info_response.rs b/nym-vpn-core/crates/nym-vpnd/src/command_interface/protobuf/info_response.rs index 8b7c947121..e720a3c135 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/command_interface/protobuf/info_response.rs +++ b/nym-vpn-core/crates/nym-vpnd/src/command_interface/protobuf/info_response.rs @@ -9,13 +9,8 @@ impl From for InfoResponse { fn from(info: VpnServiceInfo) -> Self { let build_timestamp = info.build_timestamp.map(offset_datetime_to_timestamp); - let endpoints = info - .endpoints - .into_iter() - .map(validator_details_to_endpoints) - .collect(); - - let nym_vpn_api_url = info.nym_vpn_api_url.map(string_to_url); + let nym_network = Some(to_nym_network_details(info.nym_network.clone())); + let nym_vpn_network = Some(to_nym_vpn_network_details(info.nym_vpn_network.clone())); InfoResponse { version: info.version, @@ -23,13 +18,69 @@ impl From for InfoResponse { triple: info.triple, platform: info.platform, git_commit: info.git_commit, - network_name: info.network_name, - endpoints, - nym_vpn_api_url, + nym_network, + nym_vpn_network, } } } +fn to_nym_network_details( + nym_network: nym_vpn_network_config::NymNetwork, +) -> nym_vpn_proto::NymNetworkDetails { + nym_vpn_proto::NymNetworkDetails { + network_name: nym_network.network.network_name, + chain_details: Some(to_chain_details(nym_network.network.chain_details)), + endpoints: nym_network + .network + .endpoints + .into_iter() + .map(validator_details_to_endpoints) + .collect(), + contracts: Some(to_nym_contracts(nym_network.network.contracts)), + } +} + +fn to_chain_details( + chain_details: nym_vpn_lib::nym_config::defaults::ChainDetails, +) -> nym_vpn_proto::ChainDetails { + nym_vpn_proto::ChainDetails { + bech32_account_prefix: chain_details.bech32_account_prefix, + mix_denom: Some(to_denom_details(chain_details.mix_denom)), + stake_denom: Some(to_denom_details(chain_details.stake_denom)), + } +} + +fn to_denom_details( + denom_details: nym_vpn_lib::nym_config::defaults::DenomDetailsOwned, +) -> nym_vpn_proto::DenomDetails { + nym_vpn_proto::DenomDetails { + base: denom_details.base, + display: denom_details.display, + display_exponent: denom_details.display_exponent, + } +} + +fn to_nym_contracts( + contracts: nym_vpn_lib::nym_config::defaults::NymContracts, +) -> nym_vpn_proto::NymContracts { + nym_vpn_proto::NymContracts { + mixnet_contract_address: contracts.mixnet_contract_address, + vesting_contract_address: contracts.vesting_contract_address, + ecash_contract_address: contracts.ecash_contract_address, + group_contract_address: contracts.group_contract_address, + multisig_contract_address: contracts.multisig_contract_address, + coconut_dkg_contract_address: contracts.coconut_dkg_contract_address, + } +} + +fn to_nym_vpn_network_details( + nym_vpn_network: nym_vpn_network_config::NymVpnNetwork, +) -> nym_vpn_proto::NymVpnNetworkDetails { + nym_vpn_proto::NymVpnNetworkDetails { + nym_vpn_api_url: Some(string_to_url(nym_vpn_network.nym_vpn_api_url.to_string())), + } +} + fn offset_datetime_to_timestamp(datetime: time::OffsetDateTime) -> prost_types::Timestamp { prost_types::Timestamp { seconds: datetime.unix_timestamp(), @@ -39,8 +90,8 @@ fn offset_datetime_to_timestamp(datetime: time::OffsetDateTime) -> prost_types:: fn validator_details_to_endpoints( validator_details: nym_vpn_lib::nym_config::defaults::ValidatorDetails, -) -> nym_vpn_proto::Endpoints { - nym_vpn_proto::Endpoints { +) -> nym_vpn_proto::ValidatorDetails { + nym_vpn_proto::ValidatorDetails { nyxd_url: Some(string_to_url(validator_details.nyxd_url)), websocket_url: validator_details.websocket_url.map(string_to_url), api_url: validator_details.api_url.map(string_to_url), diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/global_config.rs b/nym-vpn-core/crates/nym-vpnd/src/config.rs similarity index 100% rename from nym-vpn-core/crates/nym-vpnd/src/discovery/global_config.rs rename to nym-vpn-core/crates/nym-vpnd/src/config.rs diff --git a/nym-vpn-core/crates/nym-vpnd/src/discovery/mod.rs b/nym-vpn-core/crates/nym-vpnd/src/discovery/mod.rs deleted file mode 100644 index 12a8bc2295..0000000000 --- a/nym-vpn-core/crates/nym-vpnd/src/discovery/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2024 - Nym Technologies SA -// SPDX-License-Identifier: GPL-3.0-only - -mod bootstrap; -mod global_config; -mod nym_network; -mod nym_vpn_network; -mod refresh; - -pub(crate) use global_config::GlobalConfigFile; - -use bootstrap::Discovery; -use nym_network::NymNetwork; -use nym_vpn_lib::nym_config::defaults::NymNetworkDetails; -use nym_vpn_network::NymVpnNetwork; - -use std::time::Duration; - -const NETWORKS_SUBDIR: &str = "networks"; - -// Refresh the discovery and network details files periodically -const MAX_FILE_AGE: Duration = Duration::from_secs(60 * 60 * 24); - -#[derive(Clone, Debug)] -pub(crate) struct Network { - #[allow(unused)] - pub(crate) nym_network: NymNetwork, - #[allow(unused)] - pub(crate) nym_vpn_network: NymVpnNetwork, -} - -pub(crate) fn discover_env(network_name: &str) -> anyhow::Result { - // Lookup network discovery to bootstrap - let discovery = Discovery::ensure_exists(network_name)?; - - // Using discovery, fetch and setup nym network details - let nym_network = NymNetwork::ensure_exists(&discovery)?; - nym_network.export_to_env(); - crate::set_global_network_details(nym_network.network.clone())?; - - // Using discovery, setup nym vpn network details - let nym_vpn_network = NymVpnNetwork::from(discovery); - nym_vpn_network.export_to_env(); - - Ok(Network { - nym_network, - nym_vpn_network, - }) -} - -pub(crate) fn manual_env(network_details: &NymNetworkDetails) -> anyhow::Result { - let nym_network = NymNetwork::from(network_details.clone()); - nym_network.export_to_env(); - crate::set_global_network_details(network_details.clone())?; - - let nym_vpn_network = NymVpnNetwork::try_from(network_details)?; - nym_vpn_network.export_to_env(); - - Ok(Network { - nym_network, - nym_vpn_network, - }) -} diff --git a/nym-vpn-core/crates/nym-vpnd/src/environment.rs b/nym-vpn-core/crates/nym-vpnd/src/environment.rs new file mode 100644 index 0000000000..7a4b8c693c --- /dev/null +++ b/nym-vpn-core/crates/nym-vpnd/src/environment.rs @@ -0,0 +1,34 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use nym_vpn_lib::nym_config::defaults::NymNetworkDetails; +use nym_vpn_network_config::Network; + +use crate::{cli::CliArgs, config::GlobalConfigFile, GLOBAL_NETWORK_DETAILS}; + +fn set_global_network_details(network_details: Network) -> anyhow::Result<()> { + GLOBAL_NETWORK_DETAILS + .set(network_details) + .map_err(|_| anyhow::anyhow!("Failed to set network details")) +} + +pub(crate) fn setup_environment( + global_config_file: &GlobalConfigFile, + args: &CliArgs, +) -> anyhow::Result { + let network_env = if let Some(ref env) = args.config_env_file { + nym_vpn_lib::nym_config::defaults::setup_env(Some(env)); + let network_details = NymNetworkDetails::new_from_env(); + nym_vpn_network_config::manual_env(&network_details)? + } else { + let network_name = global_config_file.network_name.clone(); + let config_path = crate::service::config_dir(); + tracing::info!("Setting up environment by discovering the network: {network_name}"); + nym_vpn_network_config::discover_env(&config_path, &network_name)? + }; + + // TODO: pass network_env explicitly instead of relying on being exported to env + network_env.export_to_env(); + set_global_network_details(network_env.clone())?; + Ok(network_env) +} diff --git a/nym-vpn-core/crates/nym-vpnd/src/main.rs b/nym-vpn-core/crates/nym-vpnd/src/main.rs index 1b3cc7a607..8a8f447109 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/main.rs +++ b/nym-vpn-core/crates/nym-vpnd/src/main.rs @@ -3,7 +3,8 @@ mod cli; mod command_interface; -mod discovery; +mod config; +mod environment; mod logging; mod runtime; mod service; @@ -16,30 +17,24 @@ mod windows_service; use std::sync::OnceLock; use clap::Parser; -use nym_vpn_lib::nym_config::defaults::NymNetworkDetails; +use nym_vpn_network_config::Network; use service::NymVpnService; use tokio::sync::broadcast; use tokio_util::sync::CancellationToken; -use crate::{cli::CliArgs, command_interface::CommandInterfaceOptions}; +use crate::{cli::CliArgs, command_interface::CommandInterfaceOptions, config::GlobalConfigFile}; // Lazy initialized global NymNetworkDetails -static GLOBAL_NETWORK_DETAILS: OnceLock = OnceLock::new(); +static GLOBAL_NETWORK_DETAILS: OnceLock = OnceLock::new(); fn main() -> anyhow::Result<()> { run() } -fn set_global_network_details(network_details: NymNetworkDetails) -> anyhow::Result<()> { - GLOBAL_NETWORK_DETAILS - .set(network_details) - .map_err(|_| anyhow::anyhow!("Failed to set network details")) -} - #[cfg(unix)] fn run() -> anyhow::Result<()> { let args = CliArgs::parse(); - let mut global_config_file = discovery::GlobalConfigFile::read_from_file()?; + let mut global_config_file = GlobalConfigFile::read_from_file()?; if let Some(ref network) = args.network { global_config_file.network_name = network.to_owned(); @@ -48,17 +43,7 @@ fn run() -> anyhow::Result<()> { logging::setup_logging(args.command.run_as_service); - let _network_env = if let Some(ref env) = args.config_env_file { - nym_vpn_lib::nym_config::defaults::setup_env(Some(env)); - let network_details = NymNetworkDetails::new_from_env(); - discovery::manual_env(&network_details)? - } else { - let network_name = global_config_file.network_name.clone(); - tracing::info!("Setting up environment by discovering the network: {network_name}"); - discovery::discover_env(&network_name)? - }; - - // TODO: pass network_env explicitly instead of relying on being exported to env + let _ = environment::setup_environment(&global_config_file, &args)?; run_inner(args) } @@ -66,22 +51,14 @@ fn run() -> anyhow::Result<()> { #[cfg(windows)] fn run() -> anyhow::Result<()> { let args = CliArgs::parse(); - let mut global_config_file = discovery::GlobalConfigFile::read_from_file()?; + let mut global_config_file = GlobalConfigFile::read_from_file()?; if let Some(ref network) = args.network { global_config_file.network_name = network.to_owned(); global_config_file.write_to_file()?; } - let _network_env = if let Some(ref env) = args.config_env_file { - nym_vpn_lib::nym_config::defaults::setup_env(Some(env)); - let network_details = NymNetworkDetails::new_from_env(); - discovery::manual_env(&network_details)?; - } else { - let network_name = global_config_file.network_name.clone(); - tracing::info!("Setting up environment from discovery file: {network_name}"); - discovery::discover_env(&network_name)?; - }; + let _ = environment::setup_environment(&global_config_file, &args)?; if args.command.is_any() { Ok(windows_service::start(args)?) diff --git a/nym-vpn-core/crates/nym-vpnd/src/service/vpn_service.rs b/nym-vpn-core/crates/nym-vpnd/src/service/vpn_service.rs index ef1e25c6f8..f3c2845fd1 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/service/vpn_service.rs +++ b/nym-vpn-core/crates/nym-vpnd/src/service/vpn_service.rs @@ -9,6 +9,7 @@ use std::{ }; use bip39::Mnemonic; +use nym_vpn_network_config::{NymNetwork, NymVpnNetwork}; use serde::{Deserialize, Serialize}; use time::format_description::well_known::Rfc3339; use tokio::{ @@ -37,7 +38,7 @@ use nym_vpn_lib::{ }; use nym_vpn_store::keys::KeyStore as _; -use crate::GLOBAL_NETWORK_DETAILS; +use crate::{config::GlobalConfigFile, GLOBAL_NETWORK_DETAILS}; use super::{ config::{ConfigSetupError, NetworkEnvironments, NymVpnServiceConfig, DEFAULT_CONFIG_FILE}, @@ -252,9 +253,8 @@ pub struct VpnServiceInfo { pub triple: String, pub platform: String, pub git_commit: String, - pub network_name: String, - pub endpoints: Vec, - pub nym_vpn_api_url: Option, + pub nym_network: NymNetwork, + pub nym_vpn_network: NymVpnNetwork, } impl fmt::Display for VpnServiceStatus { @@ -414,7 +414,7 @@ impl NymVpnService { .get() .ok_or(Error::ConfigSetup(ConfigSetupError::GlobalNetworkNotSet))? .clone(); - let network_name = network_details.network_name.clone(); + let network_name = network_details.nym_network_details().network_name.clone(); let config_dir = super::config::config_dir().join(&network_name); let config_file = config_dir.join(DEFAULT_CONFIG_FILE); @@ -762,7 +762,11 @@ where } async fn handle_info(&self) -> VpnServiceInfo { - let network = NymNetworkDetails::new_from_env(); + // TODO: remove expect + let network = GLOBAL_NETWORK_DETAILS + .get() + .expect("Incorrect environment setup") + .clone(); let bin_info = nym_bin_common::bin_info_local_vergen!(); let user_agent = crate::util::construct_user_agent(); @@ -772,19 +776,15 @@ where triple: bin_info.cargo_triple.to_string(), platform: user_agent.platform, git_commit: bin_info.commit_sha.to_string(), - network_name: network.network_name, - endpoints: network.endpoints, - nym_vpn_api_url: network.nym_vpn_api_url, + nym_network: network.nym_network.clone(), + nym_vpn_network: network.nym_vpn_network.clone(), } } async fn handle_set_network(&self, network: String) -> Result<(), SetNetworkError> { - // let mut global_config = crate::discovery::read_global_config_file().map_err(|source| { let mut global_config = - crate::discovery::GlobalConfigFile::read_from_file().map_err(|source| { - SetNetworkError::ReadConfig { - source: source.into(), - } + GlobalConfigFile::read_from_file().map_err(|source| SetNetworkError::ReadConfig { + source: source.into(), })?; // Manually restrict the set of possible network, until we handle this automatically @@ -792,7 +792,6 @@ where .map_err(|_err| SetNetworkError::NetworkNotFound(network.to_owned()))?; global_config.network_name = network_selected.to_string(); - // crate::discovery::write_global_config_file(global_config).map_err(|source| { global_config .write_to_file() .map_err(|source| SetNetworkError::WriteConfig { diff --git a/nym-vpn-core/crates/nym-vpnd/src/util.rs b/nym-vpn-core/crates/nym-vpnd/src/util.rs index 046a3b8638..01f3ecbf4b 100644 --- a/nym-vpn-core/crates/nym-vpnd/src/util.rs +++ b/nym-vpn-core/crates/nym-vpnd/src/util.rs @@ -1,8 +1,6 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use std::{path::PathBuf, time::Duration}; - pub(crate) fn construct_user_agent() -> nym_vpn_lib::UserAgent { let bin_info = nym_bin_common::bin_info_local_vergen!(); let name = sysinfo::System::name().unwrap_or("unknown".to_string()); @@ -16,11 +14,3 @@ pub(crate) fn construct_user_agent() -> nym_vpn_lib::UserAgent { git_commit: bin_info.commit_sha.to_string(), } } - -pub(crate) fn get_age_of_file(file_path: &PathBuf) -> anyhow::Result> { - if !file_path.exists() { - return Ok(None); - } - let metadata = std::fs::metadata(file_path)?; - Ok(Some(metadata.modified()?.elapsed()?)) -} diff --git a/proto/nym/vpn.proto b/proto/nym/vpn.proto index 39aba322e8..e69fd75970 100644 --- a/proto/nym/vpn.proto +++ b/proto/nym/vpn.proto @@ -92,7 +92,39 @@ message UserAgent { string git_commit = 4; } -message Endpoints { +message DenomDetails { + string base = 1; + string display = 2; + uint32 display_exponent = 3; +} + +message ChainDetails { + string bech32_account_prefix = 1; + DenomDetails mix_denom = 2; + DenomDetails stake_denom = 3; +} + +message NymContracts { + optional string mixnet_contract_address = 1; + optional string vesting_contract_address = 2; + optional string ecash_contract_address = 3; + optional string group_contract_address = 4; + optional string multisig_contract_address = 5; + optional string coconut_dkg_contract_address = 6; +} + +message NymNetworkDetails { + string network_name = 1; + ChainDetails chain_details = 2; + repeated ValidatorDetails endpoints = 3; + NymContracts contracts = 4; +} + +message NymVpnNetworkDetails { + Url nym_vpn_api_url = 1; +} + +message ValidatorDetails { Url nyxd_url = 1; Url websocket_url = 2; Url api_url = 3; @@ -104,11 +136,10 @@ message InfoResponse { string version = 1; google.protobuf.Timestamp build_timestamp = 2; string triple = 3; - string platform = 8; - string git_commit = 4; - string network_name = 5; - repeated Endpoints endpoints = 6; - Url nym_vpn_api_url = 7; + string platform = 4; + string git_commit = 5; + NymNetworkDetails nym_network = 6; + NymVpnNetworkDetails nym_vpn_network = 7; } message SetNetworkRequest { diff --git a/wireguard/build-wireguard-go.sh b/wireguard/build-wireguard-go.sh index 7a0aaba008..30d5a2f428 100755 --- a/wireguard/build-wireguard-go.sh +++ b/wireguard/build-wireguard-go.sh @@ -122,11 +122,11 @@ function build_windows { if is_win_arm64 $@; then local arch="aarch64" export GOARCH=arm64 - export CC="/clangarm64/bin/aarch64-w64-mingw32-cc" + export CC="aarch64-w64-mingw32-cc" else local arch="x86_64" export GOARCH=amd64 - export CC="/mingw64/bin/x86_64-w64-mingw32-cc" + export CC="x86_64-w64-mingw32-cc" fi echo "Building wireguard-go for Windows ($arch)"