Compare commits

..

No commits in common. "main" and "v0.4.3" have entirely different histories.
main ... v0.4.3

233 changed files with 6434 additions and 26874 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.4.7+0
current_version = 0.4.3+0
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\+(?P<buildcode>\d+)

2
.gitignore vendored
View File

@ -5,11 +5,9 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related

View File

@ -3,122 +3,75 @@
stages:
- build
- build_flatpak
# - test
#.macos_saas_runners:
# tags:
# - saas-macos-medium-m1
# image: macos-12-xcode-14
# before_script:
# - echo "started by ${GITLAB_USER_NAME}"
.macos_saas_runners:
tags:
- saas-macos-medium-m1
image: macos-12-xcode-14
before_script:
- echo "started by ${GITLAB_USER_NAME}"
#build_macos:
# extends:
# - .macos_saas_runners
# stage: build
# script:
# - echo "place holder for build"
# - sudo softwareupdate --install-rosetta --agree-to-license
# - git clone https://gitlab.com/veilid/veilid.git ../veilid
build_macos:
extends:
- .macos_saas_runners
stage: build
script:
- echo "place holder for build"
- sudo softwareupdate --install-rosetta --agree-to-license
- git clone https://gitlab.com/veilid/veilid.git ../veilid
#- curl proto =https tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
#- source "$HOME/.cargo/env"
#- brew install capnp cmake wabt llvm protobuf openjdk@17 jq cocoapods
#- cargo install wasm-bindgen-cli wasm-pack cargo-edit
# - wget https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_arm64_3.13.5-stable.zip
# - unzip flutter_macos_arm64_3.13.5-stable.zip && export PATH="$PATH:`pwd`/flutter/bin"
# - flutter upgrade
# - yes | flutter doctor --android-licenses
# - flutter config --enable-macos-desktop --enable-ios
# - flutter config --no-analytics
# - dart --disable-analytics
# - flutter doctor -v
- wget https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_arm64_3.13.5-stable.zip
- unzip flutter_macos_arm64_3.13.5-stable.zip && export PATH="$PATH:`pwd`/flutter/bin"
- flutter upgrade
- yes | flutter doctor --android-licenses
- flutter config --enable-macos-desktop --enable-ios
- flutter config --no-analytics
- dart --disable-analytics
- flutter doctor -v
#- flutter build ipa
#- flutter build appbundle
# only:
# - schedules
when: manual
build_linux_amd64_bundle:
stage: build
tags:
- saas-linux-medium-amd64
image: ghcr.io/cirruslabs/flutter:3.29.2
image: ghcr.io/cirruslabs/flutter:3.19.4
stage: build
script:
- apt-get update
- apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev lcov rustup
- rustup toolchain install 1.81 --profile minimal --no-self-update
- apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev lcov rustc cargo
- flutter config --enable-linux-desktop
- git clone https://gitlab.com/veilid/veilid.git ../veilid
- flutter build linux
artifacts:
paths:
- build/linux/x64/release/bundle/
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
when: manual
build_linux_amd64_flatpak:
tags:
- saas-linux-small-amd64
image: ubuntu:24.04
stage: build
image: ubuntu:23.04
stage: build_flatpak
dependencies: [build_linux_amd64_bundle]
needs:
- job: build_linux_amd64_bundle
artifacts: true
script:
- apt-get update
- apt-get install -y --no-install-recommends flatpak flatpak-builder gnupg2 elfutils ca-certificates
- flatpak remote-add --no-gpg-verify --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
- flatpak install -y --noninteractive org.gnome.Sdk/x86_64/46 org.gnome.Platform/x86_64/46 app/org.flathub.flatpak-external-data-checker/x86_64/stable org.freedesktop.appstream-glib
- flatpak install -y --noninteractive org.gnome.Sdk/x86_64/45 org.gnome.Platform/x86_64/45 app/org.flathub.flatpak-external-data-checker/x86_64/stable org.freedesktop.appstream-glib
- pushd flatpak/
- flatpak-builder --force-clean build-dir com.veilid.veilidchat.yml --repo=repo
- flatpak build-bundle repo com.veilid.veilidchat.flatpak com.veilid.veilidchat
- popd
artifacts:
paths:
paths:
- flatpak/com.veilid.veilidchat.flatpak
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
build_linux_arm64_bundle:
stage: build
tags:
- saas-linux-small-arm64
image: ghcr.io/cirruslabs/flutter:3.29.2
script:
- apt-get update
- apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev lcov rustup
- rustup toolchain install 1.81 --profile minimal --no-self-update
- flutter config --enable-linux-desktop
- git clone https://gitlab.com/veilid/veilid.git ../veilid
- flutter build linux
artifacts:
paths:
- build/linux/arm64/release/bundle/
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
build_linux_arm64_flatpak:
tags:
- saas-linux-small-arm64
image: ubuntu:24.04
stage: build
dependencies: [build_linux_arm64_bundle]
needs:
- job: build_linux_arm64_bundle
artifacts: true
script:
- apt-get update
- apt-get install -y --no-install-recommends flatpak flatpak-builder gnupg2 elfutils ca-certificates
- flatpak remote-add --no-gpg-verify --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
- flatpak install -y --noninteractive org.gnome.Sdk/aarch64/46 org.gnome.Platform/aarch64/46 app/org.flathub.flatpak-external-data-checker/aarch64/stable org.freedesktop.appstream-glib
- pushd flatpak/
- flatpak-builder --force-clean build-dir com.veilid.veilidchat.arm64.yml --repo=repo
- flatpak build-bundle repo com.veilid.veilidchat.flatpak com.veilid.veilidchat
- popd
artifacts:
paths:
- flatpak/com.veilid.veilidchat.flatpak
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
when: manual
#test:
# extends:

View File

@ -1,21 +0,0 @@
First, please search through the existing issues on GitLab ***and*** read our [known issues](https://veilid.com/chat/knownissues) page before opening a new issue.
Please provide the following information to the best of your ability:
## Platform in use (Apple or Android)
## Network type (Wifi or Cell)
### If you know it, what type of NAT?
## Paste in relevant logs
1. Long press the signal meter in VeilidChat to open the console logs
2. Switch the logs to debug
3. Make the issue happen again
4. Go back into the logs and hit the copy all button
5. Paste the logs somewhere you can make edits -- remove all IPs (v4 and v6)
6. Paste or attach that redacted log here
## Description of the issue

View File

@ -1,37 +1,8 @@
## v0.4.7 ##
- *Community Contributions*
- Fix getting stuck on splash screen when veilid is already started @bmv437 / @bgrift
- Fix routing to home after initial account creation @bmv437 / @bgrift
- edit_account_form visual improvements @bmv437 / @bgrift
- Flatpak CI Update @sajattack
- Build Arm64 flatpaks @sajattack
- Dependency updates
## v0.4.6 ##
- Updated veilid-core to v0.4.4
- See Veilid changelog for specifics
- UI improvements: Theme fixes, wallpaper option added
- Responsiveness improved
- Contacts workflow more consistent
- Safe-area fixes
- Make layout more mobile-friendly
- Improved contact invitation menus
- Deadlock fixes in veilid_support
- _pollWatch was degenerate and only watched first subkey
## v0.4.5 ##
- Updated veilid-core to v0.4.1
- See Veilid changelog for specifics
- DHT speed and reliability improvements
## v0.4.4 ##
- Update beta dialog with expectations page
- Temporarily disable relay selection aggressiveness
## v0.4.3 ##
- Flutter upgrade to 3.24.0
- Contacts UI cleanup
- Incorporate symmetric NAT fix from veilid-core
- Initial public beta release
## v0.4.2 ##
- Dialogs cleanup

View File

@ -1 +0,0 @@
.cxx

View File

@ -1,9 +1,3 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@ -12,6 +6,11 @@ if (localPropertiesFile.exists()) {
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
@ -22,6 +21,10 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def buildConfig = 'debug'
def keystoreProperties = new Properties()
@ -32,16 +35,16 @@ if (keystorePropertiesFile.exists()) {
}
android {
ndkVersion "27.0.12077973"
ndkVersion "26.3.11579264"
compileSdkVersion flutter.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '17'
jvmTarget = '1.8'
}
sourceSets {
@ -67,7 +70,7 @@ android {
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
shrinkResources false
@ -79,7 +82,7 @@ android {
}
}
}
namespace 'com.veilid.veilidchat'
}
@ -87,4 +90,6 @@ flutter {
source '../..'
}
dependencies {}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

View File

@ -1,3 +1,16 @@
buildscript {
ext.kotlin_version = '1.9.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip

View File

@ -1,25 +1,11 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
include ':app'
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.8.0" apply false
id "org.jetbrains.kotlin.android" version "1.9.25" apply false
}
include ":app"
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

View File

@ -13,7 +13,7 @@
},
"splash": {
"beta_title": "VeilidChat is BETA SOFTWARE",
"beta_text": "DO NOT USE THIS FOR ANYTHING IMPORTANT\n\nUntil 1.0 is released:\n\n• You should have no expectations of actual privacy, or guarantees of security.\n• You will likely lose accounts, contacts, and messages and need to recreate them.\n\nTo know what to expect, review our known issues located here:\n\n"
"beta_text": "DO NOT USE THIS FOR ANYTHING IMPORTANT\n\nUntil 1.0 is released:\n\n• You should have no expectations of actual privacy, or guarantees of security.\n• You will likely lose accounts, contacts, and messages and need to recreate them.\n\nPlease read our BETA PARTICIPATION GUIDE located here:\n\n"
},
"account": {
"form_name": "Name",
@ -50,6 +50,7 @@
"edit_account_page": {
"titlebar": "Edit Account",
"header": "Account Profile",
"update": "Update",
"instructions": "This information will be shared with the people you invite to connect with you on VeilidChat.",
"error": "Account modification error",
"name": "Name",
@ -63,9 +64,9 @@
"destroy_account_description": "Destroy account, removing it completely from all devices everywhere",
"destroy_account_confirm_message": "This action is PERMANENT, and your VeilidChat account will no longer be recoverable with the recovery key. Restoring from backups will not recover your account!",
"destroy_account_confirm_message_details": "You will lose access to:\n • Your entire message history\n • Your contacts\n • This will not remove your messages you have sent from other people's devices\n",
"failed_to_remove_title": "Failed to remove account",
"try_again_network": "Try again when you have a more stable network connection",
"failed_to_destroy_title": "Failed to destroy account",
"confirm_are_you_sure": "Are you sure you want to do this?",
"failed_to_remove": "Failed to remove account.\n\nTry again when you have a more stable network connection.",
"failed_to_destroy": "Failed to destroy account.\n\nTry again when you have a more stable network connection.",
"account_removed": "Account removed successfully",
"account_destroyed": "Account destroyed successfully"
},
@ -82,12 +83,6 @@
"view": "View",
"share": "Share"
},
"confirmation": {
"confirm": "Confirm",
"discard_changes": "Discard changes?",
"are_you_sure_discard": "Are you sure you want to discard your changes?",
"are_you_sure": "Are you sure you want to do this?"
},
"button": {
"ok": "Ok",
"cancel": "Cancel",
@ -99,11 +94,10 @@
"close": "Close",
"yes": "Yes",
"no": "No",
"update": "Update",
"waiting_for_network": "Waiting For Network",
"chat": "Chat"
"waiting_for_network": "Waiting For Network"
},
"toast": {
"confirm": "Confirm",
"error": "Error",
"info": "Info"
},
@ -128,7 +122,7 @@
"contacts": "Contacts",
"edit_contact": "Edit Contact",
"invitations": "Invitations",
"no_contact_selected": "Select a contact to view or edit",
"no_contact_selected": "Double-click a contact to edit it",
"new_chat": "Open Chat",
"close_contact": "Close Contact"
},
@ -147,7 +141,9 @@
"form_nickname": "Nickname",
"form_notes": "Notes",
"form_fingerprint": "Fingerprint",
"form_show_availability": "Show availability"
"form_show_availability": "Show availability",
"save": "Save",
"save_disabled": "Save"
},
"availability": {
"unspecified": "Unspecified",
@ -158,8 +154,9 @@
"away": "Away"
},
"add_contact_sheet": {
"add_contact": "Add Contact",
"new_contact": "New Contact",
"create_invite": "Create\nInvitation",
"receive_invite": "Receive\nInvitation",
"scan_invite": "Scan\nInvitation",
"paste_invite": "Paste\nInvitation"
},
@ -174,21 +171,18 @@
"create_invitation_dialog": {
"title": "Create Contact Invitation",
"me": "me",
"recipient_name": "Contact Name",
"recipient_hint": "Enter the recipient's name",
"recipient_helper": "Name of the person you are inviting to chat",
"message_hint": "Enter message for contact (optional)",
"message_label": "Message",
"message_helper": "Message to send with invitation",
"fingerprint": "Fingerprint",
"fingerprint": "Fingerprint:",
"connect_with_me": "Connect with {name} on VeilidChat!",
"enter_message_hint": "Enter message for contact (optional)",
"message_to_contact": "Message to send with invitation (not encrypted)",
"generate": "Generate Invitation",
"message": "Message",
"unlocked": "Unlocked",
"pin": "PIN",
"password": "Password",
"protect_this_invitation": "Protect this invitation:",
"note": "Note:",
"note_text": "Do not post contact invitations publicly.\n\nContact invitations can be used by anyone. Make sure you send the invitation to your contact over a secure medium, and preferably use a password or pin to ensure that they are the only ones who can unlock the invitation and accept it.",
"note_text": "Contact invitations can be used by anyone. Make sure you send the invitation to your contact over a secure medium, and preferably use a password or pin to ensure that they are the only ones who can unlock the invitation and accept it.",
"pin_description": "Choose a PIN to protect the contact invite.\n\nThis level of security is appropriate only for casual connections in public environments for 'shoulder surfing' protection.",
"password_description": "Choose a strong password to protect the contact invite.\n\nThis level of security is appropriate when you must be sure the contact invitation is only accepted by its intended recipient. Share this password over a different medium than the invite itself.",
"pin_does_not_match": "PIN does not match",
@ -198,7 +192,6 @@
"invitation_copied": "Invitation Copied"
},
"invitation_dialog": {
"to": "To",
"message_from_contact": "Message from contact",
"validating": "Validating...",
"failed_to_accept": "Failed to accept contact invitation",
@ -285,7 +278,6 @@
"delivery": "Delivery",
"enable_badge": "Enable icon 'badge' bubble",
"enable_notifications": "Enable notifications",
"enable_wallpaper": "Enable wallpaper",
"message_notification_content": "Message notification content",
"invitation_accepted": "On invitation accept/reject",
"message_received": "On message received",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.7 KiB

BIN
assets/images/handshake.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/images/toilet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 683 591" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-258.886,-304.79)">
<path d="M863.18,714.04C889.629,689.649 905.735,659.528 906.84,627.009L479.4,627.009C471.935,627.009 465.896,620.954 465.896,613.505L465.896,383.995L258.886,383.995L258.886,644.605C317.804,660.73 358.554,675.578 386.046,711.378C413.191,746.722 425.198,800.858 426.222,895.218L734.112,895.218L734.112,782.788L734.147,782.788C734.147,776.409 738.69,770.745 745.186,769.554C792.893,760.691 834.159,740.827 863.186,714.038L863.18,714.04Z" style="fill-rule:nonzero;"/>
<path d="M921.09,600.04L922.367,599.989C927.383,600.161 932.25,597.794 935.601,594.427C942.949,587.044 942.965,575.173 935.551,567.759C932.113,564.321 927.386,562.196 922.199,562.196L492.889,562.196L492.889,599.989L919.989,599.989C920.364,599.989 920.719,600.005 921.094,600.04L921.09,600.04Z" style="fill-rule:nonzero;"/>
<rect x="258.89" y="304.79" width="207.01" height="52.199" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 194 KiB

View File

@ -1,663 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 225 135" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect x="0" y="0" width="225" height="135" style="fill:rgb(255,106,248);"/>
<g id="Layer1">
<rect x="0" y="0" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<path d="M0,45L0,22.5L22.5,45L0,45Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="22.5" y="22.5" width="22.5" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M42.613,22.5L44.203,22.5L22.5,44.203L22.5,42.613L42.613,22.5ZM24.887,45L23.297,45L45,23.297L45,24.887L24.887,45ZM26.477,45L28.07,45L45,28.07L45,26.477L26.477,45ZM31.25,45L29.66,45L45,29.66L45,31.25L31.25,45ZM32.84,45L34.434,45L45,34.434L45,32.84L32.84,45ZM37.613,45L36.023,45L45,36.023L45,37.613L37.613,45ZM39.207,45L40.797,45L45,40.797L45,39.207L39.207,45ZM43.977,45L42.387,45L45,42.387L45,43.977L43.977,45ZM41.023,22.5L39.43,22.5L22.5,39.43L22.5,41.023L41.023,22.5ZM36.25,22.5L37.84,22.5L22.5,37.84L22.5,36.25L36.25,22.5ZM34.66,22.5L33.066,22.5L22.5,33.066L22.5,34.66L34.66,22.5ZM29.887,22.5L31.477,22.5L22.5,31.477L22.5,29.887L29.887,22.5ZM28.293,22.5L26.703,22.5L22.5,26.703L22.5,28.293L28.293,22.5ZM23.523,22.5L25.113,22.5L22.5,25.113L22.5,23.523L23.523,22.5Z" style="fill:rgb(255,204,255);"/>
<rect x="22.5" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M33.75,7.312L29.773,11.289L33.75,15.266L37.727,11.289L33.75,7.312Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="22.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="22.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="22.5" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M45,45C45,47.953 44.418,50.879 43.289,53.609C42.156,56.34 40.5,58.82 38.41,60.91C36.32,63 33.84,64.656 31.109,65.789C28.379,66.918 25.453,67.5 22.5,67.5L22.5,45L45,45Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="0" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M0,45C0,47.953 0.581,50.879 1.711,53.609C2.844,56.34 4.5,58.82 6.59,60.91C8.68,63 11.16,64.656 13.891,65.789C16.621,66.918 19.547,67.5 22.5,67.5L22.5,45L0,45Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="0" y="67.5" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<path d="M22.5,112.5L22.5,135L45,112.5L22.5,112.5Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M22.5,90L22.5,112.5L45,90L22.5,90Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="0" y="90" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<rect x="0" y="112.5" width="22.5" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M20.113,112.5L21.703,112.5L0,134.203L0,132.613L20.113,112.5ZM2.387,135L0.797,135L22.5,113.297L22.5,114.887L2.387,135ZM3.977,135L5.57,135L22.5,118.07L22.5,116.477L3.977,135ZM8.75,135L7.16,135L22.5,119.66L22.5,121.25L8.75,135ZM10.34,135L11.934,135L22.5,124.434L22.5,122.84L10.34,135ZM15.113,135L13.523,135L22.5,126.023L22.5,127.613L15.113,135ZM16.707,135L18.297,135L22.5,130.797L22.5,129.207L16.707,135ZM21.477,135L19.887,135L22.5,132.387L22.5,133.977L21.477,135ZM18.523,112.5L16.93,112.5L0,129.43L0,131.023L18.523,112.5ZM13.75,112.5L15.34,112.5L0,127.84L0,126.25L13.75,112.5ZM12.16,112.5L10.566,112.5L0,123.066L0,124.66L12.16,112.5ZM7.387,112.5L8.977,112.5L0,121.477L0,119.887L7.387,112.5ZM5.793,112.5L4.203,112.5L0,116.703L0,118.293L5.793,112.5ZM1.023,112.5L2.613,112.5L0,115.113L0,113.523L1.023,112.5Z" style="fill:rgb(255,153,255);"/>
<rect x="67.5" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<rect x="67.5" y="22.5" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="45" y="22.5" width="22.5" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="11.25" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="11.25" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="45" width="11.25" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="45" width="11.25" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="67.5" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<rect x="67.5" y="67.5" width="22.5" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M87.613,67.5L89.203,67.5L67.5,89.203L67.5,87.613L87.613,67.5ZM69.887,90L68.297,90L90,68.297L90,69.887L69.887,90ZM71.477,90L73.07,90L90,73.07L90,71.477L71.477,90ZM76.25,90L74.66,90L90,74.66L90,76.25L76.25,90ZM77.84,90L79.434,90L90,79.434L90,77.84L77.84,90ZM82.613,90L81.023,90L90,81.023L90,82.613L82.613,90ZM84.207,90L85.797,90L90,85.797L90,84.207L84.207,90ZM88.977,90L87.387,90L90,87.387L90,88.977L88.977,90ZM86.023,67.5L84.43,67.5L67.5,84.43L67.5,86.023L86.023,67.5ZM81.25,67.5L82.84,67.5L67.5,82.84L67.5,81.25L81.25,67.5ZM79.66,67.5L78.066,67.5L67.5,78.066L67.5,79.66L79.66,67.5ZM74.887,67.5L76.477,67.5L67.5,76.477L67.5,74.887L74.887,67.5ZM73.293,67.5L71.703,67.5L67.5,71.703L67.5,73.293L73.293,67.5ZM68.523,67.5L70.113,67.5L67.5,70.113L67.5,68.523L68.523,67.5Z" style="fill:rgb(255,153,255);"/>
<rect x="45" y="67.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M45,90C45,87.047 45.582,84.121 46.711,81.391C47.844,78.66 49.5,76.18 51.59,74.09C53.68,72 56.16,70.344 58.891,69.211C61.621,68.082 64.546,67.5 67.5,67.5L67.5,90L45,90Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="123.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="45" y="123.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="67.5" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M90,135C90,132.047 89.418,129.121 88.289,126.391C87.156,123.66 85.5,121.18 83.41,119.09C81.32,117 78.84,115.344 76.109,114.211C73.379,113.082 70.453,112.5 67.5,112.5L67.5,135L90,135Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="45" y="90" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M67.5,90C67.5,92.953 66.918,95.879 65.789,98.609C64.656,101.34 63,103.82 60.91,105.91C58.82,108 56.34,109.656 53.609,110.789C50.879,111.918 47.953,112.5 45,112.5L45,90L67.5,90Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="67.5" y="90" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M69.637,91.801C69.637,91.988 69.488,92.137 69.301,92.137C69.113,92.137 68.961,91.988 68.961,91.801C68.961,91.613 69.113,91.461 69.301,91.461C69.488,91.461 69.637,91.613 69.637,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,91.801C72,91.988 71.848,92.137 71.664,92.137C71.477,92.137 71.324,91.988 71.324,91.801C71.324,91.613 71.477,91.461 71.664,91.461C71.848,91.461 72,91.613 72,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,91.801C74.363,91.988 74.211,92.137 74.023,92.137C73.84,92.137 73.688,91.988 73.688,91.801C73.688,91.613 73.84,91.461 74.023,91.461C74.211,91.461 74.363,91.613 74.363,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,91.801C76.727,91.988 76.574,92.137 76.387,92.137C76.199,92.137 76.051,91.988 76.051,91.801C76.051,91.613 76.199,91.461 76.387,91.461C76.574,91.461 76.727,91.613 76.727,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,91.801C79.086,91.988 78.938,92.137 78.75,92.137C78.562,92.137 78.414,91.988 78.414,91.801C78.414,91.613 78.562,91.461 78.75,91.461C78.938,91.461 79.086,91.613 79.086,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,91.801C81.449,91.988 81.301,92.137 81.113,92.137C80.926,92.137 80.773,91.988 80.773,91.801C80.773,91.613 80.926,91.461 81.113,91.461C81.301,91.461 81.449,91.613 81.449,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,91.801C83.812,91.988 83.66,92.137 83.477,92.137C83.289,92.137 83.137,91.988 83.137,91.801C83.137,91.613 83.289,91.461 83.477,91.461C83.66,91.461 83.812,91.613 83.812,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,91.801C86.176,91.988 86.023,92.137 85.836,92.137C85.652,92.137 85.5,91.988 85.5,91.801C85.5,91.613 85.652,91.461 85.836,91.461C86.023,91.461 86.176,91.613 86.176,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,91.801C88.539,91.988 88.387,92.137 88.199,92.137C88.012,92.137 87.863,91.988 87.863,91.801C87.863,91.613 88.012,91.461 88.199,91.461C88.387,91.461 88.539,91.613 88.539,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,94.164C69.637,94.348 69.488,94.5 69.301,94.5C69.113,94.5 68.961,94.348 68.961,94.164C68.961,93.977 69.113,93.824 69.301,93.824C69.488,93.824 69.637,93.977 69.637,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,94.164C72,94.348 71.848,94.5 71.664,94.5C71.477,94.5 71.324,94.348 71.324,94.164C71.324,93.977 71.477,93.824 71.664,93.824C71.848,93.824 72,93.977 72,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,94.164C74.363,94.348 74.211,94.5 74.023,94.5C73.84,94.5 73.688,94.348 73.688,94.164C73.688,93.977 73.84,93.824 74.023,93.824C74.211,93.824 74.363,93.977 74.363,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,94.164C76.727,94.348 76.574,94.5 76.387,94.5C76.199,94.5 76.051,94.348 76.051,94.164C76.051,93.977 76.199,93.824 76.387,93.824C76.574,93.824 76.727,93.977 76.727,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,94.164C79.086,94.348 78.938,94.5 78.75,94.5C78.562,94.5 78.414,94.348 78.414,94.164C78.414,93.977 78.562,93.824 78.75,93.824C78.938,93.824 79.086,93.977 79.086,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,94.164C81.449,94.348 81.301,94.5 81.113,94.5C80.926,94.5 80.773,94.348 80.773,94.164C80.773,93.977 80.926,93.824 81.113,93.824C81.301,93.824 81.449,93.977 81.449,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,94.164C83.812,94.348 83.66,94.5 83.477,94.5C83.289,94.5 83.137,94.348 83.137,94.164C83.137,93.977 83.289,93.824 83.477,93.824C83.66,93.824 83.812,93.977 83.812,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,94.164C86.176,94.348 86.023,94.5 85.836,94.5C85.652,94.5 85.5,94.348 85.5,94.164C85.5,93.977 85.652,93.824 85.836,93.824C86.023,93.824 86.176,93.977 86.176,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,94.164C88.539,94.348 88.387,94.5 88.199,94.5C88.012,94.5 87.863,94.348 87.863,94.164C87.863,93.977 88.012,93.824 88.199,93.824C88.387,93.824 88.539,93.977 88.539,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,96.523C69.637,96.711 69.488,96.863 69.301,96.863C69.113,96.863 68.961,96.711 68.961,96.523C68.961,96.34 69.113,96.188 69.301,96.188C69.488,96.188 69.637,96.34 69.637,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,96.523C72,96.711 71.848,96.863 71.664,96.863C71.477,96.863 71.324,96.711 71.324,96.523C71.324,96.34 71.477,96.188 71.664,96.188C71.848,96.188 72,96.34 72,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,96.523C74.363,96.711 74.211,96.863 74.023,96.863C73.84,96.863 73.688,96.711 73.688,96.523C73.688,96.34 73.84,96.188 74.023,96.188C74.211,96.188 74.363,96.34 74.363,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,96.523C76.727,96.711 76.574,96.863 76.387,96.863C76.199,96.863 76.051,96.711 76.051,96.523C76.051,96.34 76.199,96.188 76.387,96.188C76.574,96.188 76.727,96.34 76.727,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,96.523C79.086,96.711 78.938,96.863 78.75,96.863C78.562,96.863 78.414,96.711 78.414,96.523C78.414,96.34 78.562,96.188 78.75,96.188C78.938,96.188 79.086,96.34 79.086,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,96.523C81.449,96.711 81.301,96.863 81.113,96.863C80.926,96.863 80.773,96.711 80.773,96.523C80.773,96.34 80.926,96.188 81.113,96.188C81.301,96.188 81.449,96.34 81.449,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,96.523C83.812,96.711 83.66,96.863 83.477,96.863C83.289,96.863 83.137,96.711 83.137,96.523C83.137,96.34 83.289,96.188 83.477,96.188C83.66,96.188 83.812,96.34 83.812,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,96.523C86.176,96.711 86.023,96.863 85.836,96.863C85.652,96.863 85.5,96.711 85.5,96.523C85.5,96.34 85.652,96.188 85.836,96.188C86.023,96.188 86.176,96.34 86.176,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,96.523C88.539,96.711 88.387,96.863 88.199,96.863C88.012,96.863 87.863,96.711 87.863,96.523C87.863,96.34 88.012,96.188 88.199,96.188C88.387,96.188 88.539,96.34 88.539,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,98.887C69.637,99.074 69.488,99.227 69.301,99.227C69.113,99.227 68.961,99.074 68.961,98.887C68.961,98.699 69.113,98.551 69.301,98.551C69.488,98.551 69.637,98.699 69.637,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,98.887C72,99.074 71.848,99.227 71.664,99.227C71.477,99.227 71.324,99.074 71.324,98.887C71.324,98.699 71.477,98.551 71.664,98.551C71.848,98.551 72,98.699 72,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,98.887C74.363,99.074 74.211,99.227 74.023,99.227C73.84,99.227 73.688,99.074 73.688,98.887C73.688,98.699 73.84,98.551 74.023,98.551C74.211,98.551 74.363,98.699 74.363,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,98.887C76.727,99.074 76.574,99.227 76.387,99.227C76.199,99.227 76.051,99.074 76.051,98.887C76.051,98.699 76.199,98.551 76.387,98.551C76.574,98.551 76.727,98.699 76.727,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,98.887C79.086,99.074 78.938,99.227 78.75,99.227C78.562,99.227 78.414,99.074 78.414,98.887C78.414,98.699 78.562,98.551 78.75,98.551C78.938,98.551 79.086,98.699 79.086,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,98.887C81.449,99.074 81.301,99.227 81.113,99.227C80.926,99.227 80.773,99.074 80.773,98.887C80.773,98.699 80.926,98.551 81.113,98.551C81.301,98.551 81.449,98.699 81.449,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,98.887C83.812,99.074 83.66,99.227 83.477,99.227C83.289,99.227 83.137,99.074 83.137,98.887C83.137,98.699 83.289,98.551 83.477,98.551C83.66,98.551 83.812,98.699 83.812,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,98.887C86.176,99.074 86.023,99.227 85.836,99.227C85.652,99.227 85.5,99.074 85.5,98.887C85.5,98.699 85.652,98.551 85.836,98.551C86.023,98.551 86.176,98.699 86.176,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,98.887C88.539,99.074 88.387,99.227 88.199,99.227C88.012,99.227 87.863,99.074 87.863,98.887C87.863,98.699 88.012,98.551 88.199,98.551C88.387,98.551 88.539,98.699 88.539,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,101.25C69.637,101.438 69.488,101.586 69.301,101.586C69.113,101.586 68.961,101.438 68.961,101.25C68.961,101.062 69.113,100.914 69.301,100.914C69.488,100.914 69.637,101.062 69.637,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,101.25C72,101.438 71.848,101.586 71.664,101.586C71.477,101.586 71.324,101.438 71.324,101.25C71.324,101.062 71.477,100.914 71.664,100.914C71.848,100.914 72,101.062 72,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,101.25C74.363,101.438 74.211,101.586 74.023,101.586C73.84,101.586 73.688,101.438 73.688,101.25C73.688,101.062 73.84,100.914 74.023,100.914C74.211,100.914 74.363,101.062 74.363,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,101.25C76.727,101.438 76.574,101.586 76.387,101.586C76.199,101.586 76.051,101.438 76.051,101.25C76.051,101.062 76.199,100.914 76.387,100.914C76.574,100.914 76.727,101.062 76.727,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,101.25C79.086,101.438 78.938,101.586 78.75,101.586C78.562,101.586 78.414,101.438 78.414,101.25C78.414,101.062 78.562,100.914 78.75,100.914C78.938,100.914 79.086,101.062 79.086,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,101.25C81.449,101.438 81.301,101.586 81.113,101.586C80.926,101.586 80.773,101.438 80.773,101.25C80.773,101.062 80.926,100.914 81.113,100.914C81.301,100.914 81.449,101.062 81.449,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,101.25C83.812,101.438 83.66,101.586 83.477,101.586C83.289,101.586 83.137,101.438 83.137,101.25C83.137,101.062 83.289,100.914 83.477,100.914C83.66,100.914 83.812,101.062 83.812,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,101.25C86.176,101.438 86.023,101.586 85.836,101.586C85.652,101.586 85.5,101.438 85.5,101.25C85.5,101.062 85.652,100.914 85.836,100.914C86.023,100.914 86.176,101.062 86.176,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,101.25C88.539,101.438 88.387,101.586 88.199,101.586C88.012,101.586 87.863,101.438 87.863,101.25C87.863,101.062 88.012,100.914 88.199,100.914C88.387,100.914 88.539,101.062 88.539,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,103.613C69.637,103.801 69.488,103.949 69.301,103.949C69.113,103.949 68.961,103.801 68.961,103.613C68.961,103.426 69.113,103.273 69.301,103.273C69.488,103.273 69.637,103.426 69.637,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,103.613C72,103.801 71.848,103.949 71.664,103.949C71.477,103.949 71.324,103.801 71.324,103.613C71.324,103.426 71.477,103.273 71.664,103.273C71.848,103.273 72,103.426 72,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,103.613C74.363,103.801 74.211,103.949 74.023,103.949C73.84,103.949 73.688,103.801 73.688,103.613C73.688,103.426 73.84,103.273 74.023,103.273C74.211,103.273 74.363,103.426 74.363,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,103.613C76.727,103.801 76.574,103.949 76.387,103.949C76.199,103.949 76.051,103.801 76.051,103.613C76.051,103.426 76.199,103.273 76.387,103.273C76.574,103.273 76.727,103.426 76.727,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,103.613C79.086,103.801 78.938,103.949 78.75,103.949C78.562,103.949 78.414,103.801 78.414,103.613C78.414,103.426 78.562,103.273 78.75,103.273C78.938,103.273 79.086,103.426 79.086,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,103.613C81.449,103.801 81.301,103.949 81.113,103.949C80.926,103.949 80.773,103.801 80.773,103.613C80.773,103.426 80.926,103.273 81.113,103.273C81.301,103.273 81.449,103.426 81.449,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,103.613C83.812,103.801 83.66,103.949 83.477,103.949C83.289,103.949 83.137,103.801 83.137,103.613C83.137,103.426 83.289,103.273 83.477,103.273C83.66,103.273 83.812,103.426 83.812,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,103.613C86.176,103.801 86.023,103.949 85.836,103.949C85.652,103.949 85.5,103.801 85.5,103.613C85.5,103.426 85.652,103.273 85.836,103.273C86.023,103.273 86.176,103.426 86.176,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,103.613C88.539,103.801 88.387,103.949 88.199,103.949C88.012,103.949 87.863,103.801 87.863,103.613C87.863,103.426 88.012,103.273 88.199,103.273C88.387,103.273 88.539,103.426 88.539,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,105.977C69.637,106.16 69.488,106.312 69.301,106.312C69.113,106.312 68.961,106.16 68.961,105.977C68.961,105.789 69.113,105.637 69.301,105.637C69.488,105.637 69.637,105.789 69.637,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,105.977C72,106.16 71.848,106.312 71.664,106.312C71.477,106.312 71.324,106.16 71.324,105.977C71.324,105.789 71.477,105.637 71.664,105.637C71.848,105.637 72,105.789 72,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,105.977C74.363,106.16 74.211,106.312 74.023,106.312C73.84,106.312 73.688,106.16 73.688,105.977C73.688,105.789 73.84,105.637 74.023,105.637C74.211,105.637 74.363,105.789 74.363,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,105.977C76.727,106.16 76.574,106.312 76.387,106.312C76.199,106.312 76.051,106.16 76.051,105.977C76.051,105.789 76.199,105.637 76.387,105.637C76.574,105.637 76.727,105.789 76.727,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,105.977C79.086,106.16 78.938,106.312 78.75,106.312C78.562,106.312 78.414,106.16 78.414,105.977C78.414,105.789 78.562,105.637 78.75,105.637C78.938,105.637 79.086,105.789 79.086,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,105.977C81.449,106.16 81.301,106.312 81.113,106.312C80.926,106.312 80.773,106.16 80.773,105.977C80.773,105.789 80.926,105.637 81.113,105.637C81.301,105.637 81.449,105.789 81.449,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,105.977C83.812,106.16 83.66,106.312 83.477,106.312C83.289,106.312 83.137,106.16 83.137,105.977C83.137,105.789 83.289,105.637 83.477,105.637C83.66,105.637 83.812,105.789 83.812,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,105.977C86.176,106.16 86.023,106.312 85.836,106.312C85.652,106.312 85.5,106.16 85.5,105.977C85.5,105.789 85.652,105.637 85.836,105.637C86.023,105.637 86.176,105.789 86.176,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,105.977C88.539,106.16 88.387,106.312 88.199,106.312C88.012,106.312 87.863,106.16 87.863,105.977C87.863,105.789 88.012,105.637 88.199,105.637C88.387,105.637 88.539,105.789 88.539,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,108.336C69.637,108.523 69.488,108.676 69.301,108.676C69.113,108.676 68.961,108.523 68.961,108.336C68.961,108.152 69.113,108 69.301,108C69.488,108 69.637,108.152 69.637,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,108.336C72,108.523 71.848,108.676 71.664,108.676C71.477,108.676 71.324,108.523 71.324,108.336C71.324,108.152 71.477,108 71.664,108C71.848,108 72,108.152 72,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,108.336C74.363,108.523 74.211,108.676 74.023,108.676C73.84,108.676 73.688,108.523 73.688,108.336C73.688,108.152 73.84,108 74.023,108C74.211,108 74.363,108.152 74.363,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,108.336C76.727,108.523 76.574,108.676 76.387,108.676C76.199,108.676 76.051,108.523 76.051,108.336C76.051,108.152 76.199,108 76.387,108C76.574,108 76.727,108.152 76.727,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,108.336C79.086,108.523 78.938,108.676 78.75,108.676C78.562,108.676 78.414,108.523 78.414,108.336C78.414,108.152 78.562,108 78.75,108C78.938,108 79.086,108.152 79.086,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,108.336C81.449,108.523 81.301,108.676 81.113,108.676C80.926,108.676 80.773,108.523 80.773,108.336C80.773,108.152 80.926,108 81.113,108C81.301,108 81.449,108.152 81.449,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,108.336C83.812,108.523 83.66,108.676 83.477,108.676C83.289,108.676 83.137,108.523 83.137,108.336C83.137,108.152 83.289,108 83.477,108C83.66,108 83.812,108.152 83.812,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,108.336C86.176,108.523 86.023,108.676 85.836,108.676C85.652,108.676 85.5,108.523 85.5,108.336C85.5,108.152 85.652,108 85.836,108C86.023,108 86.176,108.152 86.176,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,108.336C88.539,108.523 88.387,108.676 88.199,108.676C88.012,108.676 87.863,108.523 87.863,108.336C87.863,108.152 88.012,108 88.199,108C88.387,108 88.539,108.152 88.539,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M69.637,110.699C69.637,110.887 69.488,111.039 69.301,111.039C69.113,111.039 68.961,110.887 68.961,110.699C68.961,110.512 69.113,110.363 69.301,110.363C69.488,110.363 69.637,110.512 69.637,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M72,110.699C72,110.887 71.848,111.039 71.664,111.039C71.477,111.039 71.324,110.887 71.324,110.699C71.324,110.512 71.477,110.363 71.664,110.363C71.848,110.363 72,110.512 72,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M74.363,110.699C74.363,110.887 74.211,111.039 74.023,111.039C73.84,111.039 73.688,110.887 73.688,110.699C73.688,110.512 73.84,110.363 74.023,110.363C74.211,110.363 74.363,110.512 74.363,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M76.727,110.699C76.727,110.887 76.574,111.039 76.387,111.039C76.199,111.039 76.051,110.887 76.051,110.699C76.051,110.512 76.199,110.363 76.387,110.363C76.574,110.363 76.727,110.512 76.727,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M79.086,110.699C79.086,110.887 78.938,111.039 78.75,111.039C78.562,111.039 78.414,110.887 78.414,110.699C78.414,110.512 78.562,110.363 78.75,110.363C78.938,110.363 79.086,110.512 79.086,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M81.449,110.699C81.449,110.887 81.301,111.039 81.113,111.039C80.926,111.039 80.773,110.887 80.773,110.699C80.773,110.512 80.926,110.363 81.113,110.363C81.301,110.363 81.449,110.512 81.449,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M83.812,110.699C83.812,110.887 83.66,111.039 83.477,111.039C83.289,111.039 83.137,110.887 83.137,110.699C83.137,110.512 83.289,110.363 83.477,110.363C83.66,110.363 83.812,110.512 83.812,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M86.176,110.699C86.176,110.887 86.023,111.039 85.836,111.039C85.652,111.039 85.5,110.887 85.5,110.699C85.5,110.512 85.652,110.363 85.836,110.363C86.023,110.363 86.176,110.512 86.176,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M88.539,110.699C88.539,110.887 88.387,111.039 88.199,111.039C88.012,111.039 87.863,110.887 87.863,110.699C87.863,110.512 88.012,110.363 88.199,110.363C88.387,110.363 88.539,110.512 88.539,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="90" y="33.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="90" y="33.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="112.5" y="22.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M135,45C135,42.047 134.418,39.121 133.289,36.391C132.156,33.66 130.5,31.18 128.41,29.09C126.32,27 123.84,25.344 121.109,24.211C118.379,23.082 115.453,22.5 112.5,22.5L112.5,45L135,45Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="90" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M112.5,0C112.5,2.953 111.918,5.879 110.789,8.609C109.656,11.34 108,13.82 105.91,15.91C103.82,18 101.34,19.656 98.609,20.789C95.879,21.918 92.953,22.5 90,22.5L90,0L112.5,0Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="112.5" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M114.637,1.801C114.637,1.988 114.488,2.137 114.301,2.137C114.113,2.137 113.961,1.988 113.961,1.801C113.961,1.613 114.113,1.461 114.301,1.461C114.488,1.461 114.637,1.613 114.637,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,1.801C117,1.988 116.848,2.137 116.664,2.137C116.477,2.137 116.324,1.988 116.324,1.801C116.324,1.613 116.477,1.461 116.664,1.461C116.848,1.461 117,1.613 117,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,1.801C119.363,1.988 119.211,2.137 119.023,2.137C118.84,2.137 118.688,1.988 118.688,1.801C118.688,1.613 118.84,1.461 119.023,1.461C119.211,1.461 119.363,1.613 119.363,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,1.801C121.727,1.988 121.574,2.137 121.387,2.137C121.199,2.137 121.051,1.988 121.051,1.801C121.051,1.613 121.199,1.461 121.387,1.461C121.574,1.461 121.727,1.613 121.727,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,1.801C124.086,1.988 123.938,2.137 123.75,2.137C123.562,2.137 123.414,1.988 123.414,1.801C123.414,1.613 123.562,1.461 123.75,1.461C123.938,1.461 124.086,1.613 124.086,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,1.801C126.449,1.988 126.301,2.137 126.113,2.137C125.926,2.137 125.773,1.988 125.773,1.801C125.773,1.613 125.926,1.461 126.113,1.461C126.301,1.461 126.449,1.613 126.449,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,1.801C128.812,1.988 128.66,2.137 128.477,2.137C128.289,2.137 128.136,1.988 128.136,1.801C128.136,1.613 128.289,1.461 128.477,1.461C128.66,1.461 128.812,1.613 128.812,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,1.801C131.176,1.988 131.022,2.137 130.836,2.137C130.651,2.137 130.5,1.988 130.5,1.801C130.5,1.613 130.651,1.461 130.836,1.461C131.022,1.461 131.176,1.613 131.176,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,1.801C133.539,1.988 133.387,2.137 133.199,2.137C133.012,2.137 132.863,1.988 132.863,1.801C132.863,1.613 133.012,1.461 133.199,1.461C133.387,1.461 133.539,1.613 133.539,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,4.164C114.637,4.348 114.488,4.5 114.301,4.5C114.113,4.5 113.961,4.348 113.961,4.164C113.961,3.977 114.113,3.824 114.301,3.824C114.488,3.824 114.637,3.977 114.637,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,4.164C117,4.348 116.848,4.5 116.664,4.5C116.477,4.5 116.324,4.348 116.324,4.164C116.324,3.977 116.477,3.824 116.664,3.824C116.848,3.824 117,3.977 117,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,4.164C119.363,4.348 119.211,4.5 119.023,4.5C118.84,4.5 118.688,4.348 118.688,4.164C118.688,3.977 118.84,3.824 119.023,3.824C119.211,3.824 119.363,3.977 119.363,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,4.164C121.727,4.348 121.574,4.5 121.387,4.5C121.199,4.5 121.051,4.348 121.051,4.164C121.051,3.977 121.199,3.824 121.387,3.824C121.574,3.824 121.727,3.977 121.727,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,4.164C124.086,4.348 123.938,4.5 123.75,4.5C123.562,4.5 123.414,4.348 123.414,4.164C123.414,3.977 123.562,3.824 123.75,3.824C123.938,3.824 124.086,3.977 124.086,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,4.164C126.449,4.348 126.301,4.5 126.113,4.5C125.926,4.5 125.773,4.348 125.773,4.164C125.773,3.977 125.926,3.824 126.113,3.824C126.301,3.824 126.449,3.977 126.449,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,4.164C128.812,4.348 128.66,4.5 128.477,4.5C128.289,4.5 128.136,4.348 128.136,4.164C128.136,3.977 128.289,3.824 128.477,3.824C128.66,3.824 128.812,3.977 128.812,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,4.164C131.176,4.348 131.022,4.5 130.836,4.5C130.651,4.5 130.5,4.348 130.5,4.164C130.5,3.977 130.651,3.824 130.836,3.824C131.022,3.824 131.176,3.977 131.176,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,4.164C133.539,4.348 133.387,4.5 133.199,4.5C133.012,4.5 132.863,4.348 132.863,4.164C132.863,3.977 133.012,3.824 133.199,3.824C133.387,3.824 133.539,3.977 133.539,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,6.523C114.637,6.711 114.488,6.863 114.301,6.863C114.113,6.863 113.961,6.711 113.961,6.523C113.961,6.34 114.113,6.188 114.301,6.188C114.488,6.188 114.637,6.34 114.637,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,6.523C117,6.711 116.848,6.863 116.664,6.863C116.477,6.863 116.324,6.711 116.324,6.523C116.324,6.34 116.477,6.188 116.664,6.188C116.848,6.188 117,6.34 117,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,6.523C119.363,6.711 119.211,6.863 119.023,6.863C118.84,6.863 118.688,6.711 118.688,6.523C118.688,6.34 118.84,6.188 119.023,6.188C119.211,6.188 119.363,6.34 119.363,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,6.523C121.727,6.711 121.574,6.863 121.387,6.863C121.199,6.863 121.051,6.711 121.051,6.523C121.051,6.34 121.199,6.188 121.387,6.188C121.574,6.188 121.727,6.34 121.727,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,6.523C124.086,6.711 123.938,6.863 123.75,6.863C123.562,6.863 123.414,6.711 123.414,6.523C123.414,6.34 123.562,6.188 123.75,6.188C123.938,6.188 124.086,6.34 124.086,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,6.523C126.449,6.711 126.301,6.863 126.113,6.863C125.926,6.863 125.773,6.711 125.773,6.523C125.773,6.34 125.926,6.188 126.113,6.188C126.301,6.188 126.449,6.34 126.449,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,6.523C128.812,6.711 128.66,6.863 128.477,6.863C128.289,6.863 128.136,6.711 128.136,6.523C128.136,6.34 128.289,6.188 128.477,6.188C128.66,6.188 128.812,6.34 128.812,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,6.523C131.176,6.711 131.022,6.863 130.836,6.863C130.651,6.863 130.5,6.711 130.5,6.523C130.5,6.34 130.651,6.188 130.836,6.188C131.022,6.188 131.176,6.34 131.176,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,6.523C133.539,6.711 133.387,6.863 133.199,6.863C133.012,6.863 132.863,6.711 132.863,6.523C132.863,6.34 133.012,6.188 133.199,6.188C133.387,6.188 133.539,6.34 133.539,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,8.887C114.637,9.074 114.488,9.227 114.301,9.227C114.113,9.227 113.961,9.074 113.961,8.887C113.961,8.699 114.113,8.551 114.301,8.551C114.488,8.551 114.637,8.699 114.637,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,8.887C117,9.074 116.848,9.227 116.664,9.227C116.477,9.227 116.324,9.074 116.324,8.887C116.324,8.699 116.477,8.551 116.664,8.551C116.848,8.551 117,8.699 117,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,8.887C119.363,9.074 119.211,9.227 119.023,9.227C118.84,9.227 118.688,9.074 118.688,8.887C118.688,8.699 118.84,8.551 119.023,8.551C119.211,8.551 119.363,8.699 119.363,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,8.887C121.727,9.074 121.574,9.227 121.387,9.227C121.199,9.227 121.051,9.074 121.051,8.887C121.051,8.699 121.199,8.551 121.387,8.551C121.574,8.551 121.727,8.699 121.727,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,8.887C124.086,9.074 123.938,9.227 123.75,9.227C123.562,9.227 123.414,9.074 123.414,8.887C123.414,8.699 123.562,8.551 123.75,8.551C123.938,8.551 124.086,8.699 124.086,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,8.887C126.449,9.074 126.301,9.227 126.113,9.227C125.926,9.227 125.773,9.074 125.773,8.887C125.773,8.699 125.926,8.551 126.113,8.551C126.301,8.551 126.449,8.699 126.449,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,8.887C128.812,9.074 128.66,9.227 128.477,9.227C128.289,9.227 128.136,9.074 128.136,8.887C128.136,8.699 128.289,8.551 128.477,8.551C128.66,8.551 128.812,8.699 128.812,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,8.887C131.176,9.074 131.022,9.227 130.836,9.227C130.651,9.227 130.5,9.074 130.5,8.887C130.5,8.699 130.651,8.551 130.836,8.551C131.022,8.551 131.176,8.699 131.176,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,8.887C133.539,9.074 133.387,9.227 133.199,9.227C133.012,9.227 132.863,9.074 132.863,8.887C132.863,8.699 133.012,8.551 133.199,8.551C133.387,8.551 133.539,8.699 133.539,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,11.25C114.637,11.438 114.488,11.586 114.301,11.586C114.113,11.586 113.961,11.438 113.961,11.25C113.961,11.062 114.113,10.914 114.301,10.914C114.488,10.914 114.637,11.062 114.637,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,11.25C117,11.438 116.848,11.586 116.664,11.586C116.477,11.586 116.324,11.438 116.324,11.25C116.324,11.062 116.477,10.914 116.664,10.914C116.848,10.914 117,11.062 117,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,11.25C119.363,11.438 119.211,11.586 119.023,11.586C118.84,11.586 118.688,11.438 118.688,11.25C118.688,11.062 118.84,10.914 119.023,10.914C119.211,10.914 119.363,11.062 119.363,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,11.25C121.727,11.438 121.574,11.586 121.387,11.586C121.199,11.586 121.051,11.438 121.051,11.25C121.051,11.062 121.199,10.914 121.387,10.914C121.574,10.914 121.727,11.062 121.727,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,11.25C124.086,11.438 123.938,11.586 123.75,11.586C123.562,11.586 123.414,11.438 123.414,11.25C123.414,11.062 123.562,10.914 123.75,10.914C123.938,10.914 124.086,11.062 124.086,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,11.25C126.449,11.438 126.301,11.586 126.113,11.586C125.926,11.586 125.773,11.438 125.773,11.25C125.773,11.062 125.926,10.914 126.113,10.914C126.301,10.914 126.449,11.062 126.449,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,11.25C128.812,11.438 128.66,11.586 128.477,11.586C128.289,11.586 128.136,11.438 128.136,11.25C128.136,11.062 128.289,10.914 128.477,10.914C128.66,10.914 128.812,11.062 128.812,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,11.25C131.176,11.438 131.022,11.586 130.836,11.586C130.651,11.586 130.5,11.438 130.5,11.25C130.5,11.062 130.651,10.914 130.836,10.914C131.022,10.914 131.176,11.062 131.176,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,11.25C133.539,11.438 133.387,11.586 133.199,11.586C133.012,11.586 132.863,11.438 132.863,11.25C132.863,11.062 133.012,10.914 133.199,10.914C133.387,10.914 133.539,11.062 133.539,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,13.613C114.637,13.801 114.488,13.949 114.301,13.949C114.113,13.949 113.961,13.801 113.961,13.613C113.961,13.426 114.113,13.273 114.301,13.273C114.488,13.273 114.637,13.426 114.637,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,13.613C117,13.801 116.848,13.949 116.664,13.949C116.477,13.949 116.324,13.801 116.324,13.613C116.324,13.426 116.477,13.273 116.664,13.273C116.848,13.273 117,13.426 117,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,13.613C119.363,13.801 119.211,13.949 119.023,13.949C118.84,13.949 118.688,13.801 118.688,13.613C118.688,13.426 118.84,13.273 119.023,13.273C119.211,13.273 119.363,13.426 119.363,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,13.613C121.727,13.801 121.574,13.949 121.387,13.949C121.199,13.949 121.051,13.801 121.051,13.613C121.051,13.426 121.199,13.273 121.387,13.273C121.574,13.273 121.727,13.426 121.727,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,13.613C124.086,13.801 123.938,13.949 123.75,13.949C123.562,13.949 123.414,13.801 123.414,13.613C123.414,13.426 123.562,13.273 123.75,13.273C123.938,13.273 124.086,13.426 124.086,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,13.613C126.449,13.801 126.301,13.949 126.113,13.949C125.926,13.949 125.773,13.801 125.773,13.613C125.773,13.426 125.926,13.273 126.113,13.273C126.301,13.273 126.449,13.426 126.449,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,13.613C128.812,13.801 128.66,13.949 128.477,13.949C128.289,13.949 128.136,13.801 128.136,13.613C128.136,13.426 128.289,13.273 128.477,13.273C128.66,13.273 128.812,13.426 128.812,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,13.613C131.176,13.801 131.022,13.949 130.836,13.949C130.651,13.949 130.5,13.801 130.5,13.613C130.5,13.426 130.651,13.273 130.836,13.273C131.022,13.273 131.176,13.426 131.176,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,13.613C133.539,13.801 133.387,13.949 133.199,13.949C133.012,13.949 132.863,13.801 132.863,13.613C132.863,13.426 133.012,13.273 133.199,13.273C133.387,13.273 133.539,13.426 133.539,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,15.977C114.637,16.16 114.488,16.312 114.301,16.312C114.113,16.312 113.961,16.16 113.961,15.977C113.961,15.789 114.113,15.637 114.301,15.637C114.488,15.637 114.637,15.789 114.637,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,15.977C117,16.16 116.848,16.312 116.664,16.312C116.477,16.312 116.324,16.16 116.324,15.977C116.324,15.789 116.477,15.637 116.664,15.637C116.848,15.637 117,15.789 117,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,15.977C119.363,16.16 119.211,16.312 119.023,16.312C118.84,16.312 118.688,16.16 118.688,15.977C118.688,15.789 118.84,15.637 119.023,15.637C119.211,15.637 119.363,15.789 119.363,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,15.977C121.727,16.16 121.574,16.312 121.387,16.312C121.199,16.312 121.051,16.16 121.051,15.977C121.051,15.789 121.199,15.637 121.387,15.637C121.574,15.637 121.727,15.789 121.727,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,15.977C124.086,16.16 123.938,16.312 123.75,16.312C123.562,16.312 123.414,16.16 123.414,15.977C123.414,15.789 123.562,15.637 123.75,15.637C123.938,15.637 124.086,15.789 124.086,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,15.977C126.449,16.16 126.301,16.312 126.113,16.312C125.926,16.312 125.773,16.16 125.773,15.977C125.773,15.789 125.926,15.637 126.113,15.637C126.301,15.637 126.449,15.789 126.449,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,15.977C128.812,16.16 128.66,16.312 128.477,16.312C128.289,16.312 128.136,16.16 128.136,15.977C128.136,15.789 128.289,15.637 128.477,15.637C128.66,15.637 128.812,15.789 128.812,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,15.977C131.176,16.16 131.022,16.312 130.836,16.312C130.651,16.312 130.5,16.16 130.5,15.977C130.5,15.789 130.651,15.637 130.836,15.637C131.022,15.637 131.176,15.789 131.176,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,15.977C133.539,16.16 133.387,16.312 133.199,16.312C133.012,16.312 132.863,16.16 132.863,15.977C132.863,15.789 133.012,15.637 133.199,15.637C133.387,15.637 133.539,15.789 133.539,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,18.336C114.637,18.523 114.488,18.676 114.301,18.676C114.113,18.676 113.961,18.523 113.961,18.336C113.961,18.152 114.113,18 114.301,18C114.488,18 114.637,18.152 114.637,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,18.336C117,18.523 116.848,18.676 116.664,18.676C116.477,18.676 116.324,18.523 116.324,18.336C116.324,18.152 116.477,18 116.664,18C116.848,18 117,18.152 117,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,18.336C119.363,18.523 119.211,18.676 119.023,18.676C118.84,18.676 118.688,18.523 118.688,18.336C118.688,18.152 118.84,18 119.023,18C119.211,18 119.363,18.152 119.363,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,18.336C121.727,18.523 121.574,18.676 121.387,18.676C121.199,18.676 121.051,18.523 121.051,18.336C121.051,18.152 121.199,18 121.387,18C121.574,18 121.727,18.152 121.727,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,18.336C124.086,18.523 123.938,18.676 123.75,18.676C123.562,18.676 123.414,18.523 123.414,18.336C123.414,18.152 123.562,18 123.75,18C123.938,18 124.086,18.152 124.086,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,18.336C126.449,18.523 126.301,18.676 126.113,18.676C125.926,18.676 125.773,18.523 125.773,18.336C125.773,18.152 125.926,18 126.113,18C126.301,18 126.449,18.152 126.449,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,18.336C128.812,18.523 128.66,18.676 128.477,18.676C128.289,18.676 128.136,18.523 128.136,18.336C128.136,18.152 128.289,18 128.477,18C128.66,18 128.812,18.152 128.812,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,18.336C131.176,18.523 131.022,18.676 130.836,18.676C130.651,18.676 130.5,18.523 130.5,18.336C130.5,18.152 130.651,18 130.836,18C131.022,18 131.176,18.152 131.176,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,18.336C133.539,18.523 133.387,18.676 133.199,18.676C133.012,18.676 132.863,18.523 132.863,18.336C132.863,18.152 133.012,18 133.199,18C133.387,18 133.539,18.152 133.539,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M114.637,20.699C114.637,20.887 114.488,21.039 114.301,21.039C114.113,21.039 113.961,20.887 113.961,20.699C113.961,20.512 114.113,20.363 114.301,20.363C114.488,20.363 114.637,20.512 114.637,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M117,20.699C117,20.887 116.848,21.039 116.664,21.039C116.477,21.039 116.324,20.887 116.324,20.699C116.324,20.512 116.477,20.363 116.664,20.363C116.848,20.363 117,20.512 117,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M119.363,20.699C119.363,20.887 119.211,21.039 119.023,21.039C118.84,21.039 118.688,20.887 118.688,20.699C118.688,20.512 118.84,20.363 119.023,20.363C119.211,20.363 119.363,20.512 119.363,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M121.727,20.699C121.727,20.887 121.574,21.039 121.387,21.039C121.199,21.039 121.051,20.887 121.051,20.699C121.051,20.512 121.199,20.363 121.387,20.363C121.574,20.363 121.727,20.512 121.727,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M124.086,20.699C124.086,20.887 123.938,21.039 123.75,21.039C123.562,21.039 123.414,20.887 123.414,20.699C123.414,20.512 123.562,20.363 123.75,20.363C123.938,20.363 124.086,20.512 124.086,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M126.449,20.699C126.449,20.887 126.301,21.039 126.113,21.039C125.926,21.039 125.773,20.887 125.773,20.699C125.773,20.512 125.926,20.363 126.113,20.363C126.301,20.363 126.449,20.512 126.449,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M128.812,20.699C128.812,20.887 128.66,21.039 128.477,21.039C128.289,21.039 128.136,20.887 128.136,20.699C128.136,20.512 128.289,20.363 128.477,20.363C128.66,20.363 128.812,20.512 128.812,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M131.176,20.699C131.176,20.887 131.022,21.039 130.836,21.039C130.651,21.039 130.5,20.887 130.5,20.699C130.5,20.512 130.651,20.363 130.836,20.363C131.022,20.363 131.176,20.512 131.176,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M133.539,20.699C133.539,20.887 133.387,21.039 133.199,21.039C133.012,21.039 132.863,20.887 132.863,20.699C132.863,20.512 133.012,20.363 133.199,20.363C133.387,20.363 133.539,20.512 133.539,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="90" y="45" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<path d="M90,90L90,67.5L112.5,90L90,90Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="112.5" y="67.5" width="22.5" height="22.5" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M132.613,67.5L134.203,67.5L112.5,89.203L112.5,87.613L132.613,67.5ZM114.887,90L113.297,90L135,68.297L135,69.887L114.887,90ZM116.477,90L118.07,90L135,73.07L135,71.477L116.477,90ZM121.25,90L119.66,90L135,74.66L135,76.25L121.25,90ZM122.84,90L124.434,90L135,79.434L135,77.84L122.84,90ZM127.613,90L126.023,90L135,81.023L135,82.613L127.613,90ZM129.207,90L130.797,90L135,85.797L135,84.207L129.207,90ZM133.977,90L132.387,90L135,87.387L135,88.977L133.977,90ZM131.022,67.5L129.429,67.5L112.5,84.43L112.5,86.023L131.022,67.5ZM126.25,67.5L127.84,67.5L112.5,82.84L112.5,81.25L126.25,67.5ZM124.66,67.5L123.066,67.5L112.5,78.066L112.5,79.66L124.66,67.5ZM119.887,67.5L121.477,67.5L112.5,76.477L112.5,74.887L119.887,67.5ZM118.293,67.5L116.703,67.5L112.5,71.703L112.5,73.293L118.293,67.5ZM113.523,67.5L115.113,67.5L112.5,70.113L112.5,68.523L113.523,67.5Z" style="fill:rgb(255,204,255);"/>
<rect x="112.5" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M123.75,52.312L119.773,56.289L123.75,60.266L127.727,56.289L123.75,52.312Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="90" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M112.5,135C112.5,132.047 111.918,129.121 110.789,126.391C109.656,123.66 108,121.18 105.91,119.09C103.82,117 101.34,115.344 98.609,114.211C95.879,113.082 92.953,112.5 90,112.5L90,135L112.5,135Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="112.5" y="90" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="90" y="90" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M92.137,91.801C92.137,91.988 91.988,92.137 91.801,92.137C91.613,92.137 91.461,91.988 91.461,91.801C91.461,91.613 91.613,91.461 91.801,91.461C91.988,91.461 92.137,91.613 92.137,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,91.801C94.5,91.988 94.348,92.137 94.164,92.137C93.977,92.137 93.824,91.988 93.824,91.801C93.824,91.613 93.977,91.461 94.164,91.461C94.348,91.461 94.5,91.613 94.5,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,91.801C96.863,91.988 96.711,92.137 96.523,92.137C96.34,92.137 96.188,91.988 96.188,91.801C96.188,91.613 96.34,91.461 96.523,91.461C96.711,91.461 96.863,91.613 96.863,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,91.801C99.227,91.988 99.074,92.137 98.887,92.137C98.699,92.137 98.551,91.988 98.551,91.801C98.551,91.613 98.699,91.461 98.887,91.461C99.074,91.461 99.227,91.613 99.227,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,91.801C101.586,91.988 101.438,92.137 101.25,92.137C101.062,92.137 100.914,91.988 100.914,91.801C100.914,91.613 101.062,91.461 101.25,91.461C101.438,91.461 101.586,91.613 101.586,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,91.801C103.949,91.988 103.801,92.137 103.613,92.137C103.426,92.137 103.273,91.988 103.273,91.801C103.273,91.613 103.426,91.461 103.613,91.461C103.801,91.461 103.949,91.613 103.949,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,91.801C106.312,91.988 106.16,92.137 105.977,92.137C105.789,92.137 105.637,91.988 105.637,91.801C105.637,91.613 105.789,91.461 105.977,91.461C106.16,91.461 106.312,91.613 106.312,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,91.801C108.676,91.988 108.523,92.137 108.336,92.137C108.152,92.137 108,91.988 108,91.801C108,91.613 108.152,91.461 108.336,91.461C108.523,91.461 108.676,91.613 108.676,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,91.801C111.039,91.988 110.887,92.137 110.699,92.137C110.512,92.137 110.363,91.988 110.363,91.801C110.363,91.613 110.512,91.461 110.699,91.461C110.887,91.461 111.039,91.613 111.039,91.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,94.164C92.137,94.348 91.988,94.5 91.801,94.5C91.613,94.5 91.461,94.348 91.461,94.164C91.461,93.977 91.613,93.824 91.801,93.824C91.988,93.824 92.137,93.977 92.137,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,94.164C94.5,94.348 94.348,94.5 94.164,94.5C93.977,94.5 93.824,94.348 93.824,94.164C93.824,93.977 93.977,93.824 94.164,93.824C94.348,93.824 94.5,93.977 94.5,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,94.164C96.863,94.348 96.711,94.5 96.523,94.5C96.34,94.5 96.188,94.348 96.188,94.164C96.188,93.977 96.34,93.824 96.523,93.824C96.711,93.824 96.863,93.977 96.863,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,94.164C99.227,94.348 99.074,94.5 98.887,94.5C98.699,94.5 98.551,94.348 98.551,94.164C98.551,93.977 98.699,93.824 98.887,93.824C99.074,93.824 99.227,93.977 99.227,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,94.164C101.586,94.348 101.438,94.5 101.25,94.5C101.062,94.5 100.914,94.348 100.914,94.164C100.914,93.977 101.062,93.824 101.25,93.824C101.438,93.824 101.586,93.977 101.586,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,94.164C103.949,94.348 103.801,94.5 103.613,94.5C103.426,94.5 103.273,94.348 103.273,94.164C103.273,93.977 103.426,93.824 103.613,93.824C103.801,93.824 103.949,93.977 103.949,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,94.164C106.312,94.348 106.16,94.5 105.977,94.5C105.789,94.5 105.637,94.348 105.637,94.164C105.637,93.977 105.789,93.824 105.977,93.824C106.16,93.824 106.312,93.977 106.312,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,94.164C108.676,94.348 108.523,94.5 108.336,94.5C108.152,94.5 108,94.348 108,94.164C108,93.977 108.152,93.824 108.336,93.824C108.523,93.824 108.676,93.977 108.676,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,94.164C111.039,94.348 110.887,94.5 110.699,94.5C110.512,94.5 110.363,94.348 110.363,94.164C110.363,93.977 110.512,93.824 110.699,93.824C110.887,93.824 111.039,93.977 111.039,94.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,96.523C92.137,96.711 91.988,96.863 91.801,96.863C91.613,96.863 91.461,96.711 91.461,96.523C91.461,96.34 91.613,96.188 91.801,96.188C91.988,96.188 92.137,96.34 92.137,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,96.523C94.5,96.711 94.348,96.863 94.164,96.863C93.977,96.863 93.824,96.711 93.824,96.523C93.824,96.34 93.977,96.188 94.164,96.188C94.348,96.188 94.5,96.34 94.5,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,96.523C96.863,96.711 96.711,96.863 96.523,96.863C96.34,96.863 96.188,96.711 96.188,96.523C96.188,96.34 96.34,96.188 96.523,96.188C96.711,96.188 96.863,96.34 96.863,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,96.523C99.227,96.711 99.074,96.863 98.887,96.863C98.699,96.863 98.551,96.711 98.551,96.523C98.551,96.34 98.699,96.188 98.887,96.188C99.074,96.188 99.227,96.34 99.227,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,96.523C101.586,96.711 101.438,96.863 101.25,96.863C101.062,96.863 100.914,96.711 100.914,96.523C100.914,96.34 101.062,96.188 101.25,96.188C101.438,96.188 101.586,96.34 101.586,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,96.523C103.949,96.711 103.801,96.863 103.613,96.863C103.426,96.863 103.273,96.711 103.273,96.523C103.273,96.34 103.426,96.188 103.613,96.188C103.801,96.188 103.949,96.34 103.949,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,96.523C106.312,96.711 106.16,96.863 105.977,96.863C105.789,96.863 105.637,96.711 105.637,96.523C105.637,96.34 105.789,96.188 105.977,96.188C106.16,96.188 106.312,96.34 106.312,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,96.523C108.676,96.711 108.523,96.863 108.336,96.863C108.152,96.863 108,96.711 108,96.523C108,96.34 108.152,96.188 108.336,96.188C108.523,96.188 108.676,96.34 108.676,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,96.523C111.039,96.711 110.887,96.863 110.699,96.863C110.512,96.863 110.363,96.711 110.363,96.523C110.363,96.34 110.512,96.188 110.699,96.188C110.887,96.188 111.039,96.34 111.039,96.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,98.887C92.137,99.074 91.988,99.227 91.801,99.227C91.613,99.227 91.461,99.074 91.461,98.887C91.461,98.699 91.613,98.551 91.801,98.551C91.988,98.551 92.137,98.699 92.137,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,98.887C94.5,99.074 94.348,99.227 94.164,99.227C93.977,99.227 93.824,99.074 93.824,98.887C93.824,98.699 93.977,98.551 94.164,98.551C94.348,98.551 94.5,98.699 94.5,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,98.887C96.863,99.074 96.711,99.227 96.523,99.227C96.34,99.227 96.188,99.074 96.188,98.887C96.188,98.699 96.34,98.551 96.523,98.551C96.711,98.551 96.863,98.699 96.863,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,98.887C99.227,99.074 99.074,99.227 98.887,99.227C98.699,99.227 98.551,99.074 98.551,98.887C98.551,98.699 98.699,98.551 98.887,98.551C99.074,98.551 99.227,98.699 99.227,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,98.887C101.586,99.074 101.438,99.227 101.25,99.227C101.062,99.227 100.914,99.074 100.914,98.887C100.914,98.699 101.062,98.551 101.25,98.551C101.438,98.551 101.586,98.699 101.586,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,98.887C103.949,99.074 103.801,99.227 103.613,99.227C103.426,99.227 103.273,99.074 103.273,98.887C103.273,98.699 103.426,98.551 103.613,98.551C103.801,98.551 103.949,98.699 103.949,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,98.887C106.312,99.074 106.16,99.227 105.977,99.227C105.789,99.227 105.637,99.074 105.637,98.887C105.637,98.699 105.789,98.551 105.977,98.551C106.16,98.551 106.312,98.699 106.312,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,98.887C108.676,99.074 108.523,99.227 108.336,99.227C108.152,99.227 108,99.074 108,98.887C108,98.699 108.152,98.551 108.336,98.551C108.523,98.551 108.676,98.699 108.676,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,98.887C111.039,99.074 110.887,99.227 110.699,99.227C110.512,99.227 110.363,99.074 110.363,98.887C110.363,98.699 110.512,98.551 110.699,98.551C110.887,98.551 111.039,98.699 111.039,98.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,101.25C92.137,101.438 91.988,101.586 91.801,101.586C91.613,101.586 91.461,101.438 91.461,101.25C91.461,101.062 91.613,100.914 91.801,100.914C91.988,100.914 92.137,101.062 92.137,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,101.25C94.5,101.438 94.348,101.586 94.164,101.586C93.977,101.586 93.824,101.438 93.824,101.25C93.824,101.062 93.977,100.914 94.164,100.914C94.348,100.914 94.5,101.062 94.5,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,101.25C96.863,101.438 96.711,101.586 96.523,101.586C96.34,101.586 96.188,101.438 96.188,101.25C96.188,101.062 96.34,100.914 96.523,100.914C96.711,100.914 96.863,101.062 96.863,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,101.25C99.227,101.438 99.074,101.586 98.887,101.586C98.699,101.586 98.551,101.438 98.551,101.25C98.551,101.062 98.699,100.914 98.887,100.914C99.074,100.914 99.227,101.062 99.227,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,101.25C101.586,101.438 101.438,101.586 101.25,101.586C101.062,101.586 100.914,101.438 100.914,101.25C100.914,101.062 101.062,100.914 101.25,100.914C101.438,100.914 101.586,101.062 101.586,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,101.25C103.949,101.438 103.801,101.586 103.613,101.586C103.426,101.586 103.273,101.438 103.273,101.25C103.273,101.062 103.426,100.914 103.613,100.914C103.801,100.914 103.949,101.062 103.949,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,101.25C106.312,101.438 106.16,101.586 105.977,101.586C105.789,101.586 105.637,101.438 105.637,101.25C105.637,101.062 105.789,100.914 105.977,100.914C106.16,100.914 106.312,101.062 106.312,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,101.25C108.676,101.438 108.523,101.586 108.336,101.586C108.152,101.586 108,101.438 108,101.25C108,101.062 108.152,100.914 108.336,100.914C108.523,100.914 108.676,101.062 108.676,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,101.25C111.039,101.438 110.887,101.586 110.699,101.586C110.512,101.586 110.363,101.438 110.363,101.25C110.363,101.062 110.512,100.914 110.699,100.914C110.887,100.914 111.039,101.062 111.039,101.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,103.613C92.137,103.801 91.988,103.949 91.801,103.949C91.613,103.949 91.461,103.801 91.461,103.613C91.461,103.426 91.613,103.273 91.801,103.273C91.988,103.273 92.137,103.426 92.137,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,103.613C94.5,103.801 94.348,103.949 94.164,103.949C93.977,103.949 93.824,103.801 93.824,103.613C93.824,103.426 93.977,103.273 94.164,103.273C94.348,103.273 94.5,103.426 94.5,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,103.613C96.863,103.801 96.711,103.949 96.523,103.949C96.34,103.949 96.188,103.801 96.188,103.613C96.188,103.426 96.34,103.273 96.523,103.273C96.711,103.273 96.863,103.426 96.863,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,103.613C99.227,103.801 99.074,103.949 98.887,103.949C98.699,103.949 98.551,103.801 98.551,103.613C98.551,103.426 98.699,103.273 98.887,103.273C99.074,103.273 99.227,103.426 99.227,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,103.613C101.586,103.801 101.438,103.949 101.25,103.949C101.062,103.949 100.914,103.801 100.914,103.613C100.914,103.426 101.062,103.273 101.25,103.273C101.438,103.273 101.586,103.426 101.586,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,103.613C103.949,103.801 103.801,103.949 103.613,103.949C103.426,103.949 103.273,103.801 103.273,103.613C103.273,103.426 103.426,103.273 103.613,103.273C103.801,103.273 103.949,103.426 103.949,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,103.613C106.312,103.801 106.16,103.949 105.977,103.949C105.789,103.949 105.637,103.801 105.637,103.613C105.637,103.426 105.789,103.273 105.977,103.273C106.16,103.273 106.312,103.426 106.312,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,103.613C108.676,103.801 108.523,103.949 108.336,103.949C108.152,103.949 108,103.801 108,103.613C108,103.426 108.152,103.273 108.336,103.273C108.523,103.273 108.676,103.426 108.676,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,103.613C111.039,103.801 110.887,103.949 110.699,103.949C110.512,103.949 110.363,103.801 110.363,103.613C110.363,103.426 110.512,103.273 110.699,103.273C110.887,103.273 111.039,103.426 111.039,103.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,105.977C92.137,106.16 91.988,106.312 91.801,106.312C91.613,106.312 91.461,106.16 91.461,105.977C91.461,105.789 91.613,105.637 91.801,105.637C91.988,105.637 92.137,105.789 92.137,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,105.977C94.5,106.16 94.348,106.312 94.164,106.312C93.977,106.312 93.824,106.16 93.824,105.977C93.824,105.789 93.977,105.637 94.164,105.637C94.348,105.637 94.5,105.789 94.5,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,105.977C96.863,106.16 96.711,106.312 96.523,106.312C96.34,106.312 96.188,106.16 96.188,105.977C96.188,105.789 96.34,105.637 96.523,105.637C96.711,105.637 96.863,105.789 96.863,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,105.977C99.227,106.16 99.074,106.312 98.887,106.312C98.699,106.312 98.551,106.16 98.551,105.977C98.551,105.789 98.699,105.637 98.887,105.637C99.074,105.637 99.227,105.789 99.227,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,105.977C101.586,106.16 101.438,106.312 101.25,106.312C101.062,106.312 100.914,106.16 100.914,105.977C100.914,105.789 101.062,105.637 101.25,105.637C101.438,105.637 101.586,105.789 101.586,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,105.977C103.949,106.16 103.801,106.312 103.613,106.312C103.426,106.312 103.273,106.16 103.273,105.977C103.273,105.789 103.426,105.637 103.613,105.637C103.801,105.637 103.949,105.789 103.949,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,105.977C106.312,106.16 106.16,106.312 105.977,106.312C105.789,106.312 105.637,106.16 105.637,105.977C105.637,105.789 105.789,105.637 105.977,105.637C106.16,105.637 106.312,105.789 106.312,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,105.977C108.676,106.16 108.523,106.312 108.336,106.312C108.152,106.312 108,106.16 108,105.977C108,105.789 108.152,105.637 108.336,105.637C108.523,105.637 108.676,105.789 108.676,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,105.977C111.039,106.16 110.887,106.312 110.699,106.312C110.512,106.312 110.363,106.16 110.363,105.977C110.363,105.789 110.512,105.637 110.699,105.637C110.887,105.637 111.039,105.789 111.039,105.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,108.336C92.137,108.523 91.988,108.676 91.801,108.676C91.613,108.676 91.461,108.523 91.461,108.336C91.461,108.152 91.613,108 91.801,108C91.988,108 92.137,108.152 92.137,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,108.336C94.5,108.523 94.348,108.676 94.164,108.676C93.977,108.676 93.824,108.523 93.824,108.336C93.824,108.152 93.977,108 94.164,108C94.348,108 94.5,108.152 94.5,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,108.336C96.863,108.523 96.711,108.676 96.523,108.676C96.34,108.676 96.188,108.523 96.188,108.336C96.188,108.152 96.34,108 96.523,108C96.711,108 96.863,108.152 96.863,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,108.336C99.227,108.523 99.074,108.676 98.887,108.676C98.699,108.676 98.551,108.523 98.551,108.336C98.551,108.152 98.699,108 98.887,108C99.074,108 99.227,108.152 99.227,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,108.336C101.586,108.523 101.438,108.676 101.25,108.676C101.062,108.676 100.914,108.523 100.914,108.336C100.914,108.152 101.062,108 101.25,108C101.438,108 101.586,108.152 101.586,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,108.336C103.949,108.523 103.801,108.676 103.613,108.676C103.426,108.676 103.273,108.523 103.273,108.336C103.273,108.152 103.426,108 103.613,108C103.801,108 103.949,108.152 103.949,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,108.336C106.312,108.523 106.16,108.676 105.977,108.676C105.789,108.676 105.637,108.523 105.637,108.336C105.637,108.152 105.789,108 105.977,108C106.16,108 106.312,108.152 106.312,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,108.336C108.676,108.523 108.523,108.676 108.336,108.676C108.152,108.676 108,108.523 108,108.336C108,108.152 108.152,108 108.336,108C108.523,108 108.676,108.152 108.676,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,108.336C111.039,108.523 110.887,108.676 110.699,108.676C110.512,108.676 110.363,108.523 110.363,108.336C110.363,108.152 110.512,108 110.699,108C110.887,108 111.039,108.152 111.039,108.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M92.137,110.699C92.137,110.887 91.988,111.039 91.801,111.039C91.613,111.039 91.461,110.887 91.461,110.699C91.461,110.512 91.613,110.363 91.801,110.363C91.988,110.363 92.137,110.512 92.137,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M94.5,110.699C94.5,110.887 94.348,111.039 94.164,111.039C93.977,111.039 93.824,110.887 93.824,110.699C93.824,110.512 93.977,110.363 94.164,110.363C94.348,110.363 94.5,110.512 94.5,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M96.863,110.699C96.863,110.887 96.711,111.039 96.523,111.039C96.34,111.039 96.188,110.887 96.188,110.699C96.188,110.512 96.34,110.363 96.523,110.363C96.711,110.363 96.863,110.512 96.863,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M99.227,110.699C99.227,110.887 99.074,111.039 98.887,111.039C98.699,111.039 98.551,110.887 98.551,110.699C98.551,110.512 98.699,110.363 98.887,110.363C99.074,110.363 99.227,110.512 99.227,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M101.586,110.699C101.586,110.887 101.438,111.039 101.25,111.039C101.062,111.039 100.914,110.887 100.914,110.699C100.914,110.512 101.062,110.363 101.25,110.363C101.438,110.363 101.586,110.512 101.586,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M103.949,110.699C103.949,110.887 103.801,111.039 103.613,111.039C103.426,111.039 103.273,110.887 103.273,110.699C103.273,110.512 103.426,110.363 103.613,110.363C103.801,110.363 103.949,110.512 103.949,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M106.312,110.699C106.312,110.887 106.16,111.039 105.977,111.039C105.789,111.039 105.637,110.887 105.637,110.699C105.637,110.512 105.789,110.363 105.977,110.363C106.16,110.363 106.312,110.512 106.312,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M108.676,110.699C108.676,110.887 108.523,111.039 108.336,111.039C108.152,111.039 108,110.887 108,110.699C108,110.512 108.152,110.363 108.336,110.363C108.523,110.363 108.676,110.512 108.676,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M111.039,110.699C111.039,110.887 110.887,111.039 110.699,111.039C110.512,111.039 110.363,110.887 110.363,110.699C110.363,110.512 110.512,110.363 110.699,110.363C110.887,110.363 111.039,110.512 111.039,110.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M112.5,135L112.5,112.5L135,135L112.5,135Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="135" y="22.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M157.5,45C157.5,42.047 156.918,39.121 155.789,36.391C154.656,33.66 153,31.18 150.91,29.09C148.82,27 146.34,25.344 143.609,24.211C140.879,23.082 137.953,22.5 135,22.5L135,45L157.5,45Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="157.5" y="0" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="135" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M137.137,1.801C137.137,1.988 136.988,2.137 136.801,2.137C136.613,2.137 136.461,1.988 136.461,1.801C136.461,1.613 136.613,1.461 136.801,1.461C136.988,1.461 137.137,1.613 137.137,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,1.801C139.5,1.988 139.348,2.137 139.164,2.137C138.977,2.137 138.824,1.988 138.824,1.801C138.824,1.613 138.977,1.461 139.164,1.461C139.348,1.461 139.5,1.613 139.5,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,1.801C141.863,1.988 141.711,2.137 141.523,2.137C141.34,2.137 141.188,1.988 141.188,1.801C141.188,1.613 141.34,1.461 141.523,1.461C141.711,1.461 141.863,1.613 141.863,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,1.801C144.227,1.988 144.074,2.137 143.887,2.137C143.699,2.137 143.551,1.988 143.551,1.801C143.551,1.613 143.699,1.461 143.887,1.461C144.074,1.461 144.227,1.613 144.227,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,1.801C146.586,1.988 146.438,2.137 146.25,2.137C146.062,2.137 145.914,1.988 145.914,1.801C145.914,1.613 146.062,1.461 146.25,1.461C146.438,1.461 146.586,1.613 146.586,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,1.801C148.949,1.988 148.801,2.137 148.613,2.137C148.426,2.137 148.273,1.988 148.273,1.801C148.273,1.613 148.426,1.461 148.613,1.461C148.801,1.461 148.949,1.613 148.949,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,1.801C151.312,1.988 151.16,2.137 150.977,2.137C150.789,2.137 150.637,1.988 150.637,1.801C150.637,1.613 150.789,1.461 150.977,1.461C151.16,1.461 151.312,1.613 151.312,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,1.801C153.676,1.988 153.523,2.137 153.336,2.137C153.152,2.137 153,1.988 153,1.801C153,1.613 153.152,1.461 153.336,1.461C153.523,1.461 153.676,1.613 153.676,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,1.801C156.039,1.988 155.887,2.137 155.699,2.137C155.512,2.137 155.363,1.988 155.363,1.801C155.363,1.613 155.512,1.461 155.699,1.461C155.887,1.461 156.039,1.613 156.039,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,4.164C137.137,4.348 136.988,4.5 136.801,4.5C136.613,4.5 136.461,4.348 136.461,4.164C136.461,3.977 136.613,3.824 136.801,3.824C136.988,3.824 137.137,3.977 137.137,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,4.164C139.5,4.348 139.348,4.5 139.164,4.5C138.977,4.5 138.824,4.348 138.824,4.164C138.824,3.977 138.977,3.824 139.164,3.824C139.348,3.824 139.5,3.977 139.5,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,4.164C141.863,4.348 141.711,4.5 141.523,4.5C141.34,4.5 141.188,4.348 141.188,4.164C141.188,3.977 141.34,3.824 141.523,3.824C141.711,3.824 141.863,3.977 141.863,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,4.164C144.227,4.348 144.074,4.5 143.887,4.5C143.699,4.5 143.551,4.348 143.551,4.164C143.551,3.977 143.699,3.824 143.887,3.824C144.074,3.824 144.227,3.977 144.227,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,4.164C146.586,4.348 146.438,4.5 146.25,4.5C146.062,4.5 145.914,4.348 145.914,4.164C145.914,3.977 146.062,3.824 146.25,3.824C146.438,3.824 146.586,3.977 146.586,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,4.164C148.949,4.348 148.801,4.5 148.613,4.5C148.426,4.5 148.273,4.348 148.273,4.164C148.273,3.977 148.426,3.824 148.613,3.824C148.801,3.824 148.949,3.977 148.949,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,4.164C151.312,4.348 151.16,4.5 150.977,4.5C150.789,4.5 150.637,4.348 150.637,4.164C150.637,3.977 150.789,3.824 150.977,3.824C151.16,3.824 151.312,3.977 151.312,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,4.164C153.676,4.348 153.523,4.5 153.336,4.5C153.152,4.5 153,4.348 153,4.164C153,3.977 153.152,3.824 153.336,3.824C153.523,3.824 153.676,3.977 153.676,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,4.164C156.039,4.348 155.887,4.5 155.699,4.5C155.512,4.5 155.363,4.348 155.363,4.164C155.363,3.977 155.512,3.824 155.699,3.824C155.887,3.824 156.039,3.977 156.039,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,6.523C137.137,6.711 136.988,6.863 136.801,6.863C136.613,6.863 136.461,6.711 136.461,6.523C136.461,6.34 136.613,6.188 136.801,6.188C136.988,6.188 137.137,6.34 137.137,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,6.523C139.5,6.711 139.348,6.863 139.164,6.863C138.977,6.863 138.824,6.711 138.824,6.523C138.824,6.34 138.977,6.188 139.164,6.188C139.348,6.188 139.5,6.34 139.5,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,6.523C141.863,6.711 141.711,6.863 141.523,6.863C141.34,6.863 141.188,6.711 141.188,6.523C141.188,6.34 141.34,6.188 141.523,6.188C141.711,6.188 141.863,6.34 141.863,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,6.523C144.227,6.711 144.074,6.863 143.887,6.863C143.699,6.863 143.551,6.711 143.551,6.523C143.551,6.34 143.699,6.188 143.887,6.188C144.074,6.188 144.227,6.34 144.227,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,6.523C146.586,6.711 146.438,6.863 146.25,6.863C146.062,6.863 145.914,6.711 145.914,6.523C145.914,6.34 146.062,6.188 146.25,6.188C146.438,6.188 146.586,6.34 146.586,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,6.523C148.949,6.711 148.801,6.863 148.613,6.863C148.426,6.863 148.273,6.711 148.273,6.523C148.273,6.34 148.426,6.188 148.613,6.188C148.801,6.188 148.949,6.34 148.949,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,6.523C151.312,6.711 151.16,6.863 150.977,6.863C150.789,6.863 150.637,6.711 150.637,6.523C150.637,6.34 150.789,6.188 150.977,6.188C151.16,6.188 151.312,6.34 151.312,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,6.523C153.676,6.711 153.523,6.863 153.336,6.863C153.152,6.863 153,6.711 153,6.523C153,6.34 153.152,6.188 153.336,6.188C153.523,6.188 153.676,6.34 153.676,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,6.523C156.039,6.711 155.887,6.863 155.699,6.863C155.512,6.863 155.363,6.711 155.363,6.523C155.363,6.34 155.512,6.188 155.699,6.188C155.887,6.188 156.039,6.34 156.039,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,8.887C137.137,9.074 136.988,9.227 136.801,9.227C136.613,9.227 136.461,9.074 136.461,8.887C136.461,8.699 136.613,8.551 136.801,8.551C136.988,8.551 137.137,8.699 137.137,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,8.887C139.5,9.074 139.348,9.227 139.164,9.227C138.977,9.227 138.824,9.074 138.824,8.887C138.824,8.699 138.977,8.551 139.164,8.551C139.348,8.551 139.5,8.699 139.5,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,8.887C141.863,9.074 141.711,9.227 141.523,9.227C141.34,9.227 141.188,9.074 141.188,8.887C141.188,8.699 141.34,8.551 141.523,8.551C141.711,8.551 141.863,8.699 141.863,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,8.887C144.227,9.074 144.074,9.227 143.887,9.227C143.699,9.227 143.551,9.074 143.551,8.887C143.551,8.699 143.699,8.551 143.887,8.551C144.074,8.551 144.227,8.699 144.227,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,8.887C146.586,9.074 146.438,9.227 146.25,9.227C146.062,9.227 145.914,9.074 145.914,8.887C145.914,8.699 146.062,8.551 146.25,8.551C146.438,8.551 146.586,8.699 146.586,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,8.887C148.949,9.074 148.801,9.227 148.613,9.227C148.426,9.227 148.273,9.074 148.273,8.887C148.273,8.699 148.426,8.551 148.613,8.551C148.801,8.551 148.949,8.699 148.949,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,8.887C151.312,9.074 151.16,9.227 150.977,9.227C150.789,9.227 150.637,9.074 150.637,8.887C150.637,8.699 150.789,8.551 150.977,8.551C151.16,8.551 151.312,8.699 151.312,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,8.887C153.676,9.074 153.523,9.227 153.336,9.227C153.152,9.227 153,9.074 153,8.887C153,8.699 153.152,8.551 153.336,8.551C153.523,8.551 153.676,8.699 153.676,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,8.887C156.039,9.074 155.887,9.227 155.699,9.227C155.512,9.227 155.363,9.074 155.363,8.887C155.363,8.699 155.512,8.551 155.699,8.551C155.887,8.551 156.039,8.699 156.039,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,11.25C137.137,11.438 136.988,11.586 136.801,11.586C136.613,11.586 136.461,11.438 136.461,11.25C136.461,11.062 136.613,10.914 136.801,10.914C136.988,10.914 137.137,11.062 137.137,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,11.25C139.5,11.438 139.348,11.586 139.164,11.586C138.977,11.586 138.824,11.438 138.824,11.25C138.824,11.062 138.977,10.914 139.164,10.914C139.348,10.914 139.5,11.062 139.5,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,11.25C141.863,11.438 141.711,11.586 141.523,11.586C141.34,11.586 141.188,11.438 141.188,11.25C141.188,11.062 141.34,10.914 141.523,10.914C141.711,10.914 141.863,11.062 141.863,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,11.25C144.227,11.438 144.074,11.586 143.887,11.586C143.699,11.586 143.551,11.438 143.551,11.25C143.551,11.062 143.699,10.914 143.887,10.914C144.074,10.914 144.227,11.062 144.227,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,11.25C146.586,11.438 146.438,11.586 146.25,11.586C146.062,11.586 145.914,11.438 145.914,11.25C145.914,11.062 146.062,10.914 146.25,10.914C146.438,10.914 146.586,11.062 146.586,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,11.25C148.949,11.438 148.801,11.586 148.613,11.586C148.426,11.586 148.273,11.438 148.273,11.25C148.273,11.062 148.426,10.914 148.613,10.914C148.801,10.914 148.949,11.062 148.949,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,11.25C151.312,11.438 151.16,11.586 150.977,11.586C150.789,11.586 150.637,11.438 150.637,11.25C150.637,11.062 150.789,10.914 150.977,10.914C151.16,10.914 151.312,11.062 151.312,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,11.25C153.676,11.438 153.523,11.586 153.336,11.586C153.152,11.586 153,11.438 153,11.25C153,11.062 153.152,10.914 153.336,10.914C153.523,10.914 153.676,11.062 153.676,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,11.25C156.039,11.438 155.887,11.586 155.699,11.586C155.512,11.586 155.363,11.438 155.363,11.25C155.363,11.062 155.512,10.914 155.699,10.914C155.887,10.914 156.039,11.062 156.039,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,13.613C137.137,13.801 136.988,13.949 136.801,13.949C136.613,13.949 136.461,13.801 136.461,13.613C136.461,13.426 136.613,13.273 136.801,13.273C136.988,13.273 137.137,13.426 137.137,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,13.613C139.5,13.801 139.348,13.949 139.164,13.949C138.977,13.949 138.824,13.801 138.824,13.613C138.824,13.426 138.977,13.273 139.164,13.273C139.348,13.273 139.5,13.426 139.5,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,13.613C141.863,13.801 141.711,13.949 141.523,13.949C141.34,13.949 141.188,13.801 141.188,13.613C141.188,13.426 141.34,13.273 141.523,13.273C141.711,13.273 141.863,13.426 141.863,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,13.613C144.227,13.801 144.074,13.949 143.887,13.949C143.699,13.949 143.551,13.801 143.551,13.613C143.551,13.426 143.699,13.273 143.887,13.273C144.074,13.273 144.227,13.426 144.227,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,13.613C146.586,13.801 146.438,13.949 146.25,13.949C146.062,13.949 145.914,13.801 145.914,13.613C145.914,13.426 146.062,13.273 146.25,13.273C146.438,13.273 146.586,13.426 146.586,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,13.613C148.949,13.801 148.801,13.949 148.613,13.949C148.426,13.949 148.273,13.801 148.273,13.613C148.273,13.426 148.426,13.273 148.613,13.273C148.801,13.273 148.949,13.426 148.949,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,13.613C151.312,13.801 151.16,13.949 150.977,13.949C150.789,13.949 150.637,13.801 150.637,13.613C150.637,13.426 150.789,13.273 150.977,13.273C151.16,13.273 151.312,13.426 151.312,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,13.613C153.676,13.801 153.523,13.949 153.336,13.949C153.152,13.949 153,13.801 153,13.613C153,13.426 153.152,13.273 153.336,13.273C153.523,13.273 153.676,13.426 153.676,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,13.613C156.039,13.801 155.887,13.949 155.699,13.949C155.512,13.949 155.363,13.801 155.363,13.613C155.363,13.426 155.512,13.273 155.699,13.273C155.887,13.273 156.039,13.426 156.039,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,15.977C137.137,16.16 136.988,16.312 136.801,16.312C136.613,16.312 136.461,16.16 136.461,15.977C136.461,15.789 136.613,15.637 136.801,15.637C136.988,15.637 137.137,15.789 137.137,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,15.977C139.5,16.16 139.348,16.312 139.164,16.312C138.977,16.312 138.824,16.16 138.824,15.977C138.824,15.789 138.977,15.637 139.164,15.637C139.348,15.637 139.5,15.789 139.5,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,15.977C141.863,16.16 141.711,16.312 141.523,16.312C141.34,16.312 141.188,16.16 141.188,15.977C141.188,15.789 141.34,15.637 141.523,15.637C141.711,15.637 141.863,15.789 141.863,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,15.977C144.227,16.16 144.074,16.312 143.887,16.312C143.699,16.312 143.551,16.16 143.551,15.977C143.551,15.789 143.699,15.637 143.887,15.637C144.074,15.637 144.227,15.789 144.227,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,15.977C146.586,16.16 146.438,16.312 146.25,16.312C146.062,16.312 145.914,16.16 145.914,15.977C145.914,15.789 146.062,15.637 146.25,15.637C146.438,15.637 146.586,15.789 146.586,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,15.977C148.949,16.16 148.801,16.312 148.613,16.312C148.426,16.312 148.273,16.16 148.273,15.977C148.273,15.789 148.426,15.637 148.613,15.637C148.801,15.637 148.949,15.789 148.949,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,15.977C151.312,16.16 151.16,16.312 150.977,16.312C150.789,16.312 150.637,16.16 150.637,15.977C150.637,15.789 150.789,15.637 150.977,15.637C151.16,15.637 151.312,15.789 151.312,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,15.977C153.676,16.16 153.523,16.312 153.336,16.312C153.152,16.312 153,16.16 153,15.977C153,15.789 153.152,15.637 153.336,15.637C153.523,15.637 153.676,15.789 153.676,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,15.977C156.039,16.16 155.887,16.312 155.699,16.312C155.512,16.312 155.363,16.16 155.363,15.977C155.363,15.789 155.512,15.637 155.699,15.637C155.887,15.637 156.039,15.789 156.039,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,18.336C137.137,18.523 136.988,18.676 136.801,18.676C136.613,18.676 136.461,18.523 136.461,18.336C136.461,18.152 136.613,18 136.801,18C136.988,18 137.137,18.152 137.137,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,18.336C139.5,18.523 139.348,18.676 139.164,18.676C138.977,18.676 138.824,18.523 138.824,18.336C138.824,18.152 138.977,18 139.164,18C139.348,18 139.5,18.152 139.5,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,18.336C141.863,18.523 141.711,18.676 141.523,18.676C141.34,18.676 141.188,18.523 141.188,18.336C141.188,18.152 141.34,18 141.523,18C141.711,18 141.863,18.152 141.863,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,18.336C144.227,18.523 144.074,18.676 143.887,18.676C143.699,18.676 143.551,18.523 143.551,18.336C143.551,18.152 143.699,18 143.887,18C144.074,18 144.227,18.152 144.227,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,18.336C146.586,18.523 146.438,18.676 146.25,18.676C146.062,18.676 145.914,18.523 145.914,18.336C145.914,18.152 146.062,18 146.25,18C146.438,18 146.586,18.152 146.586,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,18.336C148.949,18.523 148.801,18.676 148.613,18.676C148.426,18.676 148.273,18.523 148.273,18.336C148.273,18.152 148.426,18 148.613,18C148.801,18 148.949,18.152 148.949,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,18.336C151.312,18.523 151.16,18.676 150.977,18.676C150.789,18.676 150.637,18.523 150.637,18.336C150.637,18.152 150.789,18 150.977,18C151.16,18 151.312,18.152 151.312,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,18.336C153.676,18.523 153.523,18.676 153.336,18.676C153.152,18.676 153,18.523 153,18.336C153,18.152 153.152,18 153.336,18C153.523,18 153.676,18.152 153.676,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,18.336C156.039,18.523 155.887,18.676 155.699,18.676C155.512,18.676 155.363,18.523 155.363,18.336C155.363,18.152 155.512,18 155.699,18C155.887,18 156.039,18.152 156.039,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,20.699C137.137,20.887 136.988,21.039 136.801,21.039C136.613,21.039 136.461,20.887 136.461,20.699C136.461,20.512 136.613,20.363 136.801,20.363C136.988,20.363 137.137,20.512 137.137,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,20.699C139.5,20.887 139.348,21.039 139.164,21.039C138.977,21.039 138.824,20.887 138.824,20.699C138.824,20.512 138.977,20.363 139.164,20.363C139.348,20.363 139.5,20.512 139.5,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,20.699C141.863,20.887 141.711,21.039 141.523,21.039C141.34,21.039 141.188,20.887 141.188,20.699C141.188,20.512 141.34,20.363 141.523,20.363C141.711,20.363 141.863,20.512 141.863,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,20.699C144.227,20.887 144.074,21.039 143.887,21.039C143.699,21.039 143.551,20.887 143.551,20.699C143.551,20.512 143.699,20.363 143.887,20.363C144.074,20.363 144.227,20.512 144.227,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,20.699C146.586,20.887 146.438,21.039 146.25,21.039C146.062,21.039 145.914,20.887 145.914,20.699C145.914,20.512 146.062,20.363 146.25,20.363C146.438,20.363 146.586,20.512 146.586,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,20.699C148.949,20.887 148.801,21.039 148.613,21.039C148.426,21.039 148.273,20.887 148.273,20.699C148.273,20.512 148.426,20.363 148.613,20.363C148.801,20.363 148.949,20.512 148.949,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,20.699C151.312,20.887 151.16,21.039 150.977,21.039C150.789,21.039 150.637,20.887 150.637,20.699C150.637,20.512 150.789,20.363 150.977,20.363C151.16,20.363 151.312,20.512 151.312,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,20.699C153.676,20.887 153.523,21.039 153.336,21.039C153.152,21.039 153,20.887 153,20.699C153,20.512 153.152,20.363 153.336,20.363C153.523,20.363 153.676,20.512 153.676,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,20.699C156.039,20.887 155.887,21.039 155.699,21.039C155.512,21.039 155.363,20.887 155.363,20.699C155.363,20.512 155.512,20.363 155.699,20.363C155.887,20.363 156.039,20.512 156.039,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M157.5,45L157.5,22.5L180,45L157.5,45Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="157.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="157.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="157.5" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M180,45C180,47.953 179.418,50.879 178.289,53.609C177.156,56.34 175.5,58.82 173.41,60.91C171.32,63 168.84,64.656 166.109,65.789C163.379,66.918 160.453,67.5 157.5,67.5L157.5,45L180,45Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="135" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M135,45C135,47.953 135.582,50.879 136.711,53.609C137.844,56.34 139.5,58.82 141.59,60.91C143.68,63 146.16,64.656 148.891,65.789C151.621,66.918 154.547,67.5 157.5,67.5L157.5,45L135,45Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="135" y="67.5" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<path d="M135,90L135,112.5L157.5,90L135,90Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="157.5" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="135" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M137.137,114.301C137.137,114.488 136.988,114.637 136.801,114.637C136.613,114.637 136.461,114.488 136.461,114.301C136.461,114.113 136.613,113.961 136.801,113.961C136.988,113.961 137.137,114.113 137.137,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,114.301C139.5,114.488 139.348,114.637 139.164,114.637C138.977,114.637 138.824,114.488 138.824,114.301C138.824,114.113 138.977,113.961 139.164,113.961C139.348,113.961 139.5,114.113 139.5,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,114.301C141.863,114.488 141.711,114.637 141.523,114.637C141.34,114.637 141.188,114.488 141.188,114.301C141.188,114.113 141.34,113.961 141.523,113.961C141.711,113.961 141.863,114.113 141.863,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,114.301C144.227,114.488 144.074,114.637 143.887,114.637C143.699,114.637 143.551,114.488 143.551,114.301C143.551,114.113 143.699,113.961 143.887,113.961C144.074,113.961 144.227,114.113 144.227,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,114.301C146.586,114.488 146.438,114.637 146.25,114.637C146.062,114.637 145.914,114.488 145.914,114.301C145.914,114.113 146.062,113.961 146.25,113.961C146.438,113.961 146.586,114.113 146.586,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,114.301C148.949,114.488 148.801,114.637 148.613,114.637C148.426,114.637 148.273,114.488 148.273,114.301C148.273,114.113 148.426,113.961 148.613,113.961C148.801,113.961 148.949,114.113 148.949,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,114.301C151.312,114.488 151.16,114.637 150.977,114.637C150.789,114.637 150.637,114.488 150.637,114.301C150.637,114.113 150.789,113.961 150.977,113.961C151.16,113.961 151.312,114.113 151.312,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,114.301C153.676,114.488 153.523,114.637 153.336,114.637C153.152,114.637 153,114.488 153,114.301C153,114.113 153.152,113.961 153.336,113.961C153.523,113.961 153.676,114.113 153.676,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,114.301C156.039,114.488 155.887,114.637 155.699,114.637C155.512,114.637 155.363,114.488 155.363,114.301C155.363,114.113 155.512,113.961 155.699,113.961C155.887,113.961 156.039,114.113 156.039,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,116.664C137.137,116.848 136.988,117 136.801,117C136.613,117 136.461,116.848 136.461,116.664C136.461,116.477 136.613,116.324 136.801,116.324C136.988,116.324 137.137,116.477 137.137,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,116.664C139.5,116.848 139.348,117 139.164,117C138.977,117 138.824,116.848 138.824,116.664C138.824,116.477 138.977,116.324 139.164,116.324C139.348,116.324 139.5,116.477 139.5,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,116.664C141.863,116.848 141.711,117 141.523,117C141.34,117 141.188,116.848 141.188,116.664C141.188,116.477 141.34,116.324 141.523,116.324C141.711,116.324 141.863,116.477 141.863,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,116.664C144.227,116.848 144.074,117 143.887,117C143.699,117 143.551,116.848 143.551,116.664C143.551,116.477 143.699,116.324 143.887,116.324C144.074,116.324 144.227,116.477 144.227,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,116.664C146.586,116.848 146.438,117 146.25,117C146.062,117 145.914,116.848 145.914,116.664C145.914,116.477 146.062,116.324 146.25,116.324C146.438,116.324 146.586,116.477 146.586,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,116.664C148.949,116.848 148.801,117 148.613,117C148.426,117 148.273,116.848 148.273,116.664C148.273,116.477 148.426,116.324 148.613,116.324C148.801,116.324 148.949,116.477 148.949,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,116.664C151.312,116.848 151.16,117 150.977,117C150.789,117 150.637,116.848 150.637,116.664C150.637,116.477 150.789,116.324 150.977,116.324C151.16,116.324 151.312,116.477 151.312,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,116.664C153.676,116.848 153.523,117 153.336,117C153.152,117 153,116.848 153,116.664C153,116.477 153.152,116.324 153.336,116.324C153.523,116.324 153.676,116.477 153.676,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,116.664C156.039,116.848 155.887,117 155.699,117C155.512,117 155.363,116.848 155.363,116.664C155.363,116.477 155.512,116.324 155.699,116.324C155.887,116.324 156.039,116.477 156.039,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,119.023C137.137,119.211 136.988,119.363 136.801,119.363C136.613,119.363 136.461,119.211 136.461,119.023C136.461,118.84 136.613,118.688 136.801,118.688C136.988,118.688 137.137,118.84 137.137,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,119.023C139.5,119.211 139.348,119.363 139.164,119.363C138.977,119.363 138.824,119.211 138.824,119.023C138.824,118.84 138.977,118.688 139.164,118.688C139.348,118.688 139.5,118.84 139.5,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,119.023C141.863,119.211 141.711,119.363 141.523,119.363C141.34,119.363 141.188,119.211 141.188,119.023C141.188,118.84 141.34,118.688 141.523,118.688C141.711,118.688 141.863,118.84 141.863,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,119.023C144.227,119.211 144.074,119.363 143.887,119.363C143.699,119.363 143.551,119.211 143.551,119.023C143.551,118.84 143.699,118.688 143.887,118.688C144.074,118.688 144.227,118.84 144.227,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,119.023C146.586,119.211 146.438,119.363 146.25,119.363C146.062,119.363 145.914,119.211 145.914,119.023C145.914,118.84 146.062,118.688 146.25,118.688C146.438,118.688 146.586,118.84 146.586,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,119.023C148.949,119.211 148.801,119.363 148.613,119.363C148.426,119.363 148.273,119.211 148.273,119.023C148.273,118.84 148.426,118.688 148.613,118.688C148.801,118.688 148.949,118.84 148.949,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,119.023C151.312,119.211 151.16,119.363 150.977,119.363C150.789,119.363 150.637,119.211 150.637,119.023C150.637,118.84 150.789,118.688 150.977,118.688C151.16,118.688 151.312,118.84 151.312,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,119.023C153.676,119.211 153.523,119.363 153.336,119.363C153.152,119.363 153,119.211 153,119.023C153,118.84 153.152,118.688 153.336,118.688C153.523,118.688 153.676,118.84 153.676,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,119.023C156.039,119.211 155.887,119.363 155.699,119.363C155.512,119.363 155.363,119.211 155.363,119.023C155.363,118.84 155.512,118.688 155.699,118.688C155.887,118.688 156.039,118.84 156.039,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,121.387C137.137,121.574 136.988,121.727 136.801,121.727C136.613,121.727 136.461,121.574 136.461,121.387C136.461,121.199 136.613,121.051 136.801,121.051C136.988,121.051 137.137,121.199 137.137,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,121.387C139.5,121.574 139.348,121.727 139.164,121.727C138.977,121.727 138.824,121.574 138.824,121.387C138.824,121.199 138.977,121.051 139.164,121.051C139.348,121.051 139.5,121.199 139.5,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,121.387C141.863,121.574 141.711,121.727 141.523,121.727C141.34,121.727 141.188,121.574 141.188,121.387C141.188,121.199 141.34,121.051 141.523,121.051C141.711,121.051 141.863,121.199 141.863,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,121.387C144.227,121.574 144.074,121.727 143.887,121.727C143.699,121.727 143.551,121.574 143.551,121.387C143.551,121.199 143.699,121.051 143.887,121.051C144.074,121.051 144.227,121.199 144.227,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,121.387C146.586,121.574 146.438,121.727 146.25,121.727C146.062,121.727 145.914,121.574 145.914,121.387C145.914,121.199 146.062,121.051 146.25,121.051C146.438,121.051 146.586,121.199 146.586,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,121.387C148.949,121.574 148.801,121.727 148.613,121.727C148.426,121.727 148.273,121.574 148.273,121.387C148.273,121.199 148.426,121.051 148.613,121.051C148.801,121.051 148.949,121.199 148.949,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,121.387C151.312,121.574 151.16,121.727 150.977,121.727C150.789,121.727 150.637,121.574 150.637,121.387C150.637,121.199 150.789,121.051 150.977,121.051C151.16,121.051 151.312,121.199 151.312,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,121.387C153.676,121.574 153.523,121.727 153.336,121.727C153.152,121.727 153,121.574 153,121.387C153,121.199 153.152,121.051 153.336,121.051C153.523,121.051 153.676,121.199 153.676,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,121.387C156.039,121.574 155.887,121.727 155.699,121.727C155.512,121.727 155.363,121.574 155.363,121.387C155.363,121.199 155.512,121.051 155.699,121.051C155.887,121.051 156.039,121.199 156.039,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,123.75C137.137,123.938 136.988,124.086 136.801,124.086C136.613,124.086 136.461,123.938 136.461,123.75C136.461,123.562 136.613,123.414 136.801,123.414C136.988,123.414 137.137,123.562 137.137,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,123.75C139.5,123.938 139.348,124.086 139.164,124.086C138.977,124.086 138.824,123.938 138.824,123.75C138.824,123.562 138.977,123.414 139.164,123.414C139.348,123.414 139.5,123.562 139.5,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,123.75C141.863,123.938 141.711,124.086 141.523,124.086C141.34,124.086 141.188,123.938 141.188,123.75C141.188,123.562 141.34,123.414 141.523,123.414C141.711,123.414 141.863,123.562 141.863,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,123.75C144.227,123.938 144.074,124.086 143.887,124.086C143.699,124.086 143.551,123.938 143.551,123.75C143.551,123.562 143.699,123.414 143.887,123.414C144.074,123.414 144.227,123.562 144.227,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,123.75C146.586,123.938 146.438,124.086 146.25,124.086C146.062,124.086 145.914,123.938 145.914,123.75C145.914,123.562 146.062,123.414 146.25,123.414C146.438,123.414 146.586,123.562 146.586,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,123.75C148.949,123.938 148.801,124.086 148.613,124.086C148.426,124.086 148.273,123.938 148.273,123.75C148.273,123.562 148.426,123.414 148.613,123.414C148.801,123.414 148.949,123.562 148.949,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,123.75C151.312,123.938 151.16,124.086 150.977,124.086C150.789,124.086 150.637,123.938 150.637,123.75C150.637,123.562 150.789,123.414 150.977,123.414C151.16,123.414 151.312,123.562 151.312,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,123.75C153.676,123.938 153.523,124.086 153.336,124.086C153.152,124.086 153,123.938 153,123.75C153,123.562 153.152,123.414 153.336,123.414C153.523,123.414 153.676,123.562 153.676,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,123.75C156.039,123.938 155.887,124.086 155.699,124.086C155.512,124.086 155.363,123.938 155.363,123.75C155.363,123.562 155.512,123.414 155.699,123.414C155.887,123.414 156.039,123.562 156.039,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,126.113C137.137,126.301 136.988,126.449 136.801,126.449C136.613,126.449 136.461,126.301 136.461,126.113C136.461,125.926 136.613,125.773 136.801,125.773C136.988,125.773 137.137,125.926 137.137,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,126.113C139.5,126.301 139.348,126.449 139.164,126.449C138.977,126.449 138.824,126.301 138.824,126.113C138.824,125.926 138.977,125.773 139.164,125.773C139.348,125.773 139.5,125.926 139.5,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,126.113C141.863,126.301 141.711,126.449 141.523,126.449C141.34,126.449 141.188,126.301 141.188,126.113C141.188,125.926 141.34,125.773 141.523,125.773C141.711,125.773 141.863,125.926 141.863,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,126.113C144.227,126.301 144.074,126.449 143.887,126.449C143.699,126.449 143.551,126.301 143.551,126.113C143.551,125.926 143.699,125.773 143.887,125.773C144.074,125.773 144.227,125.926 144.227,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,126.113C146.586,126.301 146.438,126.449 146.25,126.449C146.062,126.449 145.914,126.301 145.914,126.113C145.914,125.926 146.062,125.773 146.25,125.773C146.438,125.773 146.586,125.926 146.586,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,126.113C148.949,126.301 148.801,126.449 148.613,126.449C148.426,126.449 148.273,126.301 148.273,126.113C148.273,125.926 148.426,125.773 148.613,125.773C148.801,125.773 148.949,125.926 148.949,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,126.113C151.312,126.301 151.16,126.449 150.977,126.449C150.789,126.449 150.637,126.301 150.637,126.113C150.637,125.926 150.789,125.773 150.977,125.773C151.16,125.773 151.312,125.926 151.312,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,126.113C153.676,126.301 153.523,126.449 153.336,126.449C153.152,126.449 153,126.301 153,126.113C153,125.926 153.152,125.773 153.336,125.773C153.523,125.773 153.676,125.926 153.676,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,126.113C156.039,126.301 155.887,126.449 155.699,126.449C155.512,126.449 155.363,126.301 155.363,126.113C155.363,125.926 155.512,125.773 155.699,125.773C155.887,125.773 156.039,125.926 156.039,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,128.477C137.137,128.66 136.988,128.812 136.801,128.812C136.613,128.812 136.461,128.66 136.461,128.477C136.461,128.289 136.613,128.137 136.801,128.137C136.988,128.137 137.137,128.289 137.137,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,128.477C139.5,128.66 139.348,128.812 139.164,128.812C138.977,128.812 138.824,128.66 138.824,128.477C138.824,128.289 138.977,128.137 139.164,128.137C139.348,128.137 139.5,128.289 139.5,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,128.477C141.863,128.66 141.711,128.812 141.523,128.812C141.34,128.812 141.188,128.66 141.188,128.477C141.188,128.289 141.34,128.137 141.523,128.137C141.711,128.137 141.863,128.289 141.863,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,128.477C144.227,128.66 144.074,128.812 143.887,128.812C143.699,128.812 143.551,128.66 143.551,128.477C143.551,128.289 143.699,128.137 143.887,128.137C144.074,128.137 144.227,128.289 144.227,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,128.477C146.586,128.66 146.438,128.812 146.25,128.812C146.062,128.812 145.914,128.66 145.914,128.477C145.914,128.289 146.062,128.137 146.25,128.137C146.438,128.137 146.586,128.289 146.586,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,128.477C148.949,128.66 148.801,128.812 148.613,128.812C148.426,128.812 148.273,128.66 148.273,128.477C148.273,128.289 148.426,128.137 148.613,128.137C148.801,128.137 148.949,128.289 148.949,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,128.477C151.312,128.66 151.16,128.812 150.977,128.812C150.789,128.812 150.637,128.66 150.637,128.477C150.637,128.289 150.789,128.137 150.977,128.137C151.16,128.137 151.312,128.289 151.312,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,128.477C153.676,128.66 153.523,128.812 153.336,128.812C153.152,128.812 153,128.66 153,128.477C153,128.289 153.152,128.137 153.336,128.137C153.523,128.137 153.676,128.289 153.676,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,128.477C156.039,128.66 155.887,128.812 155.699,128.812C155.512,128.812 155.363,128.66 155.363,128.477C155.363,128.289 155.512,128.137 155.699,128.137C155.887,128.137 156.039,128.289 156.039,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,130.836C137.137,131.023 136.988,131.176 136.801,131.176C136.613,131.176 136.461,131.023 136.461,130.836C136.461,130.652 136.613,130.5 136.801,130.5C136.988,130.5 137.137,130.652 137.137,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,130.836C139.5,131.023 139.348,131.176 139.164,131.176C138.977,131.176 138.824,131.023 138.824,130.836C138.824,130.652 138.977,130.5 139.164,130.5C139.348,130.5 139.5,130.652 139.5,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,130.836C141.863,131.023 141.711,131.176 141.523,131.176C141.34,131.176 141.188,131.023 141.188,130.836C141.188,130.652 141.34,130.5 141.523,130.5C141.711,130.5 141.863,130.652 141.863,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,130.836C144.227,131.023 144.074,131.176 143.887,131.176C143.699,131.176 143.551,131.023 143.551,130.836C143.551,130.652 143.699,130.5 143.887,130.5C144.074,130.5 144.227,130.652 144.227,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,130.836C146.586,131.023 146.438,131.176 146.25,131.176C146.062,131.176 145.914,131.023 145.914,130.836C145.914,130.652 146.062,130.5 146.25,130.5C146.438,130.5 146.586,130.652 146.586,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,130.836C148.949,131.023 148.801,131.176 148.613,131.176C148.426,131.176 148.273,131.023 148.273,130.836C148.273,130.652 148.426,130.5 148.613,130.5C148.801,130.5 148.949,130.652 148.949,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,130.836C151.312,131.023 151.16,131.176 150.977,131.176C150.789,131.176 150.637,131.023 150.637,130.836C150.637,130.652 150.789,130.5 150.977,130.5C151.16,130.5 151.312,130.652 151.312,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,130.836C153.676,131.023 153.523,131.176 153.336,131.176C153.152,131.176 153,131.023 153,130.836C153,130.652 153.152,130.5 153.336,130.5C153.523,130.5 153.676,130.652 153.676,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,130.836C156.039,131.023 155.887,131.176 155.699,131.176C155.512,131.176 155.363,131.023 155.363,130.836C155.363,130.652 155.512,130.5 155.699,130.5C155.887,130.5 156.039,130.652 156.039,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M137.137,133.199C137.137,133.387 136.988,133.539 136.801,133.539C136.613,133.539 136.461,133.387 136.461,133.199C136.461,133.012 136.613,132.863 136.801,132.863C136.988,132.863 137.137,133.012 137.137,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M139.5,133.199C139.5,133.387 139.348,133.539 139.164,133.539C138.977,133.539 138.824,133.387 138.824,133.199C138.824,133.012 138.977,132.863 139.164,132.863C139.348,132.863 139.5,133.012 139.5,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M141.863,133.199C141.863,133.387 141.711,133.539 141.523,133.539C141.34,133.539 141.188,133.387 141.188,133.199C141.188,133.012 141.34,132.863 141.523,132.863C141.711,132.863 141.863,133.012 141.863,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M144.227,133.199C144.227,133.387 144.074,133.539 143.887,133.539C143.699,133.539 143.551,133.387 143.551,133.199C143.551,133.012 143.699,132.863 143.887,132.863C144.074,132.863 144.227,133.012 144.227,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M146.586,133.199C146.586,133.387 146.438,133.539 146.25,133.539C146.062,133.539 145.914,133.387 145.914,133.199C145.914,133.012 146.062,132.863 146.25,132.863C146.438,132.863 146.586,133.012 146.586,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M148.949,133.199C148.949,133.387 148.801,133.539 148.613,133.539C148.426,133.539 148.273,133.387 148.273,133.199C148.273,133.012 148.426,132.863 148.613,132.863C148.801,132.863 148.949,133.012 148.949,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M151.312,133.199C151.312,133.387 151.16,133.539 150.977,133.539C150.789,133.539 150.637,133.387 150.637,133.199C150.637,133.012 150.789,132.863 150.977,132.863C151.16,132.863 151.312,133.012 151.312,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M153.676,133.199C153.676,133.387 153.523,133.539 153.336,133.539C153.152,133.539 153,133.387 153,133.199C153,133.012 153.152,132.863 153.336,132.863C153.523,132.863 153.676,133.012 153.676,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M156.039,133.199C156.039,133.387 155.887,133.539 155.699,133.539C155.512,133.539 155.363,133.387 155.363,133.199C155.363,133.012 155.512,132.863 155.699,132.863C155.887,132.863 156.039,133.012 156.039,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="157.5" y="90" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="180" y="33.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="180" y="33.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="202.5" y="22.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M225,45C225,42.047 224.418,39.121 223.289,36.391C222.156,33.66 220.5,31.18 218.41,29.09C216.32,27 213.84,25.344 211.109,24.211C208.379,23.082 205.453,22.5 202.5,22.5L202.5,45L225,45Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="180" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M202.5,0C202.5,2.953 201.918,5.879 200.789,8.609C199.656,11.34 198,13.82 195.91,15.91C193.82,18 191.34,19.656 188.609,20.789C185.879,21.918 182.953,22.5 180,22.5L180,0L202.5,0Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="202.5" y="0" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M204.637,1.801C204.637,1.988 204.488,2.137 204.301,2.137C204.113,2.137 203.961,1.988 203.961,1.801C203.961,1.613 204.113,1.461 204.301,1.461C204.488,1.461 204.637,1.613 204.637,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,1.801C207,1.988 206.848,2.137 206.664,2.137C206.477,2.137 206.324,1.988 206.324,1.801C206.324,1.613 206.477,1.461 206.664,1.461C206.848,1.461 207,1.613 207,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,1.801C209.363,1.988 209.211,2.137 209.023,2.137C208.84,2.137 208.688,1.988 208.688,1.801C208.688,1.613 208.84,1.461 209.023,1.461C209.211,1.461 209.363,1.613 209.363,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,1.801C211.727,1.988 211.574,2.137 211.387,2.137C211.199,2.137 211.051,1.988 211.051,1.801C211.051,1.613 211.199,1.461 211.387,1.461C211.574,1.461 211.727,1.613 211.727,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,1.801C214.086,1.988 213.938,2.137 213.75,2.137C213.562,2.137 213.414,1.988 213.414,1.801C213.414,1.613 213.562,1.461 213.75,1.461C213.938,1.461 214.086,1.613 214.086,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,1.801C216.449,1.988 216.301,2.137 216.113,2.137C215.926,2.137 215.773,1.988 215.773,1.801C215.773,1.613 215.926,1.461 216.113,1.461C216.301,1.461 216.449,1.613 216.449,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,1.801C218.812,1.988 218.66,2.137 218.477,2.137C218.289,2.137 218.137,1.988 218.137,1.801C218.137,1.613 218.289,1.461 218.477,1.461C218.66,1.461 218.812,1.613 218.812,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,1.801C221.176,1.988 221.023,2.137 220.836,2.137C220.652,2.137 220.5,1.988 220.5,1.801C220.5,1.613 220.652,1.461 220.836,1.461C221.023,1.461 221.176,1.613 221.176,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,1.801C223.539,1.988 223.387,2.137 223.199,2.137C223.012,2.137 222.863,1.988 222.863,1.801C222.863,1.613 223.012,1.461 223.199,1.461C223.387,1.461 223.539,1.613 223.539,1.801Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,4.164C204.637,4.348 204.488,4.5 204.301,4.5C204.113,4.5 203.961,4.348 203.961,4.164C203.961,3.977 204.113,3.824 204.301,3.824C204.488,3.824 204.637,3.977 204.637,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,4.164C207,4.348 206.848,4.5 206.664,4.5C206.477,4.5 206.324,4.348 206.324,4.164C206.324,3.977 206.477,3.824 206.664,3.824C206.848,3.824 207,3.977 207,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,4.164C209.363,4.348 209.211,4.5 209.023,4.5C208.84,4.5 208.688,4.348 208.688,4.164C208.688,3.977 208.84,3.824 209.023,3.824C209.211,3.824 209.363,3.977 209.363,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,4.164C211.727,4.348 211.574,4.5 211.387,4.5C211.199,4.5 211.051,4.348 211.051,4.164C211.051,3.977 211.199,3.824 211.387,3.824C211.574,3.824 211.727,3.977 211.727,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,4.164C214.086,4.348 213.938,4.5 213.75,4.5C213.562,4.5 213.414,4.348 213.414,4.164C213.414,3.977 213.562,3.824 213.75,3.824C213.938,3.824 214.086,3.977 214.086,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,4.164C216.449,4.348 216.301,4.5 216.113,4.5C215.926,4.5 215.773,4.348 215.773,4.164C215.773,3.977 215.926,3.824 216.113,3.824C216.301,3.824 216.449,3.977 216.449,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,4.164C218.812,4.348 218.66,4.5 218.477,4.5C218.289,4.5 218.137,4.348 218.137,4.164C218.137,3.977 218.289,3.824 218.477,3.824C218.66,3.824 218.812,3.977 218.812,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,4.164C221.176,4.348 221.023,4.5 220.836,4.5C220.652,4.5 220.5,4.348 220.5,4.164C220.5,3.977 220.652,3.824 220.836,3.824C221.023,3.824 221.176,3.977 221.176,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,4.164C223.539,4.348 223.387,4.5 223.199,4.5C223.012,4.5 222.863,4.348 222.863,4.164C222.863,3.977 223.012,3.824 223.199,3.824C223.387,3.824 223.539,3.977 223.539,4.164Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,6.523C204.637,6.711 204.488,6.863 204.301,6.863C204.113,6.863 203.961,6.711 203.961,6.523C203.961,6.34 204.113,6.188 204.301,6.188C204.488,6.188 204.637,6.34 204.637,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,6.523C207,6.711 206.848,6.863 206.664,6.863C206.477,6.863 206.324,6.711 206.324,6.523C206.324,6.34 206.477,6.188 206.664,6.188C206.848,6.188 207,6.34 207,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,6.523C209.363,6.711 209.211,6.863 209.023,6.863C208.84,6.863 208.688,6.711 208.688,6.523C208.688,6.34 208.84,6.188 209.023,6.188C209.211,6.188 209.363,6.34 209.363,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,6.523C211.727,6.711 211.574,6.863 211.387,6.863C211.199,6.863 211.051,6.711 211.051,6.523C211.051,6.34 211.199,6.188 211.387,6.188C211.574,6.188 211.727,6.34 211.727,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,6.523C214.086,6.711 213.938,6.863 213.75,6.863C213.562,6.863 213.414,6.711 213.414,6.523C213.414,6.34 213.562,6.188 213.75,6.188C213.938,6.188 214.086,6.34 214.086,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,6.523C216.449,6.711 216.301,6.863 216.113,6.863C215.926,6.863 215.773,6.711 215.773,6.523C215.773,6.34 215.926,6.188 216.113,6.188C216.301,6.188 216.449,6.34 216.449,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,6.523C218.812,6.711 218.66,6.863 218.477,6.863C218.289,6.863 218.137,6.711 218.137,6.523C218.137,6.34 218.289,6.188 218.477,6.188C218.66,6.188 218.812,6.34 218.812,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,6.523C221.176,6.711 221.023,6.863 220.836,6.863C220.652,6.863 220.5,6.711 220.5,6.523C220.5,6.34 220.652,6.188 220.836,6.188C221.023,6.188 221.176,6.34 221.176,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,6.523C223.539,6.711 223.387,6.863 223.199,6.863C223.012,6.863 222.863,6.711 222.863,6.523C222.863,6.34 223.012,6.188 223.199,6.188C223.387,6.188 223.539,6.34 223.539,6.523Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,8.887C204.637,9.074 204.488,9.227 204.301,9.227C204.113,9.227 203.961,9.074 203.961,8.887C203.961,8.699 204.113,8.551 204.301,8.551C204.488,8.551 204.637,8.699 204.637,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,8.887C207,9.074 206.848,9.227 206.664,9.227C206.477,9.227 206.324,9.074 206.324,8.887C206.324,8.699 206.477,8.551 206.664,8.551C206.848,8.551 207,8.699 207,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,8.887C209.363,9.074 209.211,9.227 209.023,9.227C208.84,9.227 208.688,9.074 208.688,8.887C208.688,8.699 208.84,8.551 209.023,8.551C209.211,8.551 209.363,8.699 209.363,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,8.887C211.727,9.074 211.574,9.227 211.387,9.227C211.199,9.227 211.051,9.074 211.051,8.887C211.051,8.699 211.199,8.551 211.387,8.551C211.574,8.551 211.727,8.699 211.727,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,8.887C214.086,9.074 213.938,9.227 213.75,9.227C213.562,9.227 213.414,9.074 213.414,8.887C213.414,8.699 213.562,8.551 213.75,8.551C213.938,8.551 214.086,8.699 214.086,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,8.887C216.449,9.074 216.301,9.227 216.113,9.227C215.926,9.227 215.773,9.074 215.773,8.887C215.773,8.699 215.926,8.551 216.113,8.551C216.301,8.551 216.449,8.699 216.449,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,8.887C218.812,9.074 218.66,9.227 218.477,9.227C218.289,9.227 218.137,9.074 218.137,8.887C218.137,8.699 218.289,8.551 218.477,8.551C218.66,8.551 218.812,8.699 218.812,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,8.887C221.176,9.074 221.023,9.227 220.836,9.227C220.652,9.227 220.5,9.074 220.5,8.887C220.5,8.699 220.652,8.551 220.836,8.551C221.023,8.551 221.176,8.699 221.176,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,8.887C223.539,9.074 223.387,9.227 223.199,9.227C223.012,9.227 222.863,9.074 222.863,8.887C222.863,8.699 223.012,8.551 223.199,8.551C223.387,8.551 223.539,8.699 223.539,8.887Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,11.25C204.637,11.438 204.488,11.586 204.301,11.586C204.113,11.586 203.961,11.438 203.961,11.25C203.961,11.062 204.113,10.914 204.301,10.914C204.488,10.914 204.637,11.062 204.637,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,11.25C207,11.438 206.848,11.586 206.664,11.586C206.477,11.586 206.324,11.438 206.324,11.25C206.324,11.062 206.477,10.914 206.664,10.914C206.848,10.914 207,11.062 207,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,11.25C209.363,11.438 209.211,11.586 209.023,11.586C208.84,11.586 208.688,11.438 208.688,11.25C208.688,11.062 208.84,10.914 209.023,10.914C209.211,10.914 209.363,11.062 209.363,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,11.25C211.727,11.438 211.574,11.586 211.387,11.586C211.199,11.586 211.051,11.438 211.051,11.25C211.051,11.062 211.199,10.914 211.387,10.914C211.574,10.914 211.727,11.062 211.727,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,11.25C214.086,11.438 213.938,11.586 213.75,11.586C213.562,11.586 213.414,11.438 213.414,11.25C213.414,11.062 213.562,10.914 213.75,10.914C213.938,10.914 214.086,11.062 214.086,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,11.25C216.449,11.438 216.301,11.586 216.113,11.586C215.926,11.586 215.773,11.438 215.773,11.25C215.773,11.062 215.926,10.914 216.113,10.914C216.301,10.914 216.449,11.062 216.449,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,11.25C218.812,11.438 218.66,11.586 218.477,11.586C218.289,11.586 218.137,11.438 218.137,11.25C218.137,11.062 218.289,10.914 218.477,10.914C218.66,10.914 218.812,11.062 218.812,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,11.25C221.176,11.438 221.023,11.586 220.836,11.586C220.652,11.586 220.5,11.438 220.5,11.25C220.5,11.062 220.652,10.914 220.836,10.914C221.023,10.914 221.176,11.062 221.176,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,11.25C223.539,11.438 223.387,11.586 223.199,11.586C223.012,11.586 222.863,11.438 222.863,11.25C222.863,11.062 223.012,10.914 223.199,10.914C223.387,10.914 223.539,11.062 223.539,11.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,13.613C204.637,13.801 204.488,13.949 204.301,13.949C204.113,13.949 203.961,13.801 203.961,13.613C203.961,13.426 204.113,13.273 204.301,13.273C204.488,13.273 204.637,13.426 204.637,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,13.613C207,13.801 206.848,13.949 206.664,13.949C206.477,13.949 206.324,13.801 206.324,13.613C206.324,13.426 206.477,13.273 206.664,13.273C206.848,13.273 207,13.426 207,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,13.613C209.363,13.801 209.211,13.949 209.023,13.949C208.84,13.949 208.688,13.801 208.688,13.613C208.688,13.426 208.84,13.273 209.023,13.273C209.211,13.273 209.363,13.426 209.363,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,13.613C211.727,13.801 211.574,13.949 211.387,13.949C211.199,13.949 211.051,13.801 211.051,13.613C211.051,13.426 211.199,13.273 211.387,13.273C211.574,13.273 211.727,13.426 211.727,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,13.613C214.086,13.801 213.938,13.949 213.75,13.949C213.562,13.949 213.414,13.801 213.414,13.613C213.414,13.426 213.562,13.273 213.75,13.273C213.938,13.273 214.086,13.426 214.086,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,13.613C216.449,13.801 216.301,13.949 216.113,13.949C215.926,13.949 215.773,13.801 215.773,13.613C215.773,13.426 215.926,13.273 216.113,13.273C216.301,13.273 216.449,13.426 216.449,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,13.613C218.812,13.801 218.66,13.949 218.477,13.949C218.289,13.949 218.137,13.801 218.137,13.613C218.137,13.426 218.289,13.273 218.477,13.273C218.66,13.273 218.812,13.426 218.812,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,13.613C221.176,13.801 221.023,13.949 220.836,13.949C220.652,13.949 220.5,13.801 220.5,13.613C220.5,13.426 220.652,13.273 220.836,13.273C221.023,13.273 221.176,13.426 221.176,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,13.613C223.539,13.801 223.387,13.949 223.199,13.949C223.012,13.949 222.863,13.801 222.863,13.613C222.863,13.426 223.012,13.273 223.199,13.273C223.387,13.273 223.539,13.426 223.539,13.613Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,15.977C204.637,16.16 204.488,16.312 204.301,16.312C204.113,16.312 203.961,16.16 203.961,15.977C203.961,15.789 204.113,15.637 204.301,15.637C204.488,15.637 204.637,15.789 204.637,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,15.977C207,16.16 206.848,16.312 206.664,16.312C206.477,16.312 206.324,16.16 206.324,15.977C206.324,15.789 206.477,15.637 206.664,15.637C206.848,15.637 207,15.789 207,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,15.977C209.363,16.16 209.211,16.312 209.023,16.312C208.84,16.312 208.688,16.16 208.688,15.977C208.688,15.789 208.84,15.637 209.023,15.637C209.211,15.637 209.363,15.789 209.363,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,15.977C211.727,16.16 211.574,16.312 211.387,16.312C211.199,16.312 211.051,16.16 211.051,15.977C211.051,15.789 211.199,15.637 211.387,15.637C211.574,15.637 211.727,15.789 211.727,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,15.977C214.086,16.16 213.938,16.312 213.75,16.312C213.562,16.312 213.414,16.16 213.414,15.977C213.414,15.789 213.562,15.637 213.75,15.637C213.938,15.637 214.086,15.789 214.086,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,15.977C216.449,16.16 216.301,16.312 216.113,16.312C215.926,16.312 215.773,16.16 215.773,15.977C215.773,15.789 215.926,15.637 216.113,15.637C216.301,15.637 216.449,15.789 216.449,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,15.977C218.812,16.16 218.66,16.312 218.477,16.312C218.289,16.312 218.137,16.16 218.137,15.977C218.137,15.789 218.289,15.637 218.477,15.637C218.66,15.637 218.812,15.789 218.812,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,15.977C221.176,16.16 221.023,16.312 220.836,16.312C220.652,16.312 220.5,16.16 220.5,15.977C220.5,15.789 220.652,15.637 220.836,15.637C221.023,15.637 221.176,15.789 221.176,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,15.977C223.539,16.16 223.387,16.312 223.199,16.312C223.012,16.312 222.863,16.16 222.863,15.977C222.863,15.789 223.012,15.637 223.199,15.637C223.387,15.637 223.539,15.789 223.539,15.977Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,18.336C204.637,18.523 204.488,18.676 204.301,18.676C204.113,18.676 203.961,18.523 203.961,18.336C203.961,18.152 204.113,18 204.301,18C204.488,18 204.637,18.152 204.637,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,18.336C207,18.523 206.848,18.676 206.664,18.676C206.477,18.676 206.324,18.523 206.324,18.336C206.324,18.152 206.477,18 206.664,18C206.848,18 207,18.152 207,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,18.336C209.363,18.523 209.211,18.676 209.023,18.676C208.84,18.676 208.688,18.523 208.688,18.336C208.688,18.152 208.84,18 209.023,18C209.211,18 209.363,18.152 209.363,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,18.336C211.727,18.523 211.574,18.676 211.387,18.676C211.199,18.676 211.051,18.523 211.051,18.336C211.051,18.152 211.199,18 211.387,18C211.574,18 211.727,18.152 211.727,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,18.336C214.086,18.523 213.938,18.676 213.75,18.676C213.562,18.676 213.414,18.523 213.414,18.336C213.414,18.152 213.562,18 213.75,18C213.938,18 214.086,18.152 214.086,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,18.336C216.449,18.523 216.301,18.676 216.113,18.676C215.926,18.676 215.773,18.523 215.773,18.336C215.773,18.152 215.926,18 216.113,18C216.301,18 216.449,18.152 216.449,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,18.336C218.812,18.523 218.66,18.676 218.477,18.676C218.289,18.676 218.137,18.523 218.137,18.336C218.137,18.152 218.289,18 218.477,18C218.66,18 218.812,18.152 218.812,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,18.336C221.176,18.523 221.023,18.676 220.836,18.676C220.652,18.676 220.5,18.523 220.5,18.336C220.5,18.152 220.652,18 220.836,18C221.023,18 221.176,18.152 221.176,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,18.336C223.539,18.523 223.387,18.676 223.199,18.676C223.012,18.676 222.863,18.523 222.863,18.336C222.863,18.152 223.012,18 223.199,18C223.387,18 223.539,18.152 223.539,18.336Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M204.637,20.699C204.637,20.887 204.488,21.039 204.301,21.039C204.113,21.039 203.961,20.887 203.961,20.699C203.961,20.512 204.113,20.363 204.301,20.363C204.488,20.363 204.637,20.512 204.637,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M207,20.699C207,20.887 206.848,21.039 206.664,21.039C206.477,21.039 206.324,20.887 206.324,20.699C206.324,20.512 206.477,20.363 206.664,20.363C206.848,20.363 207,20.512 207,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M209.363,20.699C209.363,20.887 209.211,21.039 209.023,21.039C208.84,21.039 208.688,20.887 208.688,20.699C208.688,20.512 208.84,20.363 209.023,20.363C209.211,20.363 209.363,20.512 209.363,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M211.727,20.699C211.727,20.887 211.574,21.039 211.387,21.039C211.199,21.039 211.051,20.887 211.051,20.699C211.051,20.512 211.199,20.363 211.387,20.363C211.574,20.363 211.727,20.512 211.727,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M214.086,20.699C214.086,20.887 213.938,21.039 213.75,21.039C213.562,21.039 213.414,20.887 213.414,20.699C213.414,20.512 213.562,20.363 213.75,20.363C213.938,20.363 214.086,20.512 214.086,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M216.449,20.699C216.449,20.887 216.301,21.039 216.113,21.039C215.926,21.039 215.773,20.887 215.773,20.699C215.773,20.512 215.926,20.363 216.113,20.363C216.301,20.363 216.449,20.512 216.449,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M218.812,20.699C218.812,20.887 218.66,21.039 218.477,21.039C218.289,21.039 218.137,20.887 218.137,20.699C218.137,20.512 218.289,20.363 218.477,20.363C218.66,20.363 218.812,20.512 218.812,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M221.176,20.699C221.176,20.887 221.023,21.039 220.836,21.039C220.652,21.039 220.5,20.887 220.5,20.699C220.5,20.512 220.652,20.363 220.836,20.363C221.023,20.363 221.176,20.512 221.176,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M223.539,20.699C223.539,20.887 223.387,21.039 223.199,21.039C223.012,21.039 222.863,20.887 222.863,20.699C222.863,20.512 223.012,20.363 223.199,20.363C223.387,20.363 223.539,20.512 223.539,20.699Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="202.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="202.5" y="78.75" width="22.5" height="11.25" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="180" y="67.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M191.25,74.812L187.273,78.789L191.25,82.766L195.227,78.789L191.25,74.812Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="180" y="45" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M180,67.5C180,64.547 180.582,61.621 181.711,58.891C182.844,56.16 184.5,53.68 186.59,51.59C188.68,49.5 191.16,47.844 193.891,46.711C196.621,45.582 199.547,45 202.5,45L202.5,67.5L180,67.5Z" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="202.5" y="45" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<path d="M208.125,56.25C208.125,59.355 210.645,61.875 213.75,61.875C216.855,61.875 219.375,59.355 219.375,56.25C219.375,53.145 216.855,50.625 213.75,50.625C210.645,50.625 208.125,53.145 208.125,56.25Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M180,90L180,112.5L202.5,90L180,90Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<rect x="202.5" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,153,255);fill-rule:nonzero;"/>
<rect x="180" y="112.5" width="22.5" height="22.5" style="fill:rgb(255,204,255);fill-rule:nonzero;"/>
<path d="M182.137,114.301C182.137,114.488 181.988,114.637 181.801,114.637C181.613,114.637 181.461,114.488 181.461,114.301C181.461,114.113 181.613,113.961 181.801,113.961C181.988,113.961 182.137,114.113 182.137,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,114.301C184.5,114.488 184.348,114.637 184.164,114.637C183.977,114.637 183.824,114.488 183.824,114.301C183.824,114.113 183.977,113.961 184.164,113.961C184.348,113.961 184.5,114.113 184.5,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,114.301C186.863,114.488 186.711,114.637 186.523,114.637C186.34,114.637 186.188,114.488 186.188,114.301C186.188,114.113 186.34,113.961 186.523,113.961C186.711,113.961 186.863,114.113 186.863,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,114.301C189.227,114.488 189.074,114.637 188.887,114.637C188.699,114.637 188.551,114.488 188.551,114.301C188.551,114.113 188.699,113.961 188.887,113.961C189.074,113.961 189.227,114.113 189.227,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,114.301C191.586,114.488 191.438,114.637 191.25,114.637C191.062,114.637 190.914,114.488 190.914,114.301C190.914,114.113 191.062,113.961 191.25,113.961C191.438,113.961 191.586,114.113 191.586,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,114.301C193.949,114.488 193.801,114.637 193.613,114.637C193.426,114.637 193.273,114.488 193.273,114.301C193.273,114.113 193.426,113.961 193.613,113.961C193.801,113.961 193.949,114.113 193.949,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,114.301C196.312,114.488 196.16,114.637 195.977,114.637C195.789,114.637 195.637,114.488 195.637,114.301C195.637,114.113 195.789,113.961 195.977,113.961C196.16,113.961 196.312,114.113 196.312,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,114.301C198.676,114.488 198.523,114.637 198.336,114.637C198.152,114.637 198,114.488 198,114.301C198,114.113 198.152,113.961 198.336,113.961C198.523,113.961 198.676,114.113 198.676,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,114.301C201.039,114.488 200.887,114.637 200.699,114.637C200.512,114.637 200.363,114.488 200.363,114.301C200.363,114.113 200.512,113.961 200.699,113.961C200.887,113.961 201.039,114.113 201.039,114.301Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,116.664C182.137,116.848 181.988,117 181.801,117C181.613,117 181.461,116.848 181.461,116.664C181.461,116.477 181.613,116.324 181.801,116.324C181.988,116.324 182.137,116.477 182.137,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,116.664C184.5,116.848 184.348,117 184.164,117C183.977,117 183.824,116.848 183.824,116.664C183.824,116.477 183.977,116.324 184.164,116.324C184.348,116.324 184.5,116.477 184.5,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,116.664C186.863,116.848 186.711,117 186.523,117C186.34,117 186.188,116.848 186.188,116.664C186.188,116.477 186.34,116.324 186.523,116.324C186.711,116.324 186.863,116.477 186.863,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,116.664C189.227,116.848 189.074,117 188.887,117C188.699,117 188.551,116.848 188.551,116.664C188.551,116.477 188.699,116.324 188.887,116.324C189.074,116.324 189.227,116.477 189.227,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,116.664C191.586,116.848 191.438,117 191.25,117C191.062,117 190.914,116.848 190.914,116.664C190.914,116.477 191.062,116.324 191.25,116.324C191.438,116.324 191.586,116.477 191.586,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,116.664C193.949,116.848 193.801,117 193.613,117C193.426,117 193.273,116.848 193.273,116.664C193.273,116.477 193.426,116.324 193.613,116.324C193.801,116.324 193.949,116.477 193.949,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,116.664C196.312,116.848 196.16,117 195.977,117C195.789,117 195.637,116.848 195.637,116.664C195.637,116.477 195.789,116.324 195.977,116.324C196.16,116.324 196.312,116.477 196.312,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,116.664C198.676,116.848 198.523,117 198.336,117C198.152,117 198,116.848 198,116.664C198,116.477 198.152,116.324 198.336,116.324C198.523,116.324 198.676,116.477 198.676,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,116.664C201.039,116.848 200.887,117 200.699,117C200.512,117 200.363,116.848 200.363,116.664C200.363,116.477 200.512,116.324 200.699,116.324C200.887,116.324 201.039,116.477 201.039,116.664Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,119.023C182.137,119.211 181.988,119.363 181.801,119.363C181.613,119.363 181.461,119.211 181.461,119.023C181.461,118.84 181.613,118.688 181.801,118.688C181.988,118.688 182.137,118.84 182.137,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,119.023C184.5,119.211 184.348,119.363 184.164,119.363C183.977,119.363 183.824,119.211 183.824,119.023C183.824,118.84 183.977,118.688 184.164,118.688C184.348,118.688 184.5,118.84 184.5,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,119.023C186.863,119.211 186.711,119.363 186.523,119.363C186.34,119.363 186.188,119.211 186.188,119.023C186.188,118.84 186.34,118.688 186.523,118.688C186.711,118.688 186.863,118.84 186.863,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,119.023C189.227,119.211 189.074,119.363 188.887,119.363C188.699,119.363 188.551,119.211 188.551,119.023C188.551,118.84 188.699,118.688 188.887,118.688C189.074,118.688 189.227,118.84 189.227,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,119.023C191.586,119.211 191.438,119.363 191.25,119.363C191.062,119.363 190.914,119.211 190.914,119.023C190.914,118.84 191.062,118.688 191.25,118.688C191.438,118.688 191.586,118.84 191.586,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,119.023C193.949,119.211 193.801,119.363 193.613,119.363C193.426,119.363 193.273,119.211 193.273,119.023C193.273,118.84 193.426,118.688 193.613,118.688C193.801,118.688 193.949,118.84 193.949,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,119.023C196.312,119.211 196.16,119.363 195.977,119.363C195.789,119.363 195.637,119.211 195.637,119.023C195.637,118.84 195.789,118.688 195.977,118.688C196.16,118.688 196.312,118.84 196.312,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,119.023C198.676,119.211 198.523,119.363 198.336,119.363C198.152,119.363 198,119.211 198,119.023C198,118.84 198.152,118.688 198.336,118.688C198.523,118.688 198.676,118.84 198.676,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,119.023C201.039,119.211 200.887,119.363 200.699,119.363C200.512,119.363 200.363,119.211 200.363,119.023C200.363,118.84 200.512,118.688 200.699,118.688C200.887,118.688 201.039,118.84 201.039,119.023Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,121.387C182.137,121.574 181.988,121.727 181.801,121.727C181.613,121.727 181.461,121.574 181.461,121.387C181.461,121.199 181.613,121.051 181.801,121.051C181.988,121.051 182.137,121.199 182.137,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,121.387C184.5,121.574 184.348,121.727 184.164,121.727C183.977,121.727 183.824,121.574 183.824,121.387C183.824,121.199 183.977,121.051 184.164,121.051C184.348,121.051 184.5,121.199 184.5,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,121.387C186.863,121.574 186.711,121.727 186.523,121.727C186.34,121.727 186.188,121.574 186.188,121.387C186.188,121.199 186.34,121.051 186.523,121.051C186.711,121.051 186.863,121.199 186.863,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,121.387C189.227,121.574 189.074,121.727 188.887,121.727C188.699,121.727 188.551,121.574 188.551,121.387C188.551,121.199 188.699,121.051 188.887,121.051C189.074,121.051 189.227,121.199 189.227,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,121.387C191.586,121.574 191.438,121.727 191.25,121.727C191.062,121.727 190.914,121.574 190.914,121.387C190.914,121.199 191.062,121.051 191.25,121.051C191.438,121.051 191.586,121.199 191.586,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,121.387C193.949,121.574 193.801,121.727 193.613,121.727C193.426,121.727 193.273,121.574 193.273,121.387C193.273,121.199 193.426,121.051 193.613,121.051C193.801,121.051 193.949,121.199 193.949,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,121.387C196.312,121.574 196.16,121.727 195.977,121.727C195.789,121.727 195.637,121.574 195.637,121.387C195.637,121.199 195.789,121.051 195.977,121.051C196.16,121.051 196.312,121.199 196.312,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,121.387C198.676,121.574 198.523,121.727 198.336,121.727C198.152,121.727 198,121.574 198,121.387C198,121.199 198.152,121.051 198.336,121.051C198.523,121.051 198.676,121.199 198.676,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,121.387C201.039,121.574 200.887,121.727 200.699,121.727C200.512,121.727 200.363,121.574 200.363,121.387C200.363,121.199 200.512,121.051 200.699,121.051C200.887,121.051 201.039,121.199 201.039,121.387Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,123.75C182.137,123.938 181.988,124.086 181.801,124.086C181.613,124.086 181.461,123.938 181.461,123.75C181.461,123.562 181.613,123.414 181.801,123.414C181.988,123.414 182.137,123.562 182.137,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,123.75C184.5,123.938 184.348,124.086 184.164,124.086C183.977,124.086 183.824,123.938 183.824,123.75C183.824,123.562 183.977,123.414 184.164,123.414C184.348,123.414 184.5,123.562 184.5,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,123.75C186.863,123.938 186.711,124.086 186.523,124.086C186.34,124.086 186.188,123.938 186.188,123.75C186.188,123.562 186.34,123.414 186.523,123.414C186.711,123.414 186.863,123.562 186.863,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,123.75C189.227,123.938 189.074,124.086 188.887,124.086C188.699,124.086 188.551,123.938 188.551,123.75C188.551,123.562 188.699,123.414 188.887,123.414C189.074,123.414 189.227,123.562 189.227,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,123.75C191.586,123.938 191.438,124.086 191.25,124.086C191.062,124.086 190.914,123.938 190.914,123.75C190.914,123.562 191.062,123.414 191.25,123.414C191.438,123.414 191.586,123.562 191.586,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,123.75C193.949,123.938 193.801,124.086 193.613,124.086C193.426,124.086 193.273,123.938 193.273,123.75C193.273,123.562 193.426,123.414 193.613,123.414C193.801,123.414 193.949,123.562 193.949,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,123.75C196.312,123.938 196.16,124.086 195.977,124.086C195.789,124.086 195.637,123.938 195.637,123.75C195.637,123.562 195.789,123.414 195.977,123.414C196.16,123.414 196.312,123.562 196.312,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,123.75C198.676,123.938 198.523,124.086 198.336,124.086C198.152,124.086 198,123.938 198,123.75C198,123.562 198.152,123.414 198.336,123.414C198.523,123.414 198.676,123.562 198.676,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,123.75C201.039,123.938 200.887,124.086 200.699,124.086C200.512,124.086 200.363,123.938 200.363,123.75C200.363,123.562 200.512,123.414 200.699,123.414C200.887,123.414 201.039,123.562 201.039,123.75Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,126.113C182.137,126.301 181.988,126.449 181.801,126.449C181.613,126.449 181.461,126.301 181.461,126.113C181.461,125.926 181.613,125.773 181.801,125.773C181.988,125.773 182.137,125.926 182.137,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,126.113C184.5,126.301 184.348,126.449 184.164,126.449C183.977,126.449 183.824,126.301 183.824,126.113C183.824,125.926 183.977,125.773 184.164,125.773C184.348,125.773 184.5,125.926 184.5,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,126.113C186.863,126.301 186.711,126.449 186.523,126.449C186.34,126.449 186.188,126.301 186.188,126.113C186.188,125.926 186.34,125.773 186.523,125.773C186.711,125.773 186.863,125.926 186.863,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,126.113C189.227,126.301 189.074,126.449 188.887,126.449C188.699,126.449 188.551,126.301 188.551,126.113C188.551,125.926 188.699,125.773 188.887,125.773C189.074,125.773 189.227,125.926 189.227,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,126.113C191.586,126.301 191.438,126.449 191.25,126.449C191.062,126.449 190.914,126.301 190.914,126.113C190.914,125.926 191.062,125.773 191.25,125.773C191.438,125.773 191.586,125.926 191.586,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,126.113C193.949,126.301 193.801,126.449 193.613,126.449C193.426,126.449 193.273,126.301 193.273,126.113C193.273,125.926 193.426,125.773 193.613,125.773C193.801,125.773 193.949,125.926 193.949,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,126.113C196.312,126.301 196.16,126.449 195.977,126.449C195.789,126.449 195.637,126.301 195.637,126.113C195.637,125.926 195.789,125.773 195.977,125.773C196.16,125.773 196.312,125.926 196.312,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,126.113C198.676,126.301 198.523,126.449 198.336,126.449C198.152,126.449 198,126.301 198,126.113C198,125.926 198.152,125.773 198.336,125.773C198.523,125.773 198.676,125.926 198.676,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,126.113C201.039,126.301 200.887,126.449 200.699,126.449C200.512,126.449 200.363,126.301 200.363,126.113C200.363,125.926 200.512,125.773 200.699,125.773C200.887,125.773 201.039,125.926 201.039,126.113Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,128.477C182.137,128.66 181.988,128.812 181.801,128.812C181.613,128.812 181.461,128.66 181.461,128.477C181.461,128.289 181.613,128.137 181.801,128.137C181.988,128.137 182.137,128.289 182.137,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,128.477C184.5,128.66 184.348,128.812 184.164,128.812C183.977,128.812 183.824,128.66 183.824,128.477C183.824,128.289 183.977,128.137 184.164,128.137C184.348,128.137 184.5,128.289 184.5,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,128.477C186.863,128.66 186.711,128.812 186.523,128.812C186.34,128.812 186.188,128.66 186.188,128.477C186.188,128.289 186.34,128.137 186.523,128.137C186.711,128.137 186.863,128.289 186.863,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,128.477C189.227,128.66 189.074,128.812 188.887,128.812C188.699,128.812 188.551,128.66 188.551,128.477C188.551,128.289 188.699,128.137 188.887,128.137C189.074,128.137 189.227,128.289 189.227,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,128.477C191.586,128.66 191.438,128.812 191.25,128.812C191.062,128.812 190.914,128.66 190.914,128.477C190.914,128.289 191.062,128.137 191.25,128.137C191.438,128.137 191.586,128.289 191.586,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,128.477C193.949,128.66 193.801,128.812 193.613,128.812C193.426,128.812 193.273,128.66 193.273,128.477C193.273,128.289 193.426,128.137 193.613,128.137C193.801,128.137 193.949,128.289 193.949,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,128.477C196.312,128.66 196.16,128.812 195.977,128.812C195.789,128.812 195.637,128.66 195.637,128.477C195.637,128.289 195.789,128.137 195.977,128.137C196.16,128.137 196.312,128.289 196.312,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,128.477C198.676,128.66 198.523,128.812 198.336,128.812C198.152,128.812 198,128.66 198,128.477C198,128.289 198.152,128.137 198.336,128.137C198.523,128.137 198.676,128.289 198.676,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,128.477C201.039,128.66 200.887,128.812 200.699,128.812C200.512,128.812 200.363,128.66 200.363,128.477C200.363,128.289 200.512,128.137 200.699,128.137C200.887,128.137 201.039,128.289 201.039,128.477Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,130.836C182.137,131.023 181.988,131.176 181.801,131.176C181.613,131.176 181.461,131.023 181.461,130.836C181.461,130.652 181.613,130.5 181.801,130.5C181.988,130.5 182.137,130.652 182.137,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,130.836C184.5,131.023 184.348,131.176 184.164,131.176C183.977,131.176 183.824,131.023 183.824,130.836C183.824,130.652 183.977,130.5 184.164,130.5C184.348,130.5 184.5,130.652 184.5,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,130.836C186.863,131.023 186.711,131.176 186.523,131.176C186.34,131.176 186.188,131.023 186.188,130.836C186.188,130.652 186.34,130.5 186.523,130.5C186.711,130.5 186.863,130.652 186.863,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,130.836C189.227,131.023 189.074,131.176 188.887,131.176C188.699,131.176 188.551,131.023 188.551,130.836C188.551,130.652 188.699,130.5 188.887,130.5C189.074,130.5 189.227,130.652 189.227,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,130.836C191.586,131.023 191.438,131.176 191.25,131.176C191.062,131.176 190.914,131.023 190.914,130.836C190.914,130.652 191.062,130.5 191.25,130.5C191.438,130.5 191.586,130.652 191.586,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,130.836C193.949,131.023 193.801,131.176 193.613,131.176C193.426,131.176 193.273,131.023 193.273,130.836C193.273,130.652 193.426,130.5 193.613,130.5C193.801,130.5 193.949,130.652 193.949,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,130.836C196.312,131.023 196.16,131.176 195.977,131.176C195.789,131.176 195.637,131.023 195.637,130.836C195.637,130.652 195.789,130.5 195.977,130.5C196.16,130.5 196.312,130.652 196.312,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,130.836C198.676,131.023 198.523,131.176 198.336,131.176C198.152,131.176 198,131.023 198,130.836C198,130.652 198.152,130.5 198.336,130.5C198.523,130.5 198.676,130.652 198.676,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,130.836C201.039,131.023 200.887,131.176 200.699,131.176C200.512,131.176 200.363,131.023 200.363,130.836C200.363,130.652 200.512,130.5 200.699,130.5C200.887,130.5 201.039,130.652 201.039,130.836Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M182.137,133.199C182.137,133.387 181.988,133.539 181.801,133.539C181.613,133.539 181.461,133.387 181.461,133.199C181.461,133.012 181.613,132.863 181.801,132.863C181.988,132.863 182.137,133.012 182.137,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M184.5,133.199C184.5,133.387 184.348,133.539 184.164,133.539C183.977,133.539 183.824,133.387 183.824,133.199C183.824,133.012 183.977,132.863 184.164,132.863C184.348,132.863 184.5,133.012 184.5,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M186.863,133.199C186.863,133.387 186.711,133.539 186.523,133.539C186.34,133.539 186.188,133.387 186.188,133.199C186.188,133.012 186.34,132.863 186.523,132.863C186.711,132.863 186.863,133.012 186.863,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M189.227,133.199C189.227,133.387 189.074,133.539 188.887,133.539C188.699,133.539 188.551,133.387 188.551,133.199C188.551,133.012 188.699,132.863 188.887,132.863C189.074,132.863 189.227,133.012 189.227,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M191.586,133.199C191.586,133.387 191.438,133.539 191.25,133.539C191.062,133.539 190.914,133.387 190.914,133.199C190.914,133.012 191.062,132.863 191.25,132.863C191.438,132.863 191.586,133.012 191.586,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M193.949,133.199C193.949,133.387 193.801,133.539 193.613,133.539C193.426,133.539 193.273,133.387 193.273,133.199C193.273,133.012 193.426,132.863 193.613,132.863C193.801,132.863 193.949,133.012 193.949,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M196.312,133.199C196.312,133.387 196.16,133.539 195.977,133.539C195.789,133.539 195.637,133.387 195.637,133.199C195.637,133.012 195.789,132.863 195.977,132.863C196.16,132.863 196.312,133.012 196.312,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M198.676,133.199C198.676,133.387 198.523,133.539 198.336,133.539C198.152,133.539 198,133.387 198,133.199C198,133.012 198.152,132.863 198.336,132.863C198.523,132.863 198.676,133.012 198.676,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
<path d="M201.039,133.199C201.039,133.387 200.887,133.539 200.699,133.539C200.512,133.539 200.363,133.387 200.363,133.199C200.363,133.012 200.512,132.863 200.699,132.863C200.887,132.863 201.039,133.012 201.039,133.199Z" style="fill:rgb(204,102,204);fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 159 KiB

View File

@ -1,495 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 640 352" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:bevel;">
<g id="svg_2" transform="matrix(0.725068,0,0,0.69557,-5.66008,-5.07263)">
<g>
<g transform="matrix(1.37918,0,0,1.43767,7.80628,7.29276)">
<rect x="0" y="0" width="640" height="351.059" style="fill:rgb(235,235,235);"/>
</g>
<rect x="0" y="0" width="900" height="512" style="fill:rgb(69,40,103);fill-rule:nonzero;"/>
<g transform="matrix(1,0.57735,0,1,0,-11.547)">
<rect x="0" y="10" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,34.641)">
<rect x="40" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-57.735)">
<rect x="80" y="10" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,80.829)">
<rect x="120" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-103.923)">
<rect x="160" y="10" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,127.017)">
<rect x="200" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-150.111)">
<rect x="240" y="10" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,173.205)">
<rect x="280" y="10" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-196.3)">
<rect x="320" y="10" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,219.393)">
<rect x="360" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-242.487)">
<rect x="400" y="10" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,265.581)">
<rect x="440" y="10" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-288.675)">
<rect x="480" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,311.77)">
<rect x="520" y="10" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-334.863)">
<rect x="560" y="10" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,357.957)">
<rect x="600" y="10" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-381.051)">
<rect x="640" y="10" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,404.145)">
<rect x="680" y="10" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-427.24)">
<rect x="720" y="10" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,450.333)">
<rect x="760" y="10" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-473.427)">
<rect x="800" y="10" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,496.521)">
<rect x="840" y="10" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-519.615)">
<rect x="880" y="10" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,11.547)">
<rect x="0" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-34.641)">
<rect x="40" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,57.735)">
<rect x="80" y="83.09" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-80.829)">
<rect x="120" y="83.09" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,103.923)">
<rect x="160" y="83.09" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-127.017)">
<rect x="200" y="83.09" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,150.111)">
<rect x="240" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-173.205)">
<rect x="280" y="83.09" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,196.3)">
<rect x="320" y="83.09" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-219.393)">
<rect x="360" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,242.487)">
<rect x="400" y="83.09" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-265.581)">
<rect x="440" y="83.09" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,288.675)">
<rect x="480" y="83.09" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-311.77)">
<rect x="520" y="83.09" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,334.863)">
<rect x="560" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-357.957)">
<rect x="600" y="83.09" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,381.051)">
<rect x="640" y="83.09" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-404.145)">
<rect x="680" y="83.09" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,427.24)">
<rect x="720" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-450.333)">
<rect x="760" y="83.09" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,473.427)">
<rect x="800" y="83.09" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-496.521)">
<rect x="840" y="83.09" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,519.615)">
<rect x="880" y="83.09" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-11.547)">
<rect x="0" y="156.19" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,34.641)">
<rect x="40" y="156.19" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-57.735)">
<rect x="80" y="156.19" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,80.829)">
<rect x="120" y="156.19" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-103.923)">
<rect x="160" y="156.19" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,127.017)">
<rect x="200" y="156.19" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-150.111)">
<rect x="240" y="156.19" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,173.205)">
<rect x="280" y="156.19" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-196.3)">
<rect x="320" y="156.19" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,219.393)">
<rect x="360" y="156.19" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-242.487)">
<rect x="400" y="156.19" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,265.581)">
<rect x="440" y="156.19" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-288.675)">
<rect x="480" y="156.19" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,311.77)">
<rect x="520" y="156.19" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-334.863)">
<rect x="560" y="156.19" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,357.957)">
<rect x="600" y="156.19" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-381.051)">
<rect x="640" y="156.19" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,404.145)">
<rect x="680" y="156.19" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-427.24)">
<rect x="720" y="156.19" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,450.333)">
<rect x="760" y="156.19" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-473.427)">
<rect x="800" y="156.19" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,496.521)">
<rect x="840" y="156.19" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-519.615)">
<rect x="880" y="156.19" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,11.547)">
<rect x="0" y="229.28" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-34.641)">
<rect x="40" y="229.28" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,57.735)">
<rect x="80" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-80.829)">
<rect x="120" y="229.28" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,103.923)">
<rect x="160" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-127.017)">
<rect x="200" y="229.28" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,150.111)">
<rect x="240" y="229.28" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-173.205)">
<rect x="280" y="229.28" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,196.3)">
<rect x="320" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-219.393)">
<rect x="360" y="229.28" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,242.487)">
<rect x="400" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-265.581)">
<rect x="440" y="229.28" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,288.675)">
<rect x="480" y="229.28" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-311.77)">
<rect x="520" y="229.28" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,334.863)">
<rect x="560" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-357.957)">
<rect x="600" y="229.28" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,381.051)">
<rect x="640" y="229.28" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-404.145)">
<rect x="680" y="229.28" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,427.24)">
<rect x="720" y="229.28" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-450.333)">
<rect x="760" y="229.28" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,473.427)">
<rect x="800" y="229.28" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-496.521)">
<rect x="840" y="229.28" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,519.615)">
<rect x="880" y="229.28" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-11.547)">
<rect x="0" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,34.641)">
<rect x="40" y="302.38" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-57.735)">
<rect x="80" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,80.829)">
<rect x="120" y="302.38" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-103.923)">
<rect x="160" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,127.017)">
<rect x="200" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-150.111)">
<rect x="240" y="302.38" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,173.205)">
<rect x="280" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-196.3)">
<rect x="320" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,219.393)">
<rect x="360" y="302.38" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-242.487)">
<rect x="400" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,265.581)">
<rect x="440" y="302.38" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-288.675)">
<rect x="480" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,311.77)">
<rect x="520" y="302.38" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-334.863)">
<rect x="560" y="302.38" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,357.957)">
<rect x="600" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-381.051)">
<rect x="640" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,404.145)">
<rect x="680" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-427.24)">
<rect x="720" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,450.333)">
<rect x="760" y="302.38" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-473.427)">
<rect x="800" y="302.38" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,496.521)">
<rect x="840" y="302.38" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-519.615)">
<rect x="880" y="302.38" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,11.547)">
<rect x="0" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-34.641)">
<rect x="40" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,57.735)">
<rect x="80" y="375.47" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-80.829)">
<rect x="120" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,103.923)">
<rect x="160" y="375.47" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-127.017)">
<rect x="200" y="375.47" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,150.111)">
<rect x="240" y="375.47" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-173.205)">
<rect x="280" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,196.3)">
<rect x="320" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-219.393)">
<rect x="360" y="375.47" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,242.487)">
<rect x="400" y="375.47" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-265.581)">
<rect x="440" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,288.675)">
<rect x="480" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-311.77)">
<rect x="520" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,334.863)">
<rect x="560" y="375.47" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-357.957)">
<rect x="600" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,381.051)">
<rect x="640" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-404.145)">
<rect x="680" y="375.47" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,427.24)">
<rect x="720" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-450.333)">
<rect x="760" y="375.47" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,473.427)">
<rect x="800" y="375.47" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-496.521)">
<rect x="840" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,519.615)">
<rect x="880" y="375.47" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-11.547)">
<rect x="0" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,34.641)">
<rect x="40" y="448.56" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-57.735)">
<rect x="80" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,80.829)">
<rect x="120" y="448.56" width="40" height="50" style="fill:rgb(141,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-103.923)">
<rect x="160" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,127.017)">
<rect x="200" y="448.56" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-150.111)">
<rect x="240" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,173.205)">
<rect x="280" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-196.3)">
<rect x="320" y="448.56" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,219.393)">
<rect x="360" y="448.56" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-242.487)">
<rect x="400" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,265.581)">
<rect x="440" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-288.675)">
<rect x="480" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,311.77)">
<rect x="520" y="448.56" width="40" height="50" style="fill:rgb(70,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-334.863)">
<rect x="560" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,357.957)">
<rect x="600" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-381.051)">
<rect x="640" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,404.145)">
<rect x="680" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-427.24)">
<rect x="720" y="448.56" width="40" height="50" style="fill:rgb(164,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,450.333)">
<rect x="760" y="448.56" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-473.427)">
<rect x="800" y="448.56" width="40" height="50" style="fill:rgb(176,58,164);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,-0.57735,0,1,0,496.521)">
<rect x="840" y="448.56" width="40" height="50" style="fill:rgb(93,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0.57735,0,1,0,-519.615)">
<rect x="880" y="448.56" width="40" height="50" style="fill:rgb(117,58,176);fill-rule:nonzero;stroke:rgb(69,40,103);stroke-width:2px;"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 300 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 876 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 805 KiB

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 578 390" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-97.9033,-93.9591)">
<g>
<path d="M394.544,93.959L527.058,93.959C511.637,111.95 493.464,127.07 460.801,127.07C428.138,127.07 409.965,111.95 394.544,93.959Z" style="fill:rgb(255,204,0);"/>
<path d="M97.903,105.151L97.903,93.959L219.856,93.959C204.435,111.95 186.263,127.07 153.602,127.07C128.034,127.07 111.344,117.805 97.903,105.151Z" style="fill:rgb(255,204,0);"/>
<path d="M527.058,93.959L556.407,93.959C528.979,121.265 514.397,161.977 460.801,161.977C407.204,161.977 392.622,121.265 365.193,93.959L394.544,93.959C409.965,111.95 428.138,127.07 460.801,127.07C493.464,127.07 511.637,111.95 527.058,93.959Z" style="fill:rgb(204,153,0);"/>
<path d="M97.903,140.057L97.903,105.151C111.344,117.805 128.034,127.07 153.602,127.07C186.263,127.07 204.435,111.95 219.856,93.959L249.205,93.959C221.777,121.265 207.196,161.977 153.602,161.977C128.034,161.977 111.344,152.712 97.903,140.057Z" style="fill:rgb(204,153,0);"/>
<path d="M97.903,174.968L97.903,140.057C111.344,152.712 128.034,161.977 153.602,161.977C207.196,161.977 221.777,121.265 249.205,93.959L365.193,93.959C392.622,121.265 407.204,161.977 460.801,161.977C514.397,161.977 528.979,121.265 556.407,93.959L675,93.959L675,131.544C660.693,116.455 643.165,104.727 614.398,104.727C533.762,104.727 541.441,196.887 460.801,196.887C380.16,196.887 387.84,104.727 307.199,104.727C226.559,104.727 234.238,196.887 153.602,196.887C128.034,196.887 111.344,187.622 97.903,174.968Z" style="fill:rgb(255,204,51);"/>
<path d="M97.903,209.878L97.903,174.968C111.344,187.622 128.034,196.887 153.602,196.887C234.238,196.887 226.559,104.727 307.199,104.727C387.84,104.727 380.16,196.887 460.801,196.887C541.441,196.887 533.762,104.727 614.398,104.727C643.165,104.727 660.693,116.455 675,131.544L675,166.454C660.693,151.365 643.165,139.637 614.398,139.637C533.762,139.637 541.441,231.797 460.801,231.797C380.16,231.797 387.84,139.637 307.199,139.637C226.559,139.637 234.238,231.797 153.602,231.797C128.034,231.797 111.344,222.532 97.903,209.878Z" style="fill:rgb(153,102,51);"/>
<path d="M97.903,244.788L97.903,209.878C111.344,222.532 128.034,231.797 153.602,231.797C234.238,231.797 226.559,139.637 307.199,139.637C387.84,139.637 380.16,231.797 460.801,231.797C541.441,231.797 533.762,139.637 614.398,139.637C643.165,139.637 660.693,151.365 675,166.454L675,201.364C660.693,186.275 643.165,174.547 614.398,174.547C533.762,174.547 541.441,266.707 460.801,266.707C380.16,266.707 387.84,174.547 307.199,174.547C226.559,174.547 234.238,266.707 153.602,266.707C128.034,266.707 111.344,257.442 97.903,244.788Z" style="fill:rgb(255,153,0);"/>
<path d="M97.903,279.694L97.903,244.788C111.344,257.442 128.034,266.707 153.602,266.707C234.238,266.707 226.559,174.547 307.199,174.547C387.84,174.547 380.16,266.707 460.801,266.707C541.441,266.707 533.762,174.547 614.398,174.547C643.165,174.547 660.693,186.275 675,201.364L675,236.27C660.693,221.181 643.165,209.453 614.398,209.453C533.762,209.453 541.441,301.613 460.801,301.613C380.16,301.613 387.84,209.453 307.199,209.453C226.559,209.453 234.238,301.613 153.602,301.613C128.034,301.613 111.344,292.348 97.903,279.694Z" style="fill:rgb(255,204,0);"/>
<path d="M97.903,314.604L97.903,279.694C111.344,292.348 128.034,301.613 153.602,301.613C234.238,301.613 226.559,209.453 307.199,209.453C387.84,209.453 380.16,301.613 460.801,301.613C541.441,301.613 533.762,209.453 614.398,209.453C643.165,209.453 660.693,221.181 675,236.27L675,271.18C660.693,256.091 643.165,244.363 614.398,244.363C533.762,244.363 541.441,336.523 460.801,336.523C380.16,336.523 387.84,244.363 307.199,244.363C226.559,244.363 234.238,336.523 153.602,336.523C128.034,336.523 111.344,327.258 97.903,314.604Z" style="fill:rgb(204,153,0);"/>
<path d="M97.903,349.515L97.903,314.604C111.344,327.258 128.034,336.523 153.602,336.523C234.238,336.523 226.559,244.363 307.199,244.363C387.84,244.363 380.16,336.523 460.801,336.523C541.441,336.523 533.762,244.363 614.398,244.363C643.165,244.363 660.693,256.091 675,271.18L675,306.09C660.693,291.001 643.165,279.273 614.398,279.273C533.762,279.273 541.441,371.434 460.801,371.434C380.16,371.434 387.84,279.273 307.199,279.273C226.559,279.273 234.238,371.434 153.602,371.434C128.034,371.434 111.344,362.169 97.903,349.515Z" style="fill:rgb(255,204,51);"/>
<path d="M97.903,384.425L97.903,349.515C111.344,362.169 128.034,371.434 153.602,371.434C234.238,371.434 226.559,279.273 307.199,279.273C387.84,279.273 380.16,371.434 460.801,371.434C541.441,371.434 533.762,279.273 614.398,279.273C643.165,279.273 660.693,291.001 675,306.09L675,341.001C660.693,325.912 643.165,314.184 614.398,314.184C533.762,314.184 541.441,406.344 460.801,406.344C380.16,406.344 387.84,314.184 307.199,314.184C226.559,314.184 234.238,406.344 153.602,406.344C128.034,406.344 111.344,397.079 97.903,384.425Z" style="fill:rgb(153,102,51);"/>
<path d="M97.903,419.331L97.903,384.425C111.344,397.079 128.034,406.344 153.602,406.344C234.238,406.344 226.559,314.184 307.199,314.184C387.84,314.184 380.16,406.344 460.801,406.344C541.441,406.344 533.762,314.184 614.398,314.184C643.165,314.184 660.693,325.912 675,341.001L675,375.907C660.693,360.818 643.165,349.09 614.398,349.09C533.762,349.09 541.441,441.25 460.801,441.25C380.16,441.25 387.84,349.09 307.199,349.09C226.559,349.09 234.238,441.25 153.602,441.25C128.034,441.25 111.344,431.985 97.903,419.331Z" style="fill:rgb(255,153,0);"/>
<path d="M97.903,454.241L97.903,419.331C111.344,431.985 128.034,441.25 153.602,441.25C234.238,441.25 226.559,349.09 307.199,349.09C387.84,349.09 380.16,441.25 460.801,441.25C541.441,441.25 533.762,349.09 614.398,349.09C643.165,349.09 660.693,360.818 675,375.907L675,410.817C660.693,395.728 643.165,384 614.398,384C533.762,384 541.441,476.16 460.801,476.16C380.16,476.16 387.84,384 307.199,384C226.559,384 234.238,476.16 153.602,476.16C128.034,476.16 111.344,466.895 97.903,454.241Z" style="fill:rgb(255,204,0);"/>
<path d="M97.903,483.348L97.903,454.241C111.344,466.895 128.034,476.16 153.602,476.16C234.238,476.16 226.559,384 307.199,384C387.84,384 380.16,476.16 460.801,476.16C541.441,476.16 533.762,384 614.398,384C643.165,384 660.693,395.728 675,410.817L675,445.727C660.693,430.638 643.165,418.91 614.398,418.91C563.1,418.91 547.544,456.208 522.253,483.348L399.348,483.348C374.057,456.208 358.5,418.91 307.199,418.91C255.899,418.91 240.342,456.208 215.052,483.348L97.903,483.348Z" style="fill:rgb(204,153,0);"/>
<path d="M551.289,483.348C566.069,466.975 583.929,453.816 614.398,453.816C643.165,453.816 660.693,465.544 675,480.633L675,445.727C660.693,430.638 643.165,418.91 614.398,418.91C563.1,418.91 547.544,456.208 522.253,483.348L551.289,483.348Z" style="fill:rgb(255,204,51);"/>
<path d="M399.348,483.348L370.311,483.348C355.531,466.975 337.67,453.816 307.199,453.816C276.728,453.816 258.867,466.975 244.087,483.348L215.052,483.348C240.342,456.208 255.899,418.91 307.199,418.91C358.5,418.91 374.057,456.208 399.348,483.348Z" style="fill:rgb(255,204,51);"/>
<path d="M370.311,483.348L244.087,483.348C258.867,466.975 276.728,453.816 307.199,453.816C337.67,453.816 355.531,466.975 370.311,483.348Z" style="fill:rgb(153,102,51);"/>
<path d="M675,483.348L551.289,483.348C566.069,466.975 583.929,453.816 614.398,453.816C643.165,453.816 660.693,465.544 675,480.633L675,483.348Z" style="fill:rgb(153,102,51);"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -1,928 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 600 360" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<rect id="svg_62" x="0" y="0" width="600" height="360" style="fill:rgb(104,45,180);"/>
<g id="svg_1">
<g id="svg_63">
<g id="svg_64" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,60,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_65" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,60,60)">
<circle cx="30" cy="30" r="13" style="fill:rgb(65,60,74);"/>
</g>
<g id="svg_66" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,60,60)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_2">
<g id="svg_67">
<g id="svg_68" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_69" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,60)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_70" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,60)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_71" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,60)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_3">
<g id="svg_72">
<g id="svg_73" transform="matrix(1,0,0,1,0,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_74" transform="matrix(1,0,0,1,0,120)">
<path d="M30.87,4L29.13,4L29.13,26.77L17.75,7.05L16.25,7.92L27.63,27.63L7.92,16.25L7.05,17.75L26.77,29.13L4,29.13L4,30.87L26.77,30.87L7.05,42.25L7.92,43.75L27.63,32.37L16.25,52.08L17.75,52.95L29.13,33.23L29.13,56L30.87,56L30.87,33.23L42.25,52.95L43.75,52.08L32.37,32.37L52.08,43.75L52.95,42.25L33.23,30.87L56,30.87L56,29.13L33.23,29.13L52.95,17.75L52.08,16.25L32.37,27.63L43.75,7.92L42.25,7.05L30.87,26.77L30.87,4Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_4">
<g id="svg_75">
<g id="svg_76" transform="matrix(1,0,0,1,0,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_77" transform="matrix(1,0,0,1,0,180)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_78" transform="matrix(1,0,0,1,0,180)">
<circle cx="30" cy="30" r="7" style="fill:rgb(65,60,74);"/>
</g>
</g>
</g>
<g id="svg_5">
<g id="svg_79">
<g id="svg_80" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_81" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,240)">
<path d="M4,56L56,56L30,30L4,56Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_82" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,60,240)">
<path d="M56,4L4,4L30,30L56,4Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_6">
<g id="svg_83">
<g id="svg_84" transform="matrix(1,0,0,1,0,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_85" transform="matrix(1,0,0,1,0,300)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_7">
<g id="svg_86">
<g id="svg_87" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_88" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,60)">
<path d="M30,41C23.53,41 19.01,38.78 16.12,36.22C14.67,34.93 13.63,33.56 12.95,32.34C12.26,31.09 12,30.07 12,29.5L10,29.5C10,30.55 10.43,31.9 11.2,33.3C11.28,33.44 11.35,33.57 11.43,33.71L5.5,37.13L6.5,38.87L12.57,35.36C13.2,36.15 13.94,36.95 14.8,37.71C15.91,38.691 17.128,39.543 18.43,40.25L15.13,45.96L16.87,46.96L20.24,41.13C22.68,42.17 25.59,42.87 29,42.98L29,50L31,50L31,42.98C34.41,42.87 37.32,42.17 39.76,41.13L43.13,46.96L44.87,45.96L41.57,40.25C42.872,39.543 44.09,38.691 45.2,37.71C46.001,37.004 46.737,36.227 47.4,35.39L53.43,38.87L54.43,37.13L48.55,33.74C48.63,33.59 48.72,33.45 48.8,33.3C49.57,31.9 50,30.55 50,29.5L48,29.5C48,30.07 47.73,31.09 47.05,32.34C46.37,33.56 45.33,34.93 43.88,36.22C40.99,38.78 36.47,41 30,41Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_8">
<g id="svg_89">
<g id="svg_90" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_91" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,120)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_92" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,120)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_93" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,120)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_9">
<g id="svg_94">
<g id="svg_95" transform="matrix(1,0,0,1,60,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_96" transform="matrix(1,0,0,1,60,120)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_97" transform="matrix(1,0,0,1,60,120)">
<circle cx="30" cy="30" r="7" style="fill:rgb(149,137,169);"/>
</g>
</g>
</g>
<g id="svg_10">
<g id="svg_98">
<g id="svg_99" transform="matrix(1,0,0,1,60,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_100" transform="matrix(1,0,0,1,60,180)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_11">
<g id="svg_101">
<g id="svg_102" transform="matrix(1,0,0,1,60,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_103" transform="matrix(1,0,0,1,60,240)">
<circle cx="30" cy="30" r="13" style="fill:rgb(177,163,201);"/>
</g>
<g id="svg_104" transform="matrix(1,0,0,1,60,240)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_12">
<g id="svg_105">
<g id="svg_106" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,360)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_107" transform="matrix(7.04481e-16,-1,1,7.04481e-16,60,360)">
<path d="M30.87,4L29.13,4L29.13,23.41L24.11,4.66L22.43,5.11L27.46,23.87L17.75,7.05L16.25,7.92L25.96,24.73L12.23,11L11,12.23L24.73,25.96L7.92,16.25L7.05,17.75L23.87,27.46L5.11,22.43L4.66,24.11L23.42,29.13L4,29.13L4,30.87L23.42,30.87L4.66,35.89L5.11,37.57L23.87,32.54L7.05,42.25L7.92,43.75L24.73,34.04L11,47.77L12.23,49L25.96,35.27L16.25,52.08L17.75,52.95L27.46,36.13L22.43,54.89L24.11,55.34L29.13,36.58L29.13,56L30.87,56L30.87,36.58L35.89,55.34L37.57,54.89L32.54,36.14L42.25,52.95L43.75,52.08L34.04,35.27L47.77,49L49,47.77L35.27,34.04L52.08,43.75L52.95,42.25L36.13,32.54L54.89,37.57L55.34,35.89L36.58,30.87L56,30.87L56,29.13L36.58,29.13L55.34,24.11L54.89,22.43L36.13,27.46L52.95,17.75L52.08,16.25L35.27,25.96L49,12.23L47.77,11L34.04,24.73L43.75,7.92L42.25,7.05L32.54,23.87L37.57,5.11L35.89,4.66L30.87,23.42L30.87,4Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_13">
<g id="svg_108">
<g id="svg_109" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_110" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_111" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_112" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_113" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_114" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_115" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_116" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_117" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_118" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_119" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,180,60)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_14">
<g id="svg_120">
<g id="svg_121" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_122" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,120)">
<path d="M30,41C23.53,41 19.01,38.78 16.12,36.22C14.67,34.93 13.63,33.56 12.95,32.34C12.26,31.09 12,30.07 12,29.5L10,29.5C10,30.55 10.43,31.9 11.2,33.3C11.28,33.44 11.35,33.57 11.43,33.71L5.5,37.13L6.5,38.87L12.57,35.36C13.2,36.15 13.94,36.95 14.8,37.71C15.91,38.691 17.128,39.543 18.43,40.25L15.13,45.96L16.87,46.96L20.24,41.13C22.68,42.17 25.59,42.87 29,42.98L29,50L31,50L31,42.98C34.41,42.87 37.32,42.17 39.76,41.13L43.13,46.96L44.87,45.96L41.57,40.25C42.872,39.543 44.09,38.691 45.2,37.71C46.001,37.004 46.737,36.227 47.4,35.39L53.43,38.87L54.43,37.13L48.55,33.74C48.63,33.59 48.72,33.45 48.8,33.3C49.57,31.9 50,30.55 50,29.5L48,29.5C48,30.07 47.73,31.09 47.05,32.34C46.37,33.56 45.33,34.93 43.88,36.22C40.99,38.78 36.47,41 30,41Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_15">
<g id="svg_123">
<g id="svg_124" transform="matrix(1,0,0,1,120,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_125" transform="matrix(1,0,0,1,120,120)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_126" transform="matrix(1,0,0,1,120,120)">
<circle cx="30" cy="30" r="7" style="fill:rgb(121,111,138);"/>
</g>
</g>
</g>
<g id="svg_16">
<g id="svg_127">
<g id="svg_128" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,180,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_129" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,180,180)">
<path d="M4,56L56,56L30,30L4,56Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_130" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,180,180)">
<path d="M56,4L4,4L30,30L56,4Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_17">
<g id="svg_131">
<g id="svg_132" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_133" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,300)">
<path d="M30,49C38.28,49 45,42.28 45,34L15,34C15,42.28 21.72,49 30,49Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_134" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,300)">
<circle cx="30" cy="21" r="9" style="fill:rgb(65,60,74);"/>
</g>
</g>
</g>
<g id="svg_18">
<g id="svg_135">
<g id="svg_136" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,360)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_137" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,360)">
<circle cx="30" cy="30" r="13" style="fill:rgb(177,163,201);"/>
</g>
<g id="svg_138" transform="matrix(7.04481e-16,-1,1,7.04481e-16,120,360)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_19">
<g id="svg_139">
<g id="svg_140" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,1.06581e-14)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_141" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,1.06581e-14)">
<path d="M4,30L30,30L4,4L4,30Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_142" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,1.06581e-14)">
<path d="M4,56L30,56L4,30L4,56ZM30,30L56,30L30,4L30,30Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_143" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,1.06581e-14)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_144" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,1.06581e-14)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_20">
<g id="svg_145">
<g id="svg_146" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_147" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,120)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_148" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,120)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_149" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,120)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_21">
<g id="svg_150">
<g id="svg_151" transform="matrix(7.04481e-16,-1,1,7.04481e-16,180,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_152" transform="matrix(7.04481e-16,-1,1,7.04481e-16,180,180)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_153" transform="matrix(7.04481e-16,-1,1,7.04481e-16,180,180)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_154" transform="matrix(7.04481e-16,-1,1,7.04481e-16,180,180)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_22">
<g id="svg_155">
<g id="svg_156" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_157" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,240,240)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_23">
<g id="svg_158">
<g id="svg_159" transform="matrix(1,0,0,1,180,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_160" transform="matrix(1,0,0,1,180,240)">
<path d="M30.87,4L29.13,4L29.13,26.77L17.75,7.05L16.25,7.92L27.63,27.63L7.92,16.25L7.05,17.75L26.77,29.13L4,29.13L4,30.87L26.77,30.87L7.05,42.25L7.92,43.75L27.63,32.37L16.25,52.08L17.75,52.95L29.13,33.23L29.13,56L30.87,56L30.87,33.23L42.25,52.95L43.75,52.08L32.37,32.37L52.08,43.75L52.95,42.25L33.23,30.87L56,30.87L56,29.13L33.23,29.13L52.95,17.75L52.08,16.25L32.37,27.63L43.75,7.92L42.25,7.05L30.87,26.77L30.87,4Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_24">
<g id="svg_161">
<g id="svg_162" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_163" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,300)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_164" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,300)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_165" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,240,300)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_25">
<g id="svg_166">
<g id="svg_167" transform="matrix(7.04481e-16,-1,1,7.04481e-16,240,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_168" transform="matrix(7.04481e-16,-1,1,7.04481e-16,240,60)">
<path d="M30.87,4L29.13,4L29.13,23.41L24.11,4.66L22.43,5.11L27.46,23.87L17.75,7.05L16.25,7.92L25.96,24.73L12.23,11L11,12.23L24.73,25.96L7.92,16.25L7.05,17.75L23.87,27.46L5.11,22.43L4.66,24.11L23.42,29.13L4,29.13L4,30.87L23.42,30.87L4.66,35.89L5.11,37.57L23.87,32.54L7.05,42.25L7.92,43.75L24.73,34.04L11,47.77L12.23,49L25.96,35.27L16.25,52.08L17.75,52.95L27.46,36.13L22.43,54.89L24.11,55.34L29.13,36.58L29.13,56L30.87,56L30.87,36.58L35.89,55.34L37.57,54.89L32.54,36.14L42.25,52.95L43.75,52.08L34.04,35.27L47.77,49L49,47.77L35.27,34.04L52.08,43.75L52.95,42.25L36.13,32.54L54.89,37.57L55.34,35.89L36.58,30.87L56,30.87L56,29.13L36.58,29.13L55.34,24.11L54.89,22.43L36.13,27.46L52.95,17.75L52.08,16.25L35.27,25.96L49,12.23L47.77,11L34.04,24.73L43.75,7.92L42.25,7.05L32.54,23.87L37.57,5.11L35.89,4.66L30.87,23.42L30.87,4Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_26">
<g id="svg_169">
<g id="svg_170" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,300,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_171" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,300,120)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_27">
<g id="svg_172">
<g id="svg_173" transform="matrix(1,0,0,1,240,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_174" transform="matrix(1,0,0,1,240,120)">
<path d="M4,56L56,56L30,30L4,56Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_175" transform="matrix(1,0,0,1,240,120)">
<path d="M56,4L4,4L30,30L56,4Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_28">
<g id="svg_176">
<g id="svg_177" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,300,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_178" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,300,240)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_29">
<g id="svg_179">
<g id="svg_180" transform="matrix(1,0,0,1,240,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_181" transform="matrix(1,0,0,1,240,240)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_182" transform="matrix(1,0,0,1,240,240)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_183" transform="matrix(1,0,0,1,240,240)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_184" transform="matrix(1,0,0,1,240,240)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_185" transform="matrix(1,0,0,1,240,240)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_186" transform="matrix(1,0,0,1,240,240)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_187" transform="matrix(1,0,0,1,240,240)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_188" transform="matrix(1,0,0,1,240,240)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_189" transform="matrix(1,0,0,1,240,240)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_190" transform="matrix(1,0,0,1,240,240)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_30">
<g id="svg_191">
<g id="svg_192" transform="matrix(1,0,0,1,240,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_193" transform="matrix(1,0,0,1,240,300)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_31">
<g id="svg_194">
<g id="svg_195" transform="matrix(1,0,0,1,300,0)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_196" transform="matrix(1,0,0,1,300,0)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_197" transform="matrix(1,0,0,1,300,0)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_198" transform="matrix(1,0,0,1,300,0)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_199" transform="matrix(1,0,0,1,300,0)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_200" transform="matrix(1,0,0,1,300,0)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_201" transform="matrix(1,0,0,1,300,0)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_202" transform="matrix(1,0,0,1,300,0)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_203" transform="matrix(1,0,0,1,300,0)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_204" transform="matrix(1,0,0,1,300,0)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_205" transform="matrix(1,0,0,1,300,0)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_32">
<g id="svg_206">
<g id="svg_207" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,360,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_208" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,360,120)">
<circle cx="30" cy="30" r="13" style="fill:rgb(121,111,138);"/>
</g>
<g id="svg_209" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,360,120)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_33">
<g id="svg_210">
<g id="svg_211" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_212" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_213" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_214" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_215" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_216" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_217" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_218" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_219" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_220" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_221" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,120)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_34">
<g id="svg_222">
<g id="svg_223" transform="matrix(7.04481e-16,-1,1,7.04481e-16,300,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_224" transform="matrix(7.04481e-16,-1,1,7.04481e-16,300,240)">
<path d="M4,30L30,30L4,4L4,30Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_225" transform="matrix(7.04481e-16,-1,1,7.04481e-16,300,240)">
<path d="M4,56L30,56L4,30L4,56ZM30,30L56,30L30,4L30,30Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_226" transform="matrix(7.04481e-16,-1,1,7.04481e-16,300,240)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_227" transform="matrix(7.04481e-16,-1,1,7.04481e-16,300,240)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_35">
<g id="svg_228">
<g id="svg_229" transform="matrix(1,0,0,1,300,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_230" transform="matrix(1,0,0,1,300,240)">
<path d="M4,30L30,30L4,4L4,30Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_231" transform="matrix(1,0,0,1,300,240)">
<path d="M4,56L30,56L4,30L4,56ZM30,30L56,30L30,4L30,30Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_232" transform="matrix(1,0,0,1,300,240)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_233" transform="matrix(1,0,0,1,300,240)">
<path d="M30,56L56,56L30,30L30,56Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_36">
<g id="svg_234">
<g id="svg_235" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_236" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,300)">
<path d="M30,49C38.28,49 45,42.28 45,34L15,34C15,42.28 21.72,49 30,49Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_237" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,360,300)">
<circle cx="30" cy="21" r="9" style="fill:rgb(177,163,201);"/>
</g>
</g>
</g>
<g id="svg_37">
<g id="svg_238">
<g id="svg_239" transform="matrix(1,0,0,1,360,0)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_240" transform="matrix(1,0,0,1,360,0)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_38">
<g id="svg_241">
<g id="svg_242" transform="matrix(1,0,0,1,360,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_243" transform="matrix(1,0,0,1,360,60)">
<path d="M30.87,4L29.13,4L29.13,26.77L17.75,7.05L16.25,7.92L27.63,27.63L7.92,16.25L7.05,17.75L26.77,29.13L4,29.13L4,30.87L26.77,30.87L7.05,42.25L7.92,43.75L27.63,32.37L16.25,52.08L17.75,52.95L29.13,33.23L29.13,56L30.87,56L30.87,33.23L42.25,52.95L43.75,52.08L32.37,32.37L52.08,43.75L52.95,42.25L33.23,30.87L56,30.87L56,29.13L33.23,29.13L52.95,17.75L52.08,16.25L32.37,27.63L43.75,7.92L42.25,7.05L30.87,26.77L30.87,4Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_39">
<g id="svg_244">
<g id="svg_245" transform="matrix(1,0,0,1,360,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_246" transform="matrix(1,0,0,1,360,120)">
<path d="M30.87,4L29.13,4L29.13,26.77L17.75,7.05L16.25,7.92L27.63,27.63L7.92,16.25L7.05,17.75L26.77,29.13L4,29.13L4,30.87L26.77,30.87L7.05,42.25L7.92,43.75L27.63,32.37L16.25,52.08L17.75,52.95L29.13,33.23L29.13,56L30.87,56L30.87,33.23L42.25,52.95L43.75,52.08L32.37,32.37L52.08,43.75L52.95,42.25L33.23,30.87L56,30.87L56,29.13L33.23,29.13L52.95,17.75L52.08,16.25L32.37,27.63L43.75,7.92L42.25,7.05L30.87,26.77L30.87,4Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_40">
<g id="svg_247">
<g id="svg_248" transform="matrix(1,0,0,1,360,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_249" transform="matrix(1,0,0,1,360,180)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_250" transform="matrix(1,0,0,1,360,180)">
<circle cx="30" cy="30" r="7" style="fill:rgb(93,86,106);"/>
</g>
</g>
</g>
<g id="svg_41">
<g id="svg_251">
<g id="svg_252" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,420,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_253" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,420,300)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_42">
<g id="svg_254">
<g id="svg_255" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,420,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_256" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,420,300)">
<path d="M30.87,4L29.13,4L29.13,23.41L24.11,4.66L22.43,5.11L27.46,23.87L17.75,7.05L16.25,7.92L25.96,24.73L12.23,11L11,12.23L24.73,25.96L7.92,16.25L7.05,17.75L23.87,27.46L5.11,22.43L4.66,24.11L23.42,29.13L4,29.13L4,30.87L23.42,30.87L4.66,35.89L5.11,37.57L23.87,32.54L7.05,42.25L7.92,43.75L24.73,34.04L11,47.77L12.23,49L25.96,35.27L16.25,52.08L17.75,52.95L27.46,36.13L22.43,54.89L24.11,55.34L29.13,36.58L29.13,56L30.87,56L30.87,36.58L35.89,55.34L37.57,54.89L32.54,36.14L42.25,52.95L43.75,52.08L34.04,35.27L47.77,49L49,47.77L35.27,34.04L52.08,43.75L52.95,42.25L36.13,32.54L54.89,37.57L55.34,35.89L36.58,30.87L56,30.87L56,29.13L36.58,29.13L55.34,24.11L54.89,22.43L36.13,27.46L52.95,17.75L52.08,16.25L35.27,25.96L49,12.23L47.77,11L34.04,24.73L43.75,7.92L42.25,7.05L32.54,23.87L37.57,5.11L35.89,4.66L30.87,23.42L30.87,4Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_43">
<g id="svg_257">
<g id="svg_258" transform="matrix(7.04481e-16,-1,1,7.04481e-16,420,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_259" transform="matrix(7.04481e-16,-1,1,7.04481e-16,420,60)">
<circle cx="30" cy="30" r="13" style="fill:rgb(149,137,169);"/>
</g>
<g id="svg_260" transform="matrix(7.04481e-16,-1,1,7.04481e-16,420,60)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_44">
<g id="svg_261">
<g id="svg_262" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,480,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_263" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,480,120)">
<path d="M40,36C40,41.52 35.52,46 30,46C24.48,46 20,41.52 20,36C20,30.48 29,14 30,14C31,14 40,30.48 40,36Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_45">
<g id="svg_264">
<g id="svg_265" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_266" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,120)">
<path d="M30,49C38.28,49 45,42.28 45,34L15,34C15,42.28 21.72,49 30,49Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_267" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,120)">
<circle cx="30" cy="21" r="9" style="fill:rgb(65,60,74);"/>
</g>
</g>
</g>
<g id="svg_46">
<g id="svg_268">
<g id="svg_269" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_270" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,180)">
<path d="M4,56L56,56L30,30L4,56Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_271" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,480,180)">
<path d="M56,4L4,4L30,30L56,4Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_47">
<g id="svg_272">
<g id="svg_273" transform="matrix(1,0,0,1,420,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_274" transform="matrix(1,0,0,1,420,240)">
<circle cx="30" cy="30" r="13" style="fill:rgb(177,163,201);"/>
</g>
<g id="svg_275" transform="matrix(1,0,0,1,420,240)">
<path d="M20,10L22,10L22,50L20,50L20,10ZM29,10L31,10L31,50L29,50L29,10ZM38,10L40,10L40,50L38,50L38,10Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_48">
<g id="svg_276">
<g id="svg_277" transform="matrix(1,0,0,1,420,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_278" transform="matrix(1,0,0,1,420,300)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_279" transform="matrix(1,0,0,1,420,300)">
<circle cx="30" cy="30" r="7" style="fill:rgb(65,60,74);"/>
</g>
</g>
</g>
<g id="svg_49">
<g id="svg_280">
<g id="svg_281" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_282" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_283" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_284" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_285" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_286" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_287" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_288" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_289" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_290" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_291" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,540,60)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_50">
<g id="svg_292">
<g id="svg_293" transform="matrix(1,0,0,1,480,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_294" transform="matrix(1,0,0,1,480,60)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_295" transform="matrix(1,0,0,1,480,60)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_296" transform="matrix(1,0,0,1,480,60)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_51">
<g id="svg_297">
<g id="svg_298" transform="matrix(1,0,0,1,480,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_299" transform="matrix(1,0,0,1,480,120)">
<path d="M30,41C23.53,41 19.01,38.78 16.12,36.22C14.67,34.93 13.63,33.56 12.95,32.34C12.26,31.09 12,30.07 12,29.5L10,29.5C10,30.55 10.43,31.9 11.2,33.3C11.28,33.44 11.35,33.57 11.43,33.71L5.5,37.13L6.5,38.87L12.57,35.36C13.2,36.15 13.94,36.95 14.8,37.71C15.91,38.691 17.128,39.543 18.43,40.25L15.13,45.96L16.87,46.96L20.24,41.13C22.68,42.17 25.59,42.87 29,42.98L29,50L31,50L31,42.98C34.41,42.87 37.32,42.17 39.76,41.13L43.13,46.96L44.87,45.96L41.57,40.25C42.872,39.543 44.09,38.691 45.2,37.71C46.001,37.004 46.737,36.227 47.4,35.39L53.43,38.87L54.43,37.13L48.55,33.74C48.63,33.59 48.72,33.45 48.8,33.3C49.57,31.9 50,30.55 50,29.5L48,29.5C48,30.07 47.73,31.09 47.05,32.34C46.37,33.56 45.33,34.93 43.88,36.22C40.99,38.78 36.47,41 30,41Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_52">
<g id="svg_300">
<g id="svg_301" transform="matrix(1,0,0,1,480,180)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_302" transform="matrix(1,0,0,1,480,180)">
<path d="M49,29.5C49,32.74 43.44,42 30,42C16.56,42 11,32.74 11,29.5C11,26.26 16.56,17 30,17C43.44,17 49,26.26 49,29.5Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_303" transform="matrix(1,0,0,1,480,180)">
<circle cx="30" cy="30" r="7" style="fill:rgb(65,60,74);"/>
</g>
</g>
</g>
<g id="svg_53">
<g id="svg_304">
<g id="svg_305" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
<g id="svg_306" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_307" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_308" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_309" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_310" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_311" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_312" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_313" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_314" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_315" transform="matrix(7.04481e-16,-1,1,7.04481e-16,480,300)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_54">
<g id="svg_316">
<g id="svg_317" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,540,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_318" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,540,300)">
<path d="M4,56L56,56L30,30L4,56Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_319" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,540,300)">
<path d="M56,4L4,4L30,30L56,4Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_55">
<g id="svg_320">
<g id="svg_321" transform="matrix(1,0,0,1,540,0)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_322" transform="matrix(1,0,0,1,540,0)">
<path d="M30.87,4L29.13,4L29.13,26.77L17.75,7.05L16.25,7.92L27.63,27.63L7.92,16.25L7.05,17.75L26.77,29.13L4,29.13L4,30.87L26.77,30.87L7.05,42.25L7.92,43.75L27.63,32.37L16.25,52.08L17.75,52.95L29.13,33.23L29.13,56L30.87,56L30.87,33.23L42.25,52.95L43.75,52.08L32.37,32.37L52.08,43.75L52.95,42.25L33.23,30.87L56,30.87L56,29.13L33.23,29.13L52.95,17.75L52.08,16.25L32.37,27.63L43.75,7.92L42.25,7.05L30.87,26.77L30.87,4Z" style="fill:rgb(177,163,201);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_56">
<g id="svg_323">
<g id="svg_324" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,600,60)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_325" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,600,60)">
<path d="M30,49C38.28,49 45,42.28 45,34L15,34C15,42.28 21.72,49 30,49Z" style="fill:rgb(65,60,74);fill-rule:nonzero;"/>
</g>
<g id="svg_326" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,600,60)">
<circle cx="30" cy="21" r="9" style="fill:rgb(177,163,201);"/>
</g>
</g>
</g>
<g id="svg_57">
<g id="svg_327">
<g id="svg_328" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,600,120)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_329" transform="matrix(-3.82857e-16,1,-1,-3.82857e-16,600,120)">
<path d="M30,41C23.53,41 19.01,38.78 16.12,36.22C14.67,34.93 13.63,33.56 12.95,32.34C12.26,31.09 12,30.07 12,29.5L10,29.5C10,30.55 10.43,31.9 11.2,33.3C11.28,33.44 11.35,33.57 11.43,33.71L5.5,37.13L6.5,38.87L12.57,35.36C13.2,36.15 13.94,36.95 14.8,37.71C15.91,38.691 17.128,39.543 18.43,40.25L15.13,45.96L16.87,46.96L20.24,41.13C22.68,42.17 25.59,42.87 29,42.98L29,50L31,50L31,42.98C34.41,42.87 37.32,42.17 39.76,41.13L43.13,46.96L44.87,45.96L41.57,40.25C42.872,39.543 44.09,38.691 45.2,37.71C46.001,37.004 46.737,36.227 47.4,35.39L53.43,38.87L54.43,37.13L48.55,33.74C48.63,33.59 48.72,33.45 48.8,33.3C49.57,31.9 50,30.55 50,29.5L48,29.5C48,30.07 47.73,31.09 47.05,32.34C46.37,33.56 45.33,34.93 43.88,36.22C40.99,38.78 36.47,41 30,41Z" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_58">
<g id="svg_330">
<g id="svg_331" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_332" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M15,0L0,15L30,15L15,0Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_333" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M45,0L30,15L60,15L45,0Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_334" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M15,30L0,45L30,45L15,30Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_335" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M45,30L30,45L60,45L45,30Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_336" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M30,15L15,30L45,30L30,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_337" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M30,45L15,60L45,60L30,45Z" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_338" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M60,45L45,60L60,60L60,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_339" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M60,15L45,30L60,30L60,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
<g id="svg_340" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M0,45L15,60L0,60L0,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_341" transform="matrix(-1,-7.65714e-16,7.65714e-16,-1,600,240)">
<path d="M0,15L15,30L0,30L0,15Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_59">
<g id="svg_342">
<g id="svg_343" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,300)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(149,137,169);fill-rule:nonzero;"/>
</g>
<g id="svg_344" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,300)">
<rect x="0" y="0" width="60" height="30" style="fill:rgb(37,34,42);fill-rule:nonzero;"/>
</g>
<g id="svg_345" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,300)">
<path d="M30,45C38.28,45 45,38.28 45,30L15,30C15,38.28 21.72,45 30,45Z" style="fill:rgb(205,189,233);fill-rule:nonzero;"/>
</g>
<g id="svg_346" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,300)">
<path d="M30,15C21.72,15 15,21.72 15,30L45,30C45,21.72 38.28,15 30,15Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="svg_60">
<g id="svg_347">
<g id="svg_348" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,360)">
<rect x="0" y="0" width="60" height="60" style="fill:rgb(93,86,106);fill-rule:nonzero;"/>
</g>
<g id="svg_349" transform="matrix(7.04481e-16,-1,1,7.04481e-16,540,360)">
<path d="M30,41C23.53,41 19.01,38.78 16.12,36.22C14.67,34.93 13.63,33.56 12.95,32.34C12.26,31.09 12,30.07 12,29.5L10,29.5C10,30.55 10.43,31.9 11.2,33.3C11.28,33.44 11.35,33.57 11.43,33.71L5.5,37.13L6.5,38.87L12.57,35.36C13.2,36.15 13.94,36.95 14.8,37.71C15.91,38.691 17.128,39.543 18.43,40.25L15.13,45.96L16.87,46.96L20.24,41.13C22.68,42.17 25.59,42.87 29,42.98L29,50L31,50L31,42.98C34.41,42.87 37.32,42.17 39.76,41.13L43.13,46.96L44.87,45.96L41.57,40.25C42.872,39.543 44.09,38.691 45.2,37.71C46.001,37.004 46.737,36.227 47.4,35.39L53.43,38.87L54.43,37.13L48.55,33.74C48.63,33.59 48.72,33.45 48.8,33.3C49.57,31.9 50,30.55 50,29.5L48,29.5C48,30.07 47.73,31.09 47.05,32.34C46.37,33.56 45.33,34.93 43.88,36.22C40.99,38.78 36.47,41 30,41Z" style="fill:rgb(121,111,138);fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 51 KiB

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 777 398" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-38.7834,-46.8512)">
<g id="svg_8" transform="matrix(0.862975,0,0,0.77732,38.7834,46.8512)">
<g>
<rect x="0" y="0" width="900" height="512" style="fill:rgb(32,56,26);"/>
<g transform="matrix(0.455126,-0.890427,0.890427,0.455126,-327.202,446.579)">
<path d="M517.72,-82.205L517.72,138.035C517.72,147.856 509.274,155.83 498.872,155.83L18.848,155.83C8.446,155.83 0,147.856 0,138.035L0,-82.205C0,-92.026 8.446,-100 18.848,-100L498.872,-100C509.274,-100 517.72,-92.026 517.72,-82.205Z" style="fill:rgb(165,140,51);"/>
<path d="M1046.84,17.795L1046.84,237.505C1046.84,247.326 1038.39,255.3 1027.99,255.3L547.968,255.3C537.566,255.3 529.12,247.326 529.12,237.505L529.12,17.795C529.12,7.974 537.566,0 547.968,0L1027.99,0C1038.39,0 1046.84,7.974 1046.84,17.795Z" style="fill:rgb(144,165,51);"/>
<path d="M517.72,185.025L517.72,371.495C517.72,381.316 509.274,389.29 498.872,389.29L18.848,389.29C8.446,389.29 0,381.316 0,371.495L0,185.025C0,175.204 8.446,167.23 18.848,167.23L498.872,167.23C509.274,167.23 517.72,175.204 517.72,185.025Z" style="fill:rgb(121,165,51);"/>
<path d="M1046.84,284.495L1046.84,507.415C1046.84,517.236 1038.39,525.21 1027.99,525.21L547.968,525.21C537.566,525.21 529.12,517.236 529.12,507.415L529.12,284.495C529.12,274.674 537.566,266.7 547.968,266.7L1027.99,266.7C1038.39,266.7 1046.84,274.674 1046.84,284.495Z" style="fill:rgb(121,165,51);"/>
<path d="M517.72,418.485L517.72,559.425C517.72,569.246 509.274,577.22 498.872,577.22L18.848,577.22C8.446,577.22 0,569.246 0,559.425L0,418.485C0,408.664 8.446,400.69 18.848,400.69L498.872,400.69C509.274,400.69 517.72,408.664 517.72,418.485Z" style="fill:rgb(144,165,51);"/>
<path d="M1046.84,554.405L1046.84,667.895C1046.84,677.716 1038.39,685.69 1027.99,685.69L547.968,685.69C537.566,685.69 529.12,677.716 529.12,667.895L529.12,554.405C529.12,544.584 537.566,536.61 547.968,536.61L1027.99,536.61C1038.39,536.61 1046.84,544.584 1046.84,554.405Z" style="fill:rgb(165,140,51);"/>
<path d="M517.72,606.415L517.72,777.845C517.72,787.666 509.274,795.64 498.872,795.64L18.848,795.64C8.446,795.64 0,787.666 0,777.845L0,606.415C0,596.594 8.446,588.62 18.848,588.62L498.872,588.62C509.274,588.62 517.72,596.594 517.72,606.415Z" style="fill:rgb(165,140,51);"/>
<path d="M1046.84,714.895L1046.84,836.995C1046.84,846.816 1038.39,854.79 1027.99,854.79L547.968,854.79C537.566,854.79 529.12,846.816 529.12,836.995L529.12,714.895C529.12,705.074 537.566,697.1 547.968,697.1L1027.99,697.1C1038.39,697.1 1046.84,705.074 1046.84,714.895Z" style="fill:rgb(99,165,51);"/>
<path d="M517.72,824.835L517.72,994.715C517.72,1004.54 509.274,1012.51 498.872,1012.51L18.848,1012.51C8.446,1012.51 0,1004.54 0,994.715L0,824.835C0,815.014 8.446,807.04 18.848,807.04L498.872,807.04C509.274,807.04 517.72,815.014 517.72,824.835Z" style="fill:rgb(99,165,51);"/>
<path d="M1046.84,883.975L1046.84,1039.59C1046.84,1049.41 1038.39,1057.38 1027.99,1057.38L547.968,1057.38C537.566,1057.38 529.12,1049.41 529.12,1039.59L529.12,883.975C529.12,874.154 537.566,866.18 547.968,866.18L1027.99,866.18C1038.39,866.18 1046.84,874.154 1046.84,883.975Z" style="fill:rgb(165,140,51);"/>
<path d="M517.72,1041.7L517.72,1145.52C517.72,1155.34 509.274,1163.31 498.872,1163.31L18.848,1163.31C8.446,1163.31 0,1155.34 0,1145.52L0,1041.7C0,1031.88 8.446,1023.91 18.848,1023.91L498.872,1023.91C509.274,1023.91 517.72,1031.88 517.72,1041.7Z" style="fill:rgb(165,163,51);"/>
<path d="M1046.84,1086.58L1046.84,1292.82C1046.84,1302.64 1038.39,1310.61 1027.99,1310.61L547.968,1310.61C537.566,1310.61 529.12,1302.64 529.12,1292.82L529.12,1086.58C529.12,1076.75 537.566,1068.78 547.968,1068.78L1027.99,1068.78C1038.39,1068.78 1046.84,1076.75 1046.84,1086.58Z" style="fill:rgb(144,165,51);"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,349 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 675 372" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-64.8114,-78.863)">
<g>
<g transform="matrix(-0.990165,1.22465e-16,1.2126e-16,1,803.985,0)">
<rect x="64.811" y="78.863" width="681.705" height="371.841" style="fill:rgb(133,14,0);"/>
</g>
<g transform="matrix(-1,1.22465e-16,1.22465e-16,1,811.327,0)">
<path d="M149.167,450.439L149.165,450.439L164.434,429.75L149.167,450.439Z" style="fill:rgb(42,0,0);"/>
<path d="M524.112,142.497L526.023,96L524.117,142.5L524.112,142.497Z" style="fill:rgb(42,0,0);"/>
<path d="M141.531,202.5L141.528,202.496L153.934,156.75L141.531,202.5Z" style="fill:rgb(42,0,0);"/>
<path d="M124.281,291.75L124.28,291.747L174.184,231.75L124.281,291.75Z" style="fill:rgb(42,0,0);"/>
<path d="M346.93,342.75L342.777,386.249L342.774,386.243L346.93,342.75Z" style="fill:rgb(42,0,0);"/>
<path d="M310.121,318.75L310.119,318.744L316.685,299.659L310.121,318.75Z" style="fill:rgb(42,0,0);"/>
<path d="M516.617,331.5L516.613,331.493L522.273,298.5L516.617,331.5Z" style="fill:rgb(42,0,0);"/>
<path d="M542.521,197.994L549.676,156L542.523,198L542.521,197.994Z" style="fill:rgb(42,0,0);"/>
<path d="M328.526,193.497L370.93,152.25L328.527,193.5L328.526,193.497Z" style="fill:rgb(42,0,0);"/>
<path d="M348.43,251.25L323.277,280.5L323.276,280.497L348.43,251.25Z" style="fill:rgb(42,0,0);"/>
<path d="M561.676,240L522.273,298.5L522.273,298.496L561.676,240Z" style="fill:rgb(42,0,0);"/>
<path d="M518.864,224.997L542.523,198L518.867,225L518.864,224.997Z" style="fill:rgb(42,0,0);"/>
<path d="M300.369,227.247L313.745,211.217L300.371,227.25L300.369,227.247Z" style="fill:rgb(42,0,0);"/>
<path d="M537.668,78.863L537.67,78.863L526.023,96L526.022,95.997L537.668,78.863Z" style="fill:rgb(42,0,0);"/>
<path d="M339.142,78.863L339.145,78.863L335.277,102L335.274,101.994L339.142,78.863Z" style="fill:rgb(42,0,0);"/>
<path d="M116.375,165L127.277,111L127.278,110.998L127.281,111L116.375,165Z" style="fill:rgb(42,0,0);"/>
<path d="M99.125,231L141.527,202.5L141.531,202.5L99.125,231Z" style="fill:rgb(42,0,0);"/>
<path d="M93.875,335.25L124.277,291.75L124.281,291.75L93.875,335.25Z" style="fill:rgb(42,0,0);"/>
<path d="M120.125,406.5L135.526,363.003L135.531,363L120.125,406.5Z" style="fill:rgb(42,0,0);"/>
<path d="M171.184,336.75L135.531,363L135.529,362.999L171.184,336.75Z" style="fill:rgb(42,0,0);"/>
<path d="M548.926,323.25L520.023,393L520.023,392.994L548.926,323.25Z" style="fill:rgb(42,0,0);"/>
<path d="M345.737,450.439L345.734,450.439L356.68,413.25L345.737,450.439Z" style="fill:rgb(42,0,0);"/>
<path d="M531.302,450.439L531.3,450.439L565.426,420L531.302,450.439Z" style="fill:rgb(42,0,0);"/>
<path d="M127.28,110.996L152.135,78.863L127.281,111L127.28,110.996Z" style="fill:rgb(42,0,0);"/>
<path d="M305.621,435L305.619,434.997L324.622,410.068L305.621,435Z" style="fill:rgb(42,0,0);"/>
<path d="M524.867,409.5L524.86,409.492L520.023,393L524.867,409.5Z" style="fill:rgb(42,0,0);"/>
<path d="M71.516,78.863L72.547,78.863L90.469,90L71.516,91.741L71.516,78.863Z" style="fill:rgb(186,5,9);"/>
<path d="M72.547,78.863L94.955,78.863L90.469,90L72.547,78.863Z" style="fill:rgb(193,8,14);"/>
<path d="M127.281,111L127.28,110.996L127.278,110.998L127.281,111Z" style="fill:rgb(179,10,18);"/>
<path d="M90.469,90L127.276,110.997L127.277,111L90.469,90Z" style="fill:rgb(179,10,18);"/>
<path d="M94.955,78.863L115.669,78.863L127.276,110.997L90.469,90L94.955,78.863Z" style="fill:rgb(179,10,18);"/>
<path d="M127.276,110.997L127.278,110.998L127.277,111L127.276,110.997Z" style="fill:rgb(177,13,23);"/>
<path d="M115.67,78.863L152.135,78.863L127.28,110.996L115.67,78.863Z" style="fill:rgb(177,13,23);"/>
<path d="M127.28,110.996L115.67,78.863L115.669,78.863L127.276,110.997L127.278,110.998L127.28,110.996Z" style="fill:rgb(177,13,23);"/>
<path d="M152.135,78.863L163.391,78.863L172.34,98.25L127.281,111L152.135,78.863Z" style="fill:rgb(175,15,27);"/>
<path d="M163.391,78.863L191.921,78.863L172.34,98.25L163.391,78.863Z" style="fill:rgb(172,18,32);"/>
<path d="M227.152,89.25L222.567,78.863L191.921,78.863L172.34,98.25L227.152,89.25Z" style="fill:rgb(157,19,33);"/>
<path d="M222.567,78.863L243.375,78.863L227.152,89.25L222.567,78.863Z" style="fill:rgb(141,19,33);"/>
<path d="M243.375,78.863L271.124,78.863L277.465,96L227.152,89.25L243.375,78.863Z" style="fill:rgb(150,23,40);"/>
<path d="M271.124,78.863L293.724,78.863L277.465,96L271.124,78.863Z" style="fill:rgb(151,26,45);"/>
<path d="M312.369,146.247L324.023,123.737L312.371,146.25L312.369,146.247Z" style="fill:rgb(130,24,42);"/>
<path d="M293.724,78.863L322.244,78.863L335.273,102L277.465,96L293.724,78.863Z" style="fill:rgb(130,24,42);"/>
<path d="M335.277,102L335.274,101.994L335.273,102L335.277,102Z" style="fill:rgb(130,24,42);"/>
<path d="M335.274,101.994L322.245,78.863L322.244,78.863L335.273,102L335.274,101.994Z" style="fill:rgb(124,25,44);"/>
<path d="M322.245,78.863L339.142,78.863L335.274,101.994L322.245,78.863Z" style="fill:rgb(124,25,44);"/>
<path d="M389.336,96L374.107,78.863L339.145,78.863L335.277,102L389.336,96Z" style="fill:rgb(128,28,49);"/>
<path d="M374.107,78.863L405.848,78.863L389.336,96L374.107,78.863Z" style="fill:rgb(128,30,53);"/>
<path d="M419.398,100.5L418.673,78.863L405.848,78.863L389.336,96L419.398,100.5Z" style="fill:rgb(112,29,50);"/>
<path d="M418.673,78.863L446.329,78.863L419.398,100.5L418.673,78.863Z" style="fill:rgb(107,29,51);"/>
<path d="M446.329,78.863L458.585,78.863L471.961,115.5L419.398,100.5L446.329,78.863Z" style="fill:rgb(103,30,52);"/>
<path d="M458.585,78.863L494.778,78.863L471.961,115.5L458.585,78.863Z" style="fill:rgb(99,31,54);"/>
<path d="M494.778,78.863L522.608,78.863L526.02,96L526.022,95.997L526.023,96L471.961,115.5L494.778,78.863Z" style="fill:rgb(100,33,58);"/>
<path d="M526.022,95.997L522.61,78.863L522.608,78.863L526.02,96L526.022,95.997Z" style="fill:rgb(83,29,50);"/>
<path d="M522.61,78.863L537.668,78.863L526.022,95.997L522.61,78.863Z" style="fill:rgb(83,29,50);"/>
<path d="M578.582,100.5L571.308,78.863L537.67,78.863L526.023,96L578.582,100.5Z" style="fill:rgb(99,37,64);"/>
<path d="M571.308,78.863L592.162,78.863L578.582,100.5L571.308,78.863Z" style="fill:rgb(90,36,62);"/>
<path d="M648.395,110.25L626.283,78.863L592.162,78.863L578.582,100.5L648.395,110.25Z" style="fill:rgb(84,35,61);"/>
<path d="M626.283,78.863L660.593,78.863L648.395,110.25L626.283,78.863Z" style="fill:rgb(73,32,55);"/>
<path d="M693.457,119.25L671.797,78.863L660.593,78.863L648.395,110.25L693.457,119.25Z" style="fill:rgb(70,32,56);"/>
<path d="M671.797,78.863L707.957,78.863L693.457,119.25L671.797,78.863Z" style="fill:rgb(67,32,56);"/>
<path d="M742.266,120L712.905,78.863L707.957,78.863L693.457,119.25L742.266,120Z" style="fill:rgb(66,33,58);"/>
<path d="M712.905,78.863L746.516,78.863L746.516,114.368L742.266,120L712.905,78.863Z" style="fill:rgb(54,28,49);"/>
<path d="M746.516,114.368L746.516,116.73L742.266,120L746.516,114.368Z" style="fill:rgb(58,31,55);"/>
<path d="M71.516,139.474L71.516,91.741L90.469,90L71.516,139.474Z" style="fill:rgb(192,8,14);"/>
<path d="M71.516,139.474L90.469,90L116.375,165L71.516,163.755L71.516,139.474Z" style="fill:rgb(185,10,18);"/>
<path d="M116.375,165L90.469,90L127.277,111L116.375,165Z" style="fill:rgb(175,12,22);"/>
<path d="M153.934,156.75L127.281,111L116.375,165L153.934,156.75Z" style="fill:rgb(165,14,25);"/>
<path d="M127.281,111L172.34,98.25L153.934,156.75L127.281,111Z" style="fill:rgb(170,18,31);"/>
<path d="M153.934,156.75L172.34,98.25L195.246,143.25L153.934,156.75Z" style="fill:rgb(166,20,35);"/>
<path d="M172.34,98.25L227.152,89.25L195.246,143.25L172.34,98.25Z" style="fill:rgb(142,19,33);"/>
<path d="M272.559,157.5L227.152,89.25L195.246,143.25L272.559,157.5Z" style="fill:rgb(146,22,39);"/>
<path d="M227.152,89.25L277.465,96L272.559,157.5L227.152,89.25Z" style="fill:rgb(131,22,39);"/>
<path d="M272.559,157.5L277.465,96L312.367,146.25L312.369,146.247L312.371,146.25L272.559,157.5Z" style="fill:rgb(147,27,47);"/>
<path d="M312.369,146.247L277.465,96L312.367,146.25L312.369,146.247Z" style="fill:rgb(139,28,49);"/>
<path d="M277.465,96L335.273,102L324.023,123.737L312.369,146.247L277.465,96Z" style="fill:rgb(139,28,49);"/>
<path d="M370.93,152.25L335.275,102.003L324.023,123.737L312.371,146.25L370.93,152.25Z" style="fill:rgb(135,30,52);"/>
<path d="M335.273,102L324.023,123.737L335.275,102.003L335.273,102Z" style="fill:rgb(135,30,52);"/>
<path d="M335.275,102.003L335.277,102L335.273,102L335.275,102.003Z" style="fill:rgb(134,32,55);"/>
<path d="M335.277,102L389.336,96L370.93,152.25L335.275,102.003L335.277,102Z" style="fill:rgb(134,32,55);"/>
<path d="M418.992,157.5L389.336,96L370.93,152.25L418.992,157.5Z" style="fill:rgb(107,27,48);"/>
<path d="M389.336,96L419.398,100.5L418.992,157.5L389.336,96Z" style="fill:rgb(124,34,59);"/>
<path d="M454.305,144.75L419.398,100.5L418.992,157.5L454.305,144.75Z" style="fill:rgb(97,28,49);"/>
<path d="M419.398,100.5L471.961,115.5L454.305,144.75L419.398,100.5Z" style="fill:rgb(97,30,53);"/>
<path d="M454.305,144.75L471.961,115.5L524.112,142.5L454.305,144.75Z" style="fill:rgb(91,30,53);"/>
<path d="M524.117,142.5L524.112,142.497L524.112,142.5L524.117,142.5Z" style="fill:rgb(91,30,53);"/>
<path d="M524.112,142.497L471.961,115.5L524.112,142.5L524.112,142.497Z" style="fill:rgb(89,31,54);"/>
<path d="M471.961,115.5L526.023,96L524.112,142.497L471.961,115.5Z" style="fill:rgb(89,31,54);"/>
<path d="M549.676,156L526.023,96L524.117,142.5L549.676,156Z" style="fill:rgb(87,33,56);"/>
<path d="M526.023,96L578.582,100.5L549.676,156L526.023,96Z" style="fill:rgb(78,31,54);"/>
<path d="M605.988,135L578.582,100.5L549.676,156L605.988,135Z" style="fill:rgb(87,36,63);"/>
<path d="M578.582,100.5L648.395,110.25L605.988,135L578.582,100.5Z" style="fill:rgb(78,34,59);"/>
<path d="M674.301,144.75L648.395,110.25L605.988,135L674.301,144.75Z" style="fill:rgb(80,37,64);"/>
<path d="M648.395,110.25L693.457,119.25L674.301,144.75L648.395,110.25Z" style="fill:rgb(67,32,56);"/>
<path d="M706.613,162.75L693.457,119.25L674.301,144.75L706.613,162.75Z" style="fill:rgb(73,36,63);"/>
<path d="M693.457,119.25L742.266,120L706.613,162.75L693.457,119.25Z" style="fill:rgb(69,35,63);"/>
<path d="M746.516,126L746.516,160.874L706.613,162.75L742.266,120L746.516,126Z" style="fill:rgb(62,33,59);"/>
<path d="M746.516,116.73L746.516,126L742.266,120L746.516,116.73Z" style="fill:rgb(48,26,47);"/>
<path d="M71.516,197.334L71.516,171.673L92.719,190.5L71.516,197.334Z" style="fill:rgb(185,10,18);"/>
<path d="M71.516,171.673L71.516,163.755L116.375,165L92.719,190.5L71.516,171.673Z" style="fill:rgb(180,13,23);"/>
<path d="M141.527,202.5L141.528,202.496L141.531,202.5L141.527,202.5Z" style="fill:rgb(158,14,24);"/>
<path d="M92.719,190.5L116.375,165L141.527,202.5L92.719,190.5Z" style="fill:rgb(158,14,24);"/>
<path d="M116.375,165L141.527,202.5L141.528,202.496L116.375,165Z" style="fill:rgb(166,18,31);"/>
<path d="M141.528,202.496L116.375,165L153.934,156.75L141.528,202.496Z" style="fill:rgb(166,18,31);"/>
<path d="M194.09,197.25L153.934,156.75L141.531,202.5L194.09,197.25Z" style="fill:rgb(151,18,32);"/>
<path d="M153.934,156.75L195.246,143.25L194.09,197.25L153.934,156.75Z" style="fill:rgb(158,22,37);"/>
<path d="M194.09,197.25L195.246,143.25L241.402,211.5L194.09,197.25Z" style="fill:rgb(160,25,43);"/>
<path d="M195.246,143.25L272.559,157.5L241.402,211.5L195.246,143.25Z" style="fill:rgb(135,23,40);"/>
<path d="M274.465,183.75L272.559,157.5L241.402,211.5L274.465,183.75Z" style="fill:rgb(135,25,43);"/>
<path d="M272.559,157.5L312.371,146.25L274.465,183.75L272.559,157.5Z" style="fill:rgb(132,27,47);"/>
<path d="M274.465,183.75L312.371,146.25L328.523,193.5L274.465,183.75Z" style="fill:rgb(135,30,52);"/>
<path d="M328.527,193.5L328.526,193.497L328.523,193.5L328.527,193.5Z" style="fill:rgb(135,30,52);"/>
<path d="M312.371,146.25L370.93,152.25L328.526,193.497L312.371,146.25Z" style="fill:rgb(120,28,50);"/>
<path d="M328.526,193.497L312.371,146.25L328.523,193.5L328.526,193.497Z" style="fill:rgb(120,28,50);"/>
<path d="M392.336,202.5L370.93,152.25L328.527,193.5L392.336,202.5Z" style="fill:rgb(117,30,52);"/>
<path d="M370.93,152.25L418.992,157.5L392.336,202.5L370.93,152.25Z" style="fill:rgb(124,34,59);"/>
<path d="M423.148,180.75L418.992,157.5L392.336,202.5L423.148,180.75Z" style="fill:rgb(100,29,51);"/>
<path d="M418.992,157.5L454.305,144.75L423.148,180.75L418.992,157.5Z" style="fill:rgb(111,35,61);"/>
<path d="M498.961,203.25L454.305,144.75L423.148,180.75L498.961,203.25Z" style="fill:rgb(107,35,62);"/>
<path d="M454.305,144.75L524.112,142.5L524.117,142.5L498.961,203.25L454.305,144.75Z" style="fill:rgb(102,36,62);"/>
<path d="M498.961,203.25L524.117,142.5L542.52,198L498.961,203.25Z" style="fill:rgb(81,30,53);"/>
<path d="M542.523,198L542.521,197.994L542.52,198L542.523,198Z" style="fill:rgb(81,30,53);"/>
<path d="M524.117,142.5L549.676,156L542.521,197.994L524.117,142.5Z" style="fill:rgb(94,37,64);"/>
<path d="M542.521,197.994L524.117,142.5L542.52,198L542.521,197.994Z" style="fill:rgb(94,37,64);"/>
<path d="M578.582,201.75L549.676,156L542.523,198L578.582,201.75Z" style="fill:rgb(70,29,51);"/>
<path d="M549.676,156L605.988,135L578.582,201.75L549.676,156Z" style="fill:rgb(83,36,63);"/>
<path d="M641.645,210L605.988,135L578.582,201.75L641.645,210Z" style="fill:rgb(75,34,59);"/>
<path d="M605.988,135L674.301,144.75L641.645,210L605.988,135Z" style="fill:rgb(65,31,54);"/>
<path d="M687.457,180L674.301,144.75L641.645,210L687.457,180Z" style="fill:rgb(60,29,52);"/>
<path d="M687.457,180L706.613,162.75L674.301,144.75L687.457,180Z" style="fill:rgb(49,25,45);"/>
<path d="M746.516,208.113L746.516,208.763L687.457,180L706.613,162.75L746.516,208.113Z" style="fill:rgb(64,34,62);"/>
<path d="M746.516,160.874L746.516,208.113L706.613,162.75L746.516,160.874Z" style="fill:rgb(48,26,47);"/>
<path d="M71.516,219.918L71.516,197.334L92.719,190.5L71.516,219.918Z" style="fill:rgb(184,13,24);"/>
<path d="M71.516,219.918L92.719,190.5L99.125,231L71.516,242.989L71.516,219.918Z" style="fill:rgb(175,15,27);"/>
<path d="M99.125,231L92.719,190.5L141.527,202.5L99.125,231Z" style="fill:rgb(171,18,31);"/>
<path d="M141.531,202.5L99.125,231L174.184,231.75L141.531,202.5Z" style="fill:rgb(150,18,32);"/>
<path d="M174.184,231.75L141.531,202.5L194.09,197.25L174.184,231.75Z" style="fill:rgb(145,20,34);"/>
<path d="M174.184,231.75L194.09,197.25L192.996,248.25L174.184,231.75Z" style="fill:rgb(136,21,36);"/>
<path d="M194.09,197.25L241.402,211.5L192.996,248.25L194.09,197.25Z" style="fill:rgb(152,26,45);"/>
<path d="M192.996,248.25L241.402,211.5L245.559,246L192.996,248.25Z" style="fill:rgb(128,24,41);"/>
<path d="M241.402,211.5L274.465,183.75L245.559,246L241.402,211.5Z" style="fill:rgb(127,26,45);"/>
<path d="M245.559,246L274.465,183.75L300.367,227.25L300.369,227.247L300.371,227.25L245.559,246Z" style="fill:rgb(138,30,53);"/>
<path d="M274.465,183.75L328.523,193.5L313.745,211.217L300.369,227.247L274.465,183.75Z" style="fill:rgb(130,31,54);"/>
<path d="M300.369,227.247L274.465,183.75L300.367,227.25L300.369,227.247Z" style="fill:rgb(130,31,54);"/>
<path d="M348.43,251.25L328.524,193.503L313.745,211.217L300.371,227.25L348.43,251.25Z" style="fill:rgb(110,28,49);"/>
<path d="M328.523,193.5L313.745,211.217L328.524,193.503L328.523,193.5Z" style="fill:rgb(110,28,49);"/>
<path d="M328.527,193.5L392.336,202.5L348.43,251.25L328.524,193.503L328.527,193.5Z" style="fill:rgb(103,28,49);"/>
<path d="M328.524,193.503L328.527,193.5L328.523,193.5L328.524,193.503Z" style="fill:rgb(103,28,49);"/>
<path d="M407.742,239.25L392.336,202.5L348.43,251.25L407.742,239.25Z" style="fill:rgb(118,34,60);"/>
<path d="M392.336,202.5L423.148,180.75L407.742,239.25L392.336,202.5Z" style="fill:rgb(105,33,57);"/>
<path d="M466.305,249.75L423.148,180.75L407.742,239.25L466.305,249.75Z" style="fill:rgb(101,33,58);"/>
<path d="M423.148,180.75L498.961,203.25L466.305,249.75L423.148,180.75Z" style="fill:rgb(94,33,57);"/>
<path d="M466.305,249.75L498.961,203.25L518.862,225L518.864,224.997L518.867,225L466.305,249.75Z" style="fill:rgb(96,36,62);"/>
<path d="M498.961,203.25L542.52,198L542.523,198L518.864,224.997L498.961,203.25Z" style="fill:rgb(95,38,65);"/>
<path d="M518.864,224.997L498.961,203.25L518.862,225L518.864,224.997Z" style="fill:rgb(95,38,65);"/>
<path d="M561.676,240L542.523,198L518.867,225L561.676,240Z" style="fill:rgb(78,33,57);"/>
<path d="M542.523,198L578.582,201.75L561.676,240L542.523,198Z" style="fill:rgb(74,32,56);"/>
<path d="M622.488,225L578.582,201.75L561.676,240L622.488,225Z" style="fill:rgb(68,31,54);"/>
<path d="M578.582,201.75L641.645,210L622.488,225L578.582,201.75Z" style="fill:rgb(67,32,56);"/>
<path d="M676.551,238.5L641.645,210L622.488,225L676.551,238.5Z" style="fill:rgb(71,35,61);"/>
<path d="M676.551,238.5L687.457,180L641.645,210L676.551,238.5Z" style="fill:rgb(64,33,59);"/>
<path d="M723.863,242.25L687.457,180L676.551,238.5L723.863,242.25Z" style="fill:rgb(55,29,53);"/>
<path d="M746.516,208.763L746.516,210.645L723.863,242.25L687.457,180L746.516,208.763Z" style="fill:rgb(42,23,42);"/>
<path d="M746.516,210.645L746.516,246.945L723.863,242.25L746.516,210.645Z" style="fill:rgb(57,32,60);"/>
<path d="M71.516,293.187L71.516,278.416L84.469,291.75L71.516,293.187Z" style="fill:rgb(183,16,28);"/>
<path d="M71.516,278.416L71.516,242.989L99.125,231L84.469,291.75L71.516,278.416Z" style="fill:rgb(172,18,32);"/>
<path d="M124.277,291.75L124.28,291.747L124.281,291.75L124.277,291.75Z" style="fill:rgb(167,20,35);"/>
<path d="M84.469,291.75L99.125,231L124.277,291.75L84.469,291.75Z" style="fill:rgb(167,20,35);"/>
<path d="M99.125,231L124.277,291.75L124.28,291.747L99.125,231Z" style="fill:rgb(146,20,34);"/>
<path d="M124.28,291.747L99.125,231L174.184,231.75L124.28,291.747Z" style="fill:rgb(146,20,34);"/>
<path d="M174.184,231.75L124.281,291.75L197.09,270L174.184,231.75Z" style="fill:rgb(149,23,40);"/>
<path d="M174.184,231.75L192.996,248.25L197.09,270L174.184,231.75Z" style="fill:rgb(140,24,41);"/>
<path d="M197.09,270L249.652,276.75L192.996,248.25L197.09,270Z" style="fill:rgb(137,25,44);"/>
<path d="M249.652,276.75L245.559,246L192.996,248.25L249.652,276.75Z" style="fill:rgb(143,29,51);"/>
<path d="M249.652,276.75L301.465,290.25L245.559,246L249.652,276.75Z" style="fill:rgb(135,30,52);"/>
<path d="M301.465,290.25L245.559,246L300.371,227.25L301.465,290.25Z" style="fill:rgb(127,30,52);"/>
<path d="M301.465,290.25L323.272,280.503L323.273,280.5L300.371,227.25L301.465,290.25Z" style="fill:rgb(123,32,55);"/>
<path d="M323.277,280.5L323.276,280.497L323.273,280.5L323.277,280.5Z" style="fill:rgb(123,32,55);"/>
<path d="M300.371,227.25L323.273,280.5L323.276,280.497L300.371,227.25Z" style="fill:rgb(105,29,50);"/>
<path d="M323.276,280.497L348.43,251.25L300.371,227.25L323.276,280.497Z" style="fill:rgb(105,29,50);"/>
<path d="M323.277,280.5L385.586,292.5L348.43,251.25L323.277,280.5Z" style="fill:rgb(113,33,58);"/>
<path d="M385.586,292.5L407.742,239.25L348.43,251.25L385.586,292.5Z" style="fill:rgb(114,35,62);"/>
<path d="M385.586,292.5L449.398,288L407.742,239.25L385.586,292.5Z" style="fill:rgb(104,34,60);"/>
<path d="M449.398,288L466.305,249.75L407.742,239.25L449.398,288Z" style="fill:rgb(87,31,53);"/>
<path d="M449.398,288L490.711,285.75L466.305,249.75L449.398,288Z" style="fill:rgb(96,36,62);"/>
<path d="M490.711,285.75L466.305,249.75L518.867,225L490.711,285.75Z" style="fill:rgb(88,35,60);"/>
<path d="M490.711,285.75L522.27,298.499L518.867,225L490.711,285.75Z" style="fill:rgb(81,34,59);"/>
<path d="M522.27,298.499L522.273,298.5L522.273,298.496L522.27,298.499Z" style="fill:rgb(81,34,59);"/>
<path d="M518.867,225L522.27,298.499L522.273,298.496L518.867,225Z" style="fill:rgb(85,37,65);"/>
<path d="M522.273,298.496L561.676,240L518.867,225L522.273,298.496Z" style="fill:rgb(85,37,65);"/>
<path d="M522.273,298.5L591.332,293.25L561.676,240L522.273,298.5Z" style="fill:rgb(67,30,53);"/>
<path d="M591.332,293.25L622.488,225L561.676,240L591.332,293.25Z" style="fill:rgb(56,27,47);"/>
<path d="M591.332,293.25L635.645,294.75L622.488,225L591.332,293.25Z" style="fill:rgb(73,36,63);"/>
<path d="M635.645,294.75L676.551,238.5L622.488,225L635.645,294.75Z" style="fill:rgb(53,27,48);"/>
<path d="M684.457,300.75L676.551,238.5L635.645,294.75L684.457,300.75Z" style="fill:rgb(65,35,62);"/>
<path d="M684.457,300.75L723.863,242.25L676.551,238.5L684.457,300.75Z" style="fill:rgb(50,27,49);"/>
<path d="M746.016,295.5L723.863,242.25L684.457,300.75L746.016,295.5Z" style="fill:rgb(56,31,58);"/>
<path d="M746.516,246.945L746.516,294.226L746.016,295.5L723.863,242.25L746.516,246.945Z" style="fill:rgb(42,23,46);"/>
<path d="M71.516,302.757L71.516,293.187L84.469,291.75L71.516,302.757Z" style="fill:rgb(160,17,29);"/>
<path d="M71.516,302.757L84.469,291.75L93.875,335.25L71.516,326.878L71.516,302.757Z" style="fill:rgb(160,20,34);"/>
<path d="M93.875,335.25L84.469,291.75L124.277,291.75L93.875,335.25Z" style="fill:rgb(142,20,34);"/>
<path d="M124.281,291.75L93.875,335.25L171.184,336.75L124.281,291.75Z" style="fill:rgb(160,25,43);"/>
<path d="M171.184,336.75L124.281,291.75L197.09,270L171.184,336.75Z" style="fill:rgb(137,23,40);"/>
<path d="M171.184,336.75L223.746,321.75L197.09,270L171.184,336.75Z" style="fill:rgb(133,25,43);"/>
<path d="M223.746,321.75L249.652,276.75L197.09,270L223.746,321.75Z" style="fill:rgb(129,26,46);"/>
<path d="M223.746,321.75L272.559,315.75L249.652,276.75L223.746,321.75Z" style="fill:rgb(120,26,46);"/>
<path d="M272.559,315.75L249.652,276.75L301.465,290.25L272.559,315.75Z" style="fill:rgb(112,27,46);"/>
<path d="M272.559,315.75L310.117,318.75L301.465,290.25L272.559,315.75Z" style="fill:rgb(127,32,57);"/>
<path d="M310.117,318.75L310.121,318.75L310.119,318.744L310.117,318.75Z" style="fill:rgb(127,32,57);"/>
<path d="M301.465,290.25L310.117,318.75L310.119,318.744L301.465,290.25Z" style="fill:rgb(122,33,59);"/>
<path d="M310.119,318.744L301.465,290.25L323.272,280.503L316.685,299.659L310.119,318.744Z" style="fill:rgb(122,33,59);"/>
<path d="M316.685,299.659L310.121,318.75L346.93,342.75L323.275,280.506L316.685,299.659Z" style="fill:rgb(110,32,56);"/>
<path d="M323.272,280.503L316.685,299.659L323.275,280.506L323.274,280.502L323.272,280.503Z" style="fill:rgb(110,32,56);"/>
<path d="M323.273,280.5L323.272,280.503L323.274,280.502L323.273,280.5Z" style="fill:rgb(110,32,56);"/>
<path d="M346.93,342.75L385.586,292.5L323.277,280.5L323.275,280.506L346.93,342.75Z" style="fill:rgb(103,32,56);"/>
<path d="M323.275,280.506L323.277,280.5L323.274,280.502L323.275,280.506Z" style="fill:rgb(103,32,56);"/>
<path d="M323.274,280.502L323.277,280.5L323.273,280.5L323.274,280.502Z" style="fill:rgb(103,32,56);"/>
<path d="M346.93,342.75L397.242,337.5L385.586,292.5L346.93,342.75Z" style="fill:rgb(99,33,57);"/>
<path d="M397.242,337.5L449.398,288L385.586,292.5L397.242,337.5Z" style="fill:rgb(92,33,56);"/>
<path d="M397.242,337.5L455.055,321L449.398,288L397.242,337.5Z" style="fill:rgb(78,29,50);"/>
<path d="M455.055,321L449.398,288L490.711,285.75L455.055,321Z" style="fill:rgb(92,36,63);"/>
<path d="M455.055,321L516.612,331.499L490.711,285.75L455.055,321Z" style="fill:rgb(84,35,61);"/>
<path d="M516.612,331.499L516.617,331.5L516.613,331.493L516.612,331.499Z" style="fill:rgb(84,35,61);"/>
<path d="M490.711,285.75L516.612,331.499L516.613,331.493L490.711,285.75Z" style="fill:rgb(70,30,53);"/>
<path d="M516.613,331.493L490.711,285.75L522.273,298.5L516.613,331.493Z" style="fill:rgb(70,30,53);"/>
<path d="M516.617,331.5L548.926,323.25L522.273,298.5L516.617,331.5Z" style="fill:rgb(78,36,62);"/>
<path d="M548.926,323.25L591.332,293.25L522.273,298.5L548.926,323.25Z" style="fill:rgb(67,32,56);"/>
<path d="M548.926,323.25L597.738,326.25L591.332,293.25L548.926,323.25Z" style="fill:rgb(56,28,49);"/>
<path d="M597.738,326.25L635.645,294.75L591.332,293.25L597.738,326.25Z" style="fill:rgb(67,34,61);"/>
<path d="M597.738,326.25L649.551,334.5L635.645,294.75L597.738,326.25Z" style="fill:rgb(45,24,43);"/>
<path d="M649.551,334.5L635.645,294.75L684.457,300.75L649.551,334.5Z" style="fill:rgb(48,27,48);"/>
<path d="M649.551,334.5L710.363,327.75L684.457,300.75L649.551,334.5Z" style="fill:rgb(53,29,55);"/>
<path d="M710.363,327.75L746.016,295.5L684.457,300.75L710.363,327.75Z" style="fill:rgb(49,27,54);"/>
<path d="M746.516,296.212L746.516,331.62L710.363,327.75L746.016,295.5L746.516,296.212Z" style="fill:rgb(41,23,47);"/>
<path d="M71.516,387.069L71.516,362.942L84.469,391.5L71.516,387.069Z" style="fill:rgb(163,20,34);"/>
<path d="M71.516,362.942L71.516,326.878L93.875,335.25L84.469,391.5L71.516,362.942Z" style="fill:rgb(166,23,39);"/>
<path d="M135.527,363L135.529,362.999L135.531,363L135.526,363.003L135.527,363Z" style="fill:rgb(154,24,41);"/>
<path d="M84.469,391.5L93.875,335.25L135.527,363L84.469,391.5Z" style="fill:rgb(154,24,41);"/>
<path d="M93.875,335.25L135.527,363L135.529,362.999L93.875,335.25Z" style="fill:rgb(136,23,40);"/>
<path d="M135.529,362.999L93.875,335.25L171.184,336.75L135.529,362.999Z" style="fill:rgb(136,23,40);"/>
<path d="M135.531,363L170.09,389.25L171.184,336.75L135.531,363Z" style="fill:rgb(132,25,42);"/>
<path d="M170.09,389.25L223.746,321.75L171.184,336.75L170.09,389.25Z" style="fill:rgb(126,26,45);"/>
<path d="M170.09,389.25L224.152,362.25L223.746,321.75L170.09,389.25Z" style="fill:rgb(128,28,49);"/>
<path d="M224.152,362.25L223.746,321.75L272.559,315.75L224.152,362.25Z" style="fill:rgb(121,29,50);"/>
<path d="M224.152,362.25L276.715,384.75L272.559,315.75L224.152,362.25Z" style="fill:rgb(108,27,48);"/>
<path d="M276.715,384.75L272.559,315.75L310.117,318.75L310.121,318.75L276.715,384.75Z" style="fill:rgb(104,28,50);"/>
<path d="M342.777,386.249L342.773,386.25L342.774,386.243L342.777,386.249Z" style="fill:rgb(116,34,59);"/>
<path d="M276.715,384.75L342.773,386.25L310.121,318.75L276.715,384.75Z" style="fill:rgb(116,34,59);"/>
<path d="M310.121,318.75L342.773,386.25L342.774,386.243L310.121,318.75Z" style="fill:rgb(100,31,54);"/>
<path d="M342.774,386.243L310.121,318.75L346.93,342.75L342.774,386.243Z" style="fill:rgb(100,31,54);"/>
<path d="M378.086,374.25L342.777,386.249L346.93,342.75L378.086,374.25Z" style="fill:rgb(104,34,60);"/>
<path d="M378.086,374.25L397.242,337.5L346.93,342.75L378.086,374.25Z" style="fill:rgb(84,30,51);"/>
<path d="M378.086,374.25L432.148,390.75L397.242,337.5L378.086,374.25Z" style="fill:rgb(88,33,57);"/>
<path d="M432.148,390.75L397.242,337.5L455.055,321L432.148,390.75Z" style="fill:rgb(85,34,58);"/>
<path d="M432.148,390.75L491.461,366L455.055,321L432.148,390.75Z" style="fill:rgb(73,30,53);"/>
<path d="M491.461,366L455.055,321L516.612,331.499L516.617,331.5L491.461,366Z" style="fill:rgb(74,32,56);"/>
<path d="M520.021,392.998L520.023,393L520.023,392.994L520.021,392.998Z" style="fill:rgb(74,34,59);"/>
<path d="M491.461,366L520.02,392.997L516.617,331.5L491.461,366Z" style="fill:rgb(74,34,59);"/>
<path d="M520.021,392.998L520.023,392.994L516.617,331.5L520.02,392.997L520.021,392.998Z" style="fill:rgb(75,36,63);"/>
<path d="M520.023,392.994L548.926,323.25L516.617,331.5L520.023,392.994Z" style="fill:rgb(75,36,63);"/>
<path d="M520.023,393L595.832,386.25L548.926,323.25L520.023,393Z" style="fill:rgb(60,30,53);"/>
<path d="M595.832,386.25L597.738,326.25L548.926,323.25L595.832,386.25Z" style="fill:rgb(52,27,48);"/>
<path d="M595.832,386.25L646.895,366L597.738,326.25L595.832,386.25Z" style="fill:rgb(60,32,57);"/>
<path d="M646.895,366L597.738,326.25L649.551,334.5L646.895,366Z" style="fill:rgb(58,32,57);"/>
<path d="M646.895,366L685.957,393L649.551,334.5L646.895,366Z" style="fill:rgb(54,30,56);"/>
<path d="M685.957,393L649.551,334.5L710.363,327.75L685.957,393Z" style="fill:rgb(37,21,41);"/>
<path d="M685.957,393L727.266,364.5L710.363,327.75L685.957,393Z" style="fill:rgb(33,19,39);"/>
<path d="M746.516,331.62L746.516,351.988L727.266,364.5L710.363,327.75L746.516,331.62Z" style="fill:rgb(33,19,41);"/>
<path d="M746.516,351.988L746.516,364.268L727.266,364.5L746.516,351.988Z" style="fill:rgb(38,22,50);"/>
<path d="M71.516,405.402L71.516,387.069L84.469,391.5L71.516,405.402Z" style="fill:rgb(166,23,39);"/>
<path d="M71.516,405.402L84.469,391.5L120.125,406.5L71.516,416.092L71.516,405.402Z" style="fill:rgb(139,21,37);"/>
<path d="M135.527,363L84.469,391.5L135.526,363.003L135.527,363Z" style="fill:rgb(131,22,39);"/>
<path d="M120.125,406.5L84.469,391.5L135.526,363.003L120.125,406.5Z" style="fill:rgb(131,22,39);"/>
<path d="M120.125,406.5L164.434,429.75L135.531,363L120.125,406.5Z" style="fill:rgb(138,26,44);"/>
<path d="M164.434,429.75L170.09,389.25L135.531,363L164.434,429.75Z" style="fill:rgb(131,27,47);"/>
<path d="M164.434,429.75L225.996,435.75L170.09,389.25L164.434,429.75Z" style="fill:rgb(123,27,47);"/>
<path d="M225.996,435.75L170.09,389.25L224.152,362.25L225.996,435.75Z" style="fill:rgb(127,30,52);"/>
<path d="M225.996,435.75L261.308,429L224.152,362.25L225.996,435.75Z" style="fill:rgb(109,28,49);"/>
<path d="M261.308,429L224.152,362.25L276.715,384.75L261.308,429Z" style="fill:rgb(110,30,53);"/>
<path d="M261.308,429L305.617,435L276.715,384.75L261.308,429Z" style="fill:rgb(110,32,56);"/>
<path d="M305.617,435L305.621,435L305.619,434.997L305.617,435Z" style="fill:rgb(110,32,56);"/>
<path d="M305.619,434.997L276.715,384.75L342.773,386.25L324.622,410.068L305.619,434.997Z" style="fill:rgb(102,32,56);"/>
<path d="M276.715,384.75L305.617,435L305.619,434.997L276.715,384.75Z" style="fill:rgb(102,32,56);"/>
<path d="M324.622,410.068L342.775,386.253L342.773,386.25L324.622,410.068Z" style="fill:rgb(94,31,55);"/>
<path d="M305.621,435L356.68,413.25L342.775,386.253L324.622,410.068L305.621,435Z" style="fill:rgb(94,31,55);"/>
<path d="M342.777,386.25L378.086,374.25L342.777,386.249L342.777,386.25Z" style="fill:rgb(102,36,62);"/>
<path d="M342.775,386.253L342.777,386.25L342.773,386.25L342.775,386.253Z" style="fill:rgb(102,36,62);"/>
<path d="M342.777,386.249L342.777,386.25L342.773,386.25L342.777,386.249Z" style="fill:rgb(102,36,62);"/>
<path d="M356.68,413.25L378.086,374.25L342.777,386.25L342.775,386.253L356.68,413.25Z" style="fill:rgb(102,36,62);"/>
<path d="M356.68,413.25L424.992,406.5L378.086,374.25L356.68,413.25Z" style="fill:rgb(90,34,58);"/>
<path d="M424.992,406.5L378.086,374.25L432.148,390.75L424.992,406.5Z" style="fill:rgb(95,37,65);"/>
<path d="M424.992,406.5L476.805,423L432.148,390.75L424.992,406.5Z" style="fill:rgb(76,32,55);"/>
<path d="M476.805,423L432.148,390.75L491.461,366L476.805,423Z" style="fill:rgb(85,37,65);"/>
<path d="M476.805,423L524.867,409.5L524.86,409.492L524.863,409.5L491.461,366L476.805,423Z" style="fill:rgb(65,30,52);"/>
<path d="M524.86,409.492L520.023,393L520.021,392.998L520.02,393L520.02,392.997L491.461,366L524.86,409.492Z" style="fill:rgb(71,34,59);"/>
<path d="M520.02,392.997L520.02,393L520.021,392.998L520.02,392.997Z" style="fill:rgb(71,34,59);"/>
<path d="M491.461,366L524.863,409.5L524.86,409.492L491.461,366Z" style="fill:rgb(71,34,59);"/>
<path d="M524.867,409.5L565.426,420L520.023,393L524.867,409.5Z" style="fill:rgb(62,31,54);"/>
<path d="M565.426,420L595.832,386.25L520.023,393L565.426,420Z" style="fill:rgb(64,33,58);"/>
<path d="M565.426,420L599.988,424.5L595.832,386.25L565.426,420Z" style="fill:rgb(57,31,55);"/>
<path d="M599.988,424.5L595.832,386.25L646.895,366L599.988,424.5Z" style="fill:rgb(57,31,57);"/>
<path d="M599.988,424.5L648.051,413.25L646.895,366L599.988,424.5Z" style="fill:rgb(47,26,49);"/>
<path d="M648.051,413.25L646.895,366L685.957,393L648.051,413.25Z" style="fill:rgb(42,23,46);"/>
<path d="M648.051,413.25L722.363,413.25L685.957,393L648.051,413.25Z" style="fill:rgb(35,19,40);"/>
<path d="M722.363,413.25L685.957,393L727.266,364.5L722.363,413.25Z" style="fill:rgb(45,25,56);"/>
<path d="M722.363,413.25L746.516,419.397L746.516,398.21L727.266,364.5L722.363,413.25Z" style="fill:rgb(42,24,56);"/>
<path d="M746.516,398.21L727.266,364.5L746.516,364.268L746.516,398.21Z" style="fill:rgb(24,14,35);"/>
<path d="M92.643,450.439L71.516,450.439L71.516,416.092L120.125,406.5L92.643,450.439Z" style="fill:rgb(136,23,40);"/>
<path d="M127.71,450.439L92.643,450.439L120.125,406.5L127.71,450.439Z" style="fill:rgb(126,24,41);"/>
<path d="M127.712,450.439L127.71,450.439L120.125,406.5L127.712,450.439Z" style="fill:rgb(141,29,50);"/>
<path d="M149.165,450.439L127.712,450.439L120.125,406.5L164.434,429.75L149.165,450.439Z" style="fill:rgb(141,29,50);"/>
<path d="M170.017,450.439L149.167,450.439L164.434,429.75L170.017,450.439Z" style="fill:rgb(137,30,53);"/>
<path d="M209.364,450.439L170.017,450.439L164.434,429.75L225.996,435.75L209.364,450.439Z" style="fill:rgb(116,27,48);"/>
<path d="M222.241,450.439L209.364,450.439L225.996,435.75L222.241,450.439Z" style="fill:rgb(112,29,50);"/>
<path d="M234.956,450.439L222.241,450.439L225.996,435.75L261.308,429L234.956,450.439Z" style="fill:rgb(123,34,59);"/>
<path d="M293.498,450.439L234.956,450.439L261.308,429L293.498,450.439Z" style="fill:rgb(103,30,52);"/>
<path d="M294.195,450.439L293.498,450.439L261.308,429L305.617,435L305.621,435L294.195,450.439Z" style="fill:rgb(112,35,61);"/>
<path d="M328.115,450.439L294.195,450.439L305.621,435L328.115,450.439Z" style="fill:rgb(104,34,60);"/>
<path d="M328.117,450.439L328.115,450.439L305.621,435L328.117,450.439Z" style="fill:rgb(97,34,59);"/>
<path d="M345.734,450.439L328.117,450.439L305.621,435L356.68,413.25L345.734,450.439Z" style="fill:rgb(97,34,59);"/>
<path d="M383.369,450.439L345.737,450.439L356.68,413.25L383.369,450.439Z" style="fill:rgb(84,31,54);"/>
<path d="M406.103,450.439L383.369,450.439L356.68,413.25L424.992,406.5L406.103,450.439Z" style="fill:rgb(91,36,62);"/>
<path d="M431.865,450.439L406.103,450.439L424.992,406.5L431.865,450.439Z" style="fill:rgb(72,30,52);"/>
<path d="M434.913,450.439L431.865,450.439L424.992,406.5L476.805,423L434.913,450.439Z" style="fill:rgb(75,33,57);"/>
<path d="M474.725,450.439L434.913,450.439L476.805,423L474.725,450.439Z" style="fill:rgb(73,34,58);"/>
<path d="M493.234,450.439L474.725,450.439L476.805,423L524.867,409.5L493.234,450.439Z" style="fill:rgb(60,29,50);"/>
<path d="M520.976,450.439L493.234,450.439L524.867,409.5L520.976,450.439Z" style="fill:rgb(61,30,53);"/>
<path d="M520.979,450.439L520.976,450.439L524.867,409.5L520.979,450.439Z" style="fill:rgb(55,28,50);"/>
<path d="M531.3,450.439L520.979,450.439L524.867,409.5L565.426,420L531.3,450.439Z" style="fill:rgb(55,28,50);"/>
<path d="M571.489,450.439L531.302,450.439L565.426,420L571.489,450.439Z" style="fill:rgb(52,28,50);"/>
<path d="M587.777,450.439L571.489,450.439L565.426,420L599.988,424.5L587.777,450.439Z" style="fill:rgb(61,34,61);"/>
<path d="M616.864,450.439L587.777,450.439L599.988,424.5L616.864,450.439Z" style="fill:rgb(52,29,54);"/>
<path d="M639.939,450.439L616.864,450.439L599.988,424.5L648.051,413.25L639.939,450.439Z" style="fill:rgb(49,27,54);"/>
<path d="M678.864,450.439L639.939,450.439L648.051,413.25L678.864,450.439Z" style="fill:rgb(31,18,36);"/>
<path d="M692.769,450.439L678.864,450.439L648.051,413.25L722.363,413.25L692.769,450.439Z" style="fill:rgb(44,25,54);"/>
<path d="M740.978,450.439L692.769,450.439L722.363,413.25L740.978,450.439Z" style="fill:rgb(33,19,43);"/>
<path d="M746.516,419.397L746.516,450.439L740.978,450.439L722.363,413.25L746.516,419.397Z" style="fill:rgb(24,14,35);"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,9 +1,6 @@
targets:
$default:
builders:
freezed:
options:
generic_argument_factories: true
json_serializable:
options:
explicit_to_json: true

View File

@ -14,13 +14,13 @@ sed -i '' 's/MACOSX_DEPLOYMENT_TARGET = [^;]*/MACOSX_DEPLOYMENT_TARGET = 10.14.6
sed -i '' "s/platform :osx, '[^']*'/platform :osx, '10.14.6'/g" $APPDIR/macos/Podfile
# Android: Set NDK version
if [[ "$TMPDIR" != "" ]]; then
if [[ "$TMPDIR" != "" ]]; then
ANDTMP=$TMPDIR/andtmp_$(date +%s)
else
else
ANDTMP=/tmp/andtmp_$(date +%s)
fi
cat <<EOF > $ANDTMP
ndkVersion '27.0.12077973'
ndkVersion '26.3.11579264'
EOF
sed -i '' -e "/android {/r $ANDTMP" $APPDIR/android/app/build.gradle
rm -- $ANDTMP
@ -29,7 +29,7 @@ rm -- $ANDTMP
sed -i '' 's/minSdkVersion .*/minSdkVersion Math.max(flutter.minSdkVersion, 24)/g' $APPDIR/android/app/build.gradle
# Android: Set gradle plugin version
sed -i '' "s/classpath \'com.android.tools.build:gradle:[^\']*\'/classpath 'com.android.tools.build:gradle:8.8.0'/g" $APPDIR/android/build.gradle
sed -i '' "s/classpath \'com.android.tools.build:gradle:[^\']*\'/classpath 'com.android.tools.build:gradle:7.2.0'/g" $APPDIR/android/build.gradle
# Android: Set gradle version
sed -i '' 's/distributionUrl=.*/distributionUrl=https:\/\/services.gradle.org\/distributions\/gradle-8.10.2-all.zip/g' $APPDIR/android/gradle/wrapper/gradle-wrapper.properties
sed -i '' 's/distributionUrl=.*/distributionUrl=https:\/\/services.gradle.org\/distributions\/gradle-7.6.3-all.zip/g' $APPDIR/android/gradle/wrapper/gradle-wrapper.properties

View File

@ -1,35 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json
---
app-id: com.veilid.veilidchat
runtime: org.gnome.Platform
runtime-version: "46"
sdk: org.gnome.Sdk
command: veilidchat
separate-locales: false
finish-args:
- --share=ipc
- --socket=fallback-x11
- --socket=wayland
- --device=dri
- --socket=pulseaudio
- --share=network
- --talk-name=org.freedesktop.secrets
modules:
- name: VeilidChat
buildsystem: simple
only-arches:
- aarch64
build-commands:
- "./build-flatpak.sh"
sources:
- type: dir
path: ../build/linux/arm64/release/
- type: file
path: build-flatpak.sh
- type: file
path: com.veilid.veilidchat.png
- type: file
path: com.veilid.veilidchat.desktop
- type: file
path: com.veilid.veilidchat.metainfo.xml

View File

@ -3,7 +3,7 @@
---
app-id: com.veilid.veilidchat
runtime: org.gnome.Platform
runtime-version: "46"
runtime-version: "45"
sdk: org.gnome.Sdk
command: veilidchat
separate-locales: false

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '15.6'
# platform :ios, '12.4'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -4,56 +4,62 @@ PODS:
- file_saver (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_native_splash (2.4.3):
- flutter_native_splash (0.0.1):
- Flutter
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- GoogleMLKit/BarcodeScanning (7.0.0):
- GoogleDataTransport (9.4.1):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleMLKit/BarcodeScanning (6.0.0):
- GoogleMLKit/MLKitCore
- MLKitBarcodeScanning (~> 6.0.0)
- GoogleMLKit/MLKitCore (7.0.0):
- MLKitCommon (~> 12.0.0)
- MLKitBarcodeScanning (~> 5.0.0)
- GoogleMLKit/MLKitCore (6.0.0):
- MLKitCommon (~> 11.0.0)
- GoogleToolboxForMac/Defines (4.2.1)
- GoogleToolboxForMac/Logger (4.2.1):
- GoogleToolboxForMac/Defines (= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (4.2.1)":
- GoogleToolboxForMac/Defines (= 4.2.1)
- GoogleUtilities/Environment (8.0.2):
- GoogleUtilities/Environment (7.13.3):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.0.2):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.13.3):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.0.2)
- GoogleUtilities/UserDefaults (8.0.2):
- GoogleUtilities/Privacy (7.13.3)
- GoogleUtilities/UserDefaults (7.13.3):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMSessionFetcher/Core (3.5.0)
- MLImage (1.0.0-beta6)
- MLKitBarcodeScanning (6.0.0):
- MLKitCommon (~> 12.0)
- MLKitVision (~> 8.0)
- MLKitCommon (12.0.0):
- GoogleDataTransport (~> 10.0)
- GoogleUtilitiesComponents (1.1.0):
- GoogleUtilities/Logger
- GTMSessionFetcher/Core (3.4.1)
- MLImage (1.0.0-beta5)
- MLKitBarcodeScanning (5.0.0):
- MLKitCommon (~> 11.0)
- MLKitVision (~> 7.0)
- MLKitCommon (11.0.0):
- GoogleDataTransport (< 10.0, >= 9.4.1)
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GoogleUtilities/Logger (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- GoogleUtilities/UserDefaults (< 8.0, >= 7.13.0)
- GoogleUtilitiesComponents (~> 1.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLKitVision (8.0.0):
- MLKitVision (7.0.0):
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLImage (= 1.0.0-beta6)
- MLKitCommon (~> 12.0)
- mobile_scanner (6.0.2):
- MLImage (= 1.0.0-beta5)
- MLKitCommon (~> 11.0)
- mobile_scanner (5.1.1):
- Flutter
- GoogleMLKit/BarcodeScanning (~> 6.0.0)
- nanopb (2.30910.0):
- nanopb/decode (= 2.30910.0)
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
- native_device_orientation (0.0.1):
- Flutter
- GoogleMLKit/BarcodeScanning (~> 7.0.0)
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- package_info_plus (0.4.5):
- Flutter
- pasteboard (0.0.1):
@ -69,7 +75,9 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- smart_auth (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- system_info_plus (0.0.1):
@ -85,13 +93,15 @@ DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `.symlinks/plugins/printing/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- smart_auth (from `.symlinks/plugins/smart_auth/ios`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- system_info_plus (from `.symlinks/plugins/system_info_plus/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- veilid (from `.symlinks/plugins/veilid/ios`)
@ -102,6 +112,7 @@ SPEC REPOS:
- GoogleMLKit
- GoogleToolboxForMac
- GoogleUtilities
- GoogleUtilitiesComponents
- GTMSessionFetcher
- MLImage
- MLKitBarcodeScanning
@ -121,6 +132,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_native_splash/ios"
mobile_scanner:
:path: ".symlinks/plugins/mobile_scanner/ios"
native_device_orientation:
:path: ".symlinks/plugins/native_device_orientation/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
pasteboard:
@ -133,8 +146,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
smart_auth:
:path: ".symlinks/plugins/smart_auth/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/darwin"
system_info_plus:
:path: ".symlinks/plugins/system_info_plus/ios"
url_launcher_ios:
@ -143,33 +158,36 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/veilid/ios"
SPEC CHECKSUMS:
camera_avfoundation: 04b44aeb14070126c6529e5ab82cc7c9fca107cf
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleMLKit: 97ac7af399057e99182ee8edfa8249e3226a4065
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
mobile_scanner: af8f71879eaba2bbcb4d86c6a462c3c0e7f23036
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
printing: 54ff03f28fe9ba3aa93358afb80a8595a071dd07
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe
GTMSessionFetcher: 8000756fc1c19d2e5697b90311f7832d2e33f6cd
MLImage: 1824212150da33ef225fbd3dc49f184cf611046c
MLKitBarcodeScanning: 10ca0845a6d15f2f6e911f682a1998b68b973e8b
MLKitCommon: afec63980417d29ffbb4790529a1b0a2291699e1
MLKitVision: e858c5f125ecc288e4a31127928301eaba9ae0c1
mobile_scanner: 8564358885a9253c43f822435b70f9345c87224f
nanopb: 438bc412db1928dac798aa6fd75726007be04262
native_device_orientation: 348b10c346a60ebbc62fb235a4fdb5d1b61a8f55
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
veilid: b3b9418ae6b083e662396bfa2c635fb115c8510e
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
smart_auth: 4bedbc118723912d0e45a07e8ab34039c19e04f2
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
veilid: f5c2e662f91907b30cf95762619526ac3e4512fd
PODFILE CHECKSUM: c8bf5b16c34712d5790b0b8d2472cc66ac0a8487
PODFILE CHECKSUM: 5d504085cd7c7a4d71ee600d7af087cb60ab75b2
COCOAPODS: 1.16.2
COCOAPODS: 1.15.2

View File

@ -156,7 +156,6 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@ -343,7 +342,6 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -354,7 +352,6 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -380,11 +377,9 @@
CLANG_ENABLE_MODULES = YES;
DEVELOPMENT_TEAM = XP5LBLT7M7;
ENABLE_BITCODE = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -420,7 +415,6 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -431,7 +425,6 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -477,7 +470,6 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -488,7 +480,6 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -516,11 +507,9 @@
CLANG_ENABLE_MODULES = YES;
DEVELOPMENT_TEAM = XP5LBLT7M7;
ENABLE_BITCODE = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -542,11 +531,9 @@
CLANG_ENABLE_MODULES = YES;
DEVELOPMENT_TEAM = XP5LBLT7M7;
ENABLE_BITCODE = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = VeilidChat;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",

View File

@ -48,7 +48,6 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@ -23,6 +23,7 @@ class AccountInfoCubit extends Cubit<AccountInfo> {
if (acctInfo != null) {
emit(acctInfo);
}
break;
}
});
}

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:async_tools/async_tools.dart';
import 'package:protobuf/protobuf.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../proto/proto.dart' as proto;
@ -46,30 +47,53 @@ class AccountRecordCubit extends DefaultDHTRecordCubit<AccountRecordState> {
// Public Interface
void updateAccount(
AccountSpec accountSpec, Future<void> Function() onChanged) {
_sspUpdate.updateState((accountSpec, onChanged), (state) async {
AccountSpec accountSpec, Future<void> Function() onSuccess) {
_sspUpdate.updateState((accountSpec, onSuccess), (state) async {
await _updateAccountAsync(state.$1, state.$2);
});
}
Future<void> _updateAccountAsync(
AccountSpec accountSpec, Future<void> Function() onChanged) async {
var changed = true;
AccountSpec accountSpec, Future<void> Function() onSuccess) async {
var changed = false;
await record?.eventualUpdateProtobuf(proto.Account.fromBuffer, (old) async {
changed = false;
if (old == null) {
return null;
}
final oldAccountSpec = AccountSpec.fromProto(old);
changed = oldAccountSpec != accountSpec;
if (!changed) {
return null;
}
final newAccount = old.deepCopy()
..profile.name = accountSpec.name
..profile.pronouns = accountSpec.pronouns
..profile.about = accountSpec.about
..profile.availability = accountSpec.availability
..profile.status = accountSpec.status
//..profile.avatar =
..profile.timestamp = Veilid.instance.now().toInt64()
..invisible = accountSpec.invisible
..autodetectAway = accountSpec.autoAway
..autoAwayTimeoutMin = accountSpec.autoAwayTimeout
..freeMessage = accountSpec.freeMessage
..awayMessage = accountSpec.awayMessage
..busyMessage = accountSpec.busyMessage;
return accountSpec.updateProto(old);
if (newAccount.profile != old.profile ||
newAccount.invisible != old.invisible ||
newAccount.autodetectAway != old.autodetectAway ||
newAccount.autoAwayTimeoutMin != old.autoAwayTimeoutMin ||
newAccount.freeMessage != old.freeMessage ||
newAccount.busyMessage != old.busyMessage ||
newAccount.awayMessage != old.awayMessage) {
changed = true;
}
if (changed) {
return newAccount;
}
return null;
});
if (changed) {
await onChanged();
await onSuccess();
}
}

View File

@ -14,6 +14,7 @@ class ActiveLocalAccountCubit extends Cubit<TypedKey?> {
switch (change) {
case AccountRepositoryChange.activeLocalAccount:
emit(_accountRepository.getActiveLocalAccount());
break;
// Ignore these
case AccountRepositoryChange.localAccounts:
case AccountRepositoryChange.userLogins:

View File

@ -20,6 +20,7 @@ class LocalAccountsCubit extends Cubit<LocalAccountsState>
switch (change) {
case AccountRepositoryChange.localAccounts:
emit(_accountRepository.getLocalAccounts());
break;
// Ignore these
case AccountRepositoryChange.userLogins:
case AccountRepositoryChange.activeLocalAccount:

View File

@ -15,9 +15,6 @@ import '../../notifications/notifications.dart';
import '../../proto/proto.dart' as proto;
import '../account_manager.dart';
const _kAccountRecordSubscriptionListenKey =
'accountRecordSubscriptionListenKey';
class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
PerAccountCollectionCubit({
required Locator locator,
@ -35,7 +32,6 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
await _processor.close();
await accountInfoCubit.close();
await _accountRecordSubscription?.cancel();
await serialFutureClose((this, _kAccountRecordSubscriptionListenKey));
await accountRecordCubit?.close();
await activeSingleContactChatBlocMapCubitUpdater.close();
@ -87,7 +83,7 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
accountRecordCubit = null;
// Update state to 'loading'
nextState = await _updateAccountRecordState(nextState, null);
nextState = _updateAccountRecordState(nextState, null);
emit(nextState);
} else {
///////////////// Logged in ///////////////////
@ -99,22 +95,20 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
// Update state to value
nextState =
await _updateAccountRecordState(nextState, accountRecordCubit!.state);
_updateAccountRecordState(nextState, accountRecordCubit!.state);
emit(nextState);
// Subscribe AccountRecordCubit
_accountRecordSubscription ??=
accountRecordCubit!.stream.listen((avAccountRecordState) {
serialFuture((this, _kAccountRecordSubscriptionListenKey), () async {
emit(await _updateAccountRecordState(state, avAccountRecordState));
});
emit(_updateAccountRecordState(state, avAccountRecordState));
});
}
}
Future<PerAccountCollectionState> _updateAccountRecordState(
PerAccountCollectionState _updateAccountRecordState(
PerAccountCollectionState prevState,
AsyncValue<AccountRecordState>? avAccountRecordState) async {
AsyncValue<AccountRecordState>? avAccountRecordState) {
// Get next state
final nextState =
prevState.copyWith(avAccountRecordState: avAccountRecordState);
@ -127,8 +121,8 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
.avAccountRecordState?.asData?.value.contactInvitationRecords
.toVeilid();
final contactInvitationListCubit = await contactInvitationListCubitUpdater
.update(accountInfo.userLogin == null ||
final contactInvitationListCubit = contactInvitationListCubitUpdater.update(
accountInfo.userLogin == null ||
contactInvitationListRecordPointer == null
? null
: (accountInfo, contactInvitationListRecordPointer));
@ -137,35 +131,34 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
final contactListRecordPointer =
nextState.avAccountRecordState?.asData?.value.contactList.toVeilid();
final contactListCubit = await contactListCubitUpdater.update(
final contactListCubit = contactListCubitUpdater.update(
accountInfo.userLogin == null || contactListRecordPointer == null
? null
: (accountInfo, contactListRecordPointer));
// WaitingInvitationsBlocMapCubit
final waitingInvitationsBlocMapCubit =
await waitingInvitationsBlocMapCubitUpdater.update(
accountInfo.userLogin == null ||
contactInvitationListCubit == null ||
contactListCubit == null
? null
: (
accountInfo,
accountRecordCubit!,
contactInvitationListCubit,
contactListCubit,
_locator<NotificationsCubit>(),
));
final waitingInvitationsBlocMapCubit = waitingInvitationsBlocMapCubitUpdater
.update(accountInfo.userLogin == null ||
contactInvitationListCubit == null ||
contactListCubit == null
? null
: (
accountInfo,
accountRecordCubit!,
contactInvitationListCubit,
contactListCubit,
_locator<NotificationsCubit>(),
));
// ActiveChatCubit
final activeChatCubit = await activeChatCubitUpdater
final activeChatCubit = activeChatCubitUpdater
.update((accountInfo.userLogin == null) ? null : true);
// ChatListCubit
final chatListRecordPointer =
nextState.avAccountRecordState?.asData?.value.chatList.toVeilid();
final chatListCubit = await chatListCubitUpdater.update(
final chatListCubit = chatListCubitUpdater.update(
accountInfo.userLogin == null ||
chatListRecordPointer == null ||
activeChatCubit == null
@ -174,7 +167,7 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
// ActiveConversationsBlocMapCubit
final activeConversationsBlocMapCubit =
await activeConversationsBlocMapCubitUpdater.update(
activeConversationsBlocMapCubitUpdater.update(
accountRecordCubit == null ||
chatListCubit == null ||
contactListCubit == null
@ -188,7 +181,7 @@ class PerAccountCollectionCubit extends Cubit<PerAccountCollectionState> {
// ActiveSingleContactChatBlocMapCubit
final activeSingleContactChatBlocMapCubit =
await activeSingleContactChatBlocMapCubitUpdater.update(
activeSingleContactChatBlocMapCubitUpdater.update(
accountInfo.userLogin == null ||
activeConversationsBlocMapCubit == null
? null

View File

@ -17,6 +17,7 @@ class UserLoginsCubit extends Cubit<UserLoginsState> {
switch (change) {
case AccountRepositoryChange.userLogins:
emit(_accountRepository.getUserLogins());
break;
// Ignore these
case AccountRepositoryChange.localAccounts:
case AccountRepositoryChange.activeLocalAccount:

View File

@ -13,7 +13,7 @@ enum AccountInfoStatus {
}
@immutable
class AccountInfo extends Equatable implements ToDebugMap {
class AccountInfo extends Equatable {
const AccountInfo({
required this.status,
required this.localAccount,
@ -30,13 +30,6 @@ class AccountInfo extends Equatable implements ToDebugMap {
localAccount,
userLogin,
];
@override
Map<String, dynamic> toDebugMap() => {
'status': status,
'localAccount': localAccount,
'userLogin': userLogin,
};
}
extension AccountInfoExt on AccountInfo {

View File

@ -1,16 +1,12 @@
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'package:protobuf/protobuf.dart';
import 'package:veilid_support/veilid_support.dart';
import 'package:flutter/widgets.dart';
import '../../proto/proto.dart' as proto;
/// Profile and Account configurable fields
/// Some are publicly visible via the proto.Profile
/// Some are privately held as proto.Account configurations
@immutable
class AccountSpec extends Equatable {
const AccountSpec(
class AccountSpec {
AccountSpec(
{required this.name,
required this.pronouns,
required this.about,
@ -23,99 +19,37 @@ class AccountSpec extends Equatable {
required this.autoAway,
required this.autoAwayTimeout});
const AccountSpec.empty()
: name = '',
pronouns = '',
about = '',
availability = proto.Availability.AVAILABILITY_FREE,
invisible = false,
freeMessage = '',
awayMessage = '',
busyMessage = '',
avatar = null,
autoAway = false,
autoAwayTimeout = 15;
AccountSpec.fromProto(proto.Account p)
: name = p.profile.name,
pronouns = p.profile.pronouns,
about = p.profile.about,
availability = p.profile.availability,
invisible = p.invisible,
freeMessage = p.freeMessage,
awayMessage = p.awayMessage,
busyMessage = p.busyMessage,
avatar = p.profile.hasAvatar() ? p.profile.avatar : null,
autoAway = p.autodetectAway,
autoAwayTimeout = p.autoAwayTimeoutMin;
String get status {
late final String status;
switch (availability) {
case proto.Availability.AVAILABILITY_AWAY:
status = awayMessage;
break;
case proto.Availability.AVAILABILITY_BUSY:
status = busyMessage;
break;
case proto.Availability.AVAILABILITY_FREE:
status = freeMessage;
break;
case proto.Availability.AVAILABILITY_UNSPECIFIED:
case proto.Availability.AVAILABILITY_OFFLINE:
status = '';
break;
}
return status;
}
Future<proto.Account> updateProto(proto.Account old) async {
final newProto = old.deepCopy()
..profile.name = name
..profile.pronouns = pronouns
..profile.about = about
..profile.availability = availability
..profile.status = status
..profile.timestamp = Veilid.instance.now().toInt64()
..invisible = invisible
..autodetectAway = autoAway
..autoAwayTimeoutMin = autoAwayTimeout
..freeMessage = freeMessage
..awayMessage = awayMessage
..busyMessage = busyMessage;
final newAvatar = avatar;
if (newAvatar != null) {
newProto.profile.avatar = newAvatar;
} else {
newProto.profile.clearAvatar();
}
return newProto;
}
////////////////////////////////////////////////////////////////////////////
final String name;
final String pronouns;
final String about;
final proto.Availability availability;
final bool invisible;
final String freeMessage;
final String awayMessage;
final String busyMessage;
final proto.DataReference? avatar;
final bool autoAway;
final int autoAwayTimeout;
@override
List<Object?> get props => [
name,
pronouns,
about,
availability,
invisible,
freeMessage,
awayMessage,
busyMessage,
avatar,
autoAway,
autoAwayTimeout
];
String name;
String pronouns;
String about;
proto.Availability availability;
bool invisible;
String freeMessage;
String awayMessage;
String busyMessage;
ImageProvider? avatar;
bool autoAway;
int autoAwayTimeout;
}

View File

@ -16,7 +16,7 @@ part 'local_account.freezed.dart';
// This is the root of the account information tree for VeilidChat
//
@freezed
sealed class LocalAccount with _$LocalAccount {
class LocalAccount with _$LocalAccount {
const factory LocalAccount({
// The super identity key record for the account,
// containing the publicKey in the currentIdentity
@ -40,13 +40,6 @@ sealed class LocalAccount with _$LocalAccount {
required String name,
}) = _LocalAccount;
factory LocalAccount.fromJson(dynamic json) {
try {
return _$LocalAccountFromJson(json as Map<String, dynamic>);
// Need to catch any errors here too
// ignore: avoid_catches_without_on_clauses
} catch (e, st) {
throw Exception('invalid local account: $e\n$st');
}
}
factory LocalAccount.fromJson(dynamic json) =>
_$LocalAccountFromJson(json as Map<String, dynamic>);
}

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,78 +9,45 @@ part of 'local_account.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
LocalAccount _$LocalAccountFromJson(Map<String, dynamic> json) {
return _LocalAccount.fromJson(json);
}
/// @nodoc
mixin _$LocalAccount {
// The super identity key record for the account,
// containing the publicKey in the currentIdentity
SuperIdentity
get superIdentity; // The encrypted currentIdentity secret that goes with
SuperIdentity get superIdentity =>
throw _privateConstructorUsedError; // The encrypted currentIdentity secret that goes with
// the identityPublicKey with appended salt
@Uint8ListJsonConverter()
Uint8List
get identitySecretBytes; // The kind of encryption input used on the account
EncryptionKeyType
get encryptionKeyType; // If account is not hidden, password can be retrieved via
bool
get biometricsEnabled; // Keep account hidden unless account password is entered
Uint8List get identitySecretBytes =>
throw _privateConstructorUsedError; // The kind of encryption input used on the account
EncryptionKeyType get encryptionKeyType =>
throw _privateConstructorUsedError; // If account is not hidden, password can be retrieved via
bool get biometricsEnabled =>
throw _privateConstructorUsedError; // Keep account hidden unless account password is entered
// (tries all hidden accounts with auth method (no biometrics))
bool get hiddenAccount; // Display name for account until it is unlocked
String get name;
bool get hiddenAccount =>
throw _privateConstructorUsedError; // Display name for account until it is unlocked
String get name => throw _privateConstructorUsedError;
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$LocalAccountCopyWith<LocalAccount> get copyWith =>
_$LocalAccountCopyWithImpl<LocalAccount>(
this as LocalAccount, _$identity);
/// Serializes this LocalAccount to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is LocalAccount &&
(identical(other.superIdentity, superIdentity) ||
other.superIdentity == superIdentity) &&
const DeepCollectionEquality()
.equals(other.identitySecretBytes, identitySecretBytes) &&
(identical(other.encryptionKeyType, encryptionKeyType) ||
other.encryptionKeyType == encryptionKeyType) &&
(identical(other.biometricsEnabled, biometricsEnabled) ||
other.biometricsEnabled == biometricsEnabled) &&
(identical(other.hiddenAccount, hiddenAccount) ||
other.hiddenAccount == hiddenAccount) &&
(identical(other.name, name) || other.name == name));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
superIdentity,
const DeepCollectionEquality().hash(identitySecretBytes),
encryptionKeyType,
biometricsEnabled,
hiddenAccount,
name);
@override
String toString() {
return 'LocalAccount(superIdentity: $superIdentity, identitySecretBytes: $identitySecretBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount, name: $name)';
}
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class $LocalAccountCopyWith<$Res> {
abstract class $LocalAccountCopyWith<$Res> {
factory $LocalAccountCopyWith(
LocalAccount value, $Res Function(LocalAccount) _then) =
_$LocalAccountCopyWithImpl;
LocalAccount value, $Res Function(LocalAccount) then) =
_$LocalAccountCopyWithImpl<$Res, LocalAccount>;
@useResult
$Res call(
{SuperIdentity superIdentity,
@ -95,14 +61,15 @@ abstract mixin class $LocalAccountCopyWith<$Res> {
}
/// @nodoc
class _$LocalAccountCopyWithImpl<$Res> implements $LocalAccountCopyWith<$Res> {
_$LocalAccountCopyWithImpl(this._self, this._then);
class _$LocalAccountCopyWithImpl<$Res, $Val extends LocalAccount>
implements $LocalAccountCopyWith<$Res> {
_$LocalAccountCopyWithImpl(this._value, this._then);
final LocalAccount _self;
final $Res Function(LocalAccount) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -113,57 +80,123 @@ class _$LocalAccountCopyWithImpl<$Res> implements $LocalAccountCopyWith<$Res> {
Object? hiddenAccount = null,
Object? name = null,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
superIdentity: null == superIdentity
? _self.superIdentity
? _value.superIdentity
: superIdentity // ignore: cast_nullable_to_non_nullable
as SuperIdentity,
identitySecretBytes: null == identitySecretBytes
? _self.identitySecretBytes
? _value.identitySecretBytes
: identitySecretBytes // ignore: cast_nullable_to_non_nullable
as Uint8List,
encryptionKeyType: null == encryptionKeyType
? _self.encryptionKeyType
? _value.encryptionKeyType
: encryptionKeyType // ignore: cast_nullable_to_non_nullable
as EncryptionKeyType,
biometricsEnabled: null == biometricsEnabled
? _self.biometricsEnabled
? _value.biometricsEnabled
: biometricsEnabled // ignore: cast_nullable_to_non_nullable
as bool,
hiddenAccount: null == hiddenAccount
? _self.hiddenAccount
? _value.hiddenAccount
: hiddenAccount // ignore: cast_nullable_to_non_nullable
as bool,
name: null == name
? _self.name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
));
) as $Val);
}
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SuperIdentityCopyWith<$Res> get superIdentity {
return $SuperIdentityCopyWith<$Res>(_self.superIdentity, (value) {
return _then(_self.copyWith(superIdentity: value));
return $SuperIdentityCopyWith<$Res>(_value.superIdentity, (value) {
return _then(_value.copyWith(superIdentity: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$LocalAccountImplCopyWith<$Res>
implements $LocalAccountCopyWith<$Res> {
factory _$$LocalAccountImplCopyWith(
_$LocalAccountImpl value, $Res Function(_$LocalAccountImpl) then) =
__$$LocalAccountImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{SuperIdentity superIdentity,
@Uint8ListJsonConverter() Uint8List identitySecretBytes,
EncryptionKeyType encryptionKeyType,
bool biometricsEnabled,
bool hiddenAccount,
String name});
@override
$SuperIdentityCopyWith<$Res> get superIdentity;
}
/// @nodoc
class __$$LocalAccountImplCopyWithImpl<$Res>
extends _$LocalAccountCopyWithImpl<$Res, _$LocalAccountImpl>
implements _$$LocalAccountImplCopyWith<$Res> {
__$$LocalAccountImplCopyWithImpl(
_$LocalAccountImpl _value, $Res Function(_$LocalAccountImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? superIdentity = null,
Object? identitySecretBytes = null,
Object? encryptionKeyType = null,
Object? biometricsEnabled = null,
Object? hiddenAccount = null,
Object? name = null,
}) {
return _then(_$LocalAccountImpl(
superIdentity: null == superIdentity
? _value.superIdentity
: superIdentity // ignore: cast_nullable_to_non_nullable
as SuperIdentity,
identitySecretBytes: null == identitySecretBytes
? _value.identitySecretBytes
: identitySecretBytes // ignore: cast_nullable_to_non_nullable
as Uint8List,
encryptionKeyType: null == encryptionKeyType
? _value.encryptionKeyType
: encryptionKeyType // ignore: cast_nullable_to_non_nullable
as EncryptionKeyType,
biometricsEnabled: null == biometricsEnabled
? _value.biometricsEnabled
: biometricsEnabled // ignore: cast_nullable_to_non_nullable
as bool,
hiddenAccount: null == hiddenAccount
? _value.hiddenAccount
: hiddenAccount // ignore: cast_nullable_to_non_nullable
as bool,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _LocalAccount implements LocalAccount {
const _LocalAccount(
class _$LocalAccountImpl implements _LocalAccount {
const _$LocalAccountImpl(
{required this.superIdentity,
@Uint8ListJsonConverter() required this.identitySecretBytes,
required this.encryptionKeyType,
required this.biometricsEnabled,
required this.hiddenAccount,
required this.name});
factory _LocalAccount.fromJson(Map<String, dynamic> json) =>
_$LocalAccountFromJson(json);
factory _$LocalAccountImpl.fromJson(Map<String, dynamic> json) =>
_$$LocalAccountImplFromJson(json);
// The super identity key record for the account,
// containing the publicKey in the currentIdentity
@ -188,26 +221,16 @@ class _LocalAccount implements LocalAccount {
@override
final String name;
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LocalAccountCopyWith<_LocalAccount> get copyWith =>
__$LocalAccountCopyWithImpl<_LocalAccount>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$LocalAccountToJson(
this,
);
String toString() {
return 'LocalAccount(superIdentity: $superIdentity, identitySecretBytes: $identitySecretBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount, name: $name)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _LocalAccount &&
other is _$LocalAccountImpl &&
(identical(other.superIdentity, superIdentity) ||
other.superIdentity == superIdentity) &&
const DeepCollectionEquality()
@ -221,7 +244,7 @@ class _LocalAccount implements LocalAccount {
(identical(other.name, name) || other.name == name));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(
runtimeType,
@ -232,89 +255,50 @@ class _LocalAccount implements LocalAccount {
hiddenAccount,
name);
@override
String toString() {
return 'LocalAccount(superIdentity: $superIdentity, identitySecretBytes: $identitySecretBytes, encryptionKeyType: $encryptionKeyType, biometricsEnabled: $biometricsEnabled, hiddenAccount: $hiddenAccount, name: $name)';
}
}
/// @nodoc
abstract mixin class _$LocalAccountCopyWith<$Res>
implements $LocalAccountCopyWith<$Res> {
factory _$LocalAccountCopyWith(
_LocalAccount value, $Res Function(_LocalAccount) _then) =
__$LocalAccountCopyWithImpl;
@override
@useResult
$Res call(
{SuperIdentity superIdentity,
@Uint8ListJsonConverter() Uint8List identitySecretBytes,
EncryptionKeyType encryptionKeyType,
bool biometricsEnabled,
bool hiddenAccount,
String name});
@override
$SuperIdentityCopyWith<$Res> get superIdentity;
}
/// @nodoc
class __$LocalAccountCopyWithImpl<$Res>
implements _$LocalAccountCopyWith<$Res> {
__$LocalAccountCopyWithImpl(this._self, this._then);
final _LocalAccount _self;
final $Res Function(_LocalAccount) _then;
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? superIdentity = null,
Object? identitySecretBytes = null,
Object? encryptionKeyType = null,
Object? biometricsEnabled = null,
Object? hiddenAccount = null,
Object? name = null,
}) {
return _then(_LocalAccount(
superIdentity: null == superIdentity
? _self.superIdentity
: superIdentity // ignore: cast_nullable_to_non_nullable
as SuperIdentity,
identitySecretBytes: null == identitySecretBytes
? _self.identitySecretBytes
: identitySecretBytes // ignore: cast_nullable_to_non_nullable
as Uint8List,
encryptionKeyType: null == encryptionKeyType
? _self.encryptionKeyType
: encryptionKeyType // ignore: cast_nullable_to_non_nullable
as EncryptionKeyType,
biometricsEnabled: null == biometricsEnabled
? _self.biometricsEnabled
: biometricsEnabled // ignore: cast_nullable_to_non_nullable
as bool,
hiddenAccount: null == hiddenAccount
? _self.hiddenAccount
: hiddenAccount // ignore: cast_nullable_to_non_nullable
as bool,
name: null == name
? _self.name
: name // ignore: cast_nullable_to_non_nullable
as String,
));
}
_$$LocalAccountImplCopyWith<_$LocalAccountImpl> get copyWith =>
__$$LocalAccountImplCopyWithImpl<_$LocalAccountImpl>(this, _$identity);
/// Create a copy of LocalAccount
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SuperIdentityCopyWith<$Res> get superIdentity {
return $SuperIdentityCopyWith<$Res>(_self.superIdentity, (value) {
return _then(_self.copyWith(superIdentity: value));
});
Map<String, dynamic> toJson() {
return _$$LocalAccountImplToJson(
this,
);
}
}
// dart format on
abstract class _LocalAccount implements LocalAccount {
const factory _LocalAccount(
{required final SuperIdentity superIdentity,
@Uint8ListJsonConverter() required final Uint8List identitySecretBytes,
required final EncryptionKeyType encryptionKeyType,
required final bool biometricsEnabled,
required final bool hiddenAccount,
required final String name}) = _$LocalAccountImpl;
factory _LocalAccount.fromJson(Map<String, dynamic> json) =
_$LocalAccountImpl.fromJson;
@override // The super identity key record for the account,
// containing the publicKey in the currentIdentity
SuperIdentity get superIdentity;
@override // The encrypted currentIdentity secret that goes with
// the identityPublicKey with appended salt
@Uint8ListJsonConverter()
Uint8List get identitySecretBytes;
@override // The kind of encryption input used on the account
EncryptionKeyType get encryptionKeyType;
@override // If account is not hidden, password can be retrieved via
bool get biometricsEnabled;
@override // Keep account hidden unless account password is entered
// (tries all hidden accounts with auth method (no biometrics))
bool get hiddenAccount;
@override // Display name for account until it is unlocked
String get name;
@override
@JsonKey(ignore: true)
_$$LocalAccountImplCopyWith<_$LocalAccountImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -6,8 +6,8 @@ part of 'local_account.dart';
// JsonSerializableGenerator
// **************************************************************************
_LocalAccount _$LocalAccountFromJson(Map<String, dynamic> json) =>
_LocalAccount(
_$LocalAccountImpl _$$LocalAccountImplFromJson(Map<String, dynamic> json) =>
_$LocalAccountImpl(
superIdentity: SuperIdentity.fromJson(json['super_identity']),
identitySecretBytes: const Uint8ListJsonConverter()
.fromJson(json['identity_secret_bytes']),
@ -18,7 +18,7 @@ _LocalAccount _$LocalAccountFromJson(Map<String, dynamic> json) =>
name: json['name'] as String,
);
Map<String, dynamic> _$LocalAccountToJson(_LocalAccount instance) =>
Map<String, dynamic> _$$LocalAccountImplToJson(_$LocalAccountImpl instance) =>
<String, dynamic>{
'super_identity': instance.superIdentity.toJson(),
'identity_secret_bytes':

View File

@ -2,7 +2,6 @@ import 'package:async_tools/async_tools.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../../chat/chat.dart';
import '../../../chat_list/chat_list.dart';
@ -15,9 +14,7 @@ import '../../account_manager.dart';
part 'per_account_collection_state.freezed.dart';
@freezed
sealed class PerAccountCollectionState
with _$PerAccountCollectionState
implements ToDebugMap {
class PerAccountCollectionState with _$PerAccountCollectionState {
const factory PerAccountCollectionState({
required AccountInfo accountInfo,
required AsyncValue<AccountRecordState>? avAccountRecordState,
@ -32,27 +29,9 @@ sealed class PerAccountCollectionState
required ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit,
}) = _PerAccountCollectionState;
const PerAccountCollectionState._();
@override
Map<String, dynamic> toDebugMap() => {
'accountInfo': accountInfo,
'avAccountRecordState': avAccountRecordState,
'accountInfoCubit': accountInfoCubit,
'accountRecordCubit': accountRecordCubit,
'contactInvitationListCubit': contactInvitationListCubit,
'contactListCubit': contactListCubit,
'waitingInvitationsBlocMapCubit': waitingInvitationsBlocMapCubit,
'activeChatCubit': activeChatCubit,
'chatListCubit': chatListCubit,
'activeConversationsBlocMapCubit': activeConversationsBlocMapCubit,
'activeSingleContactChatBlocMapCubit':
activeSingleContactChatBlocMapCubit,
};
}
extension PerAccountCollectionStateExt on PerAccountCollectionState {
// Returns if the account is ready and logged in
bool get isReady =>
avAccountRecordState != null &&
avAccountRecordState!.isData &&
@ -66,11 +45,7 @@ extension PerAccountCollectionStateExt on PerAccountCollectionState {
activeConversationsBlocMapCubit != null &&
activeSingleContactChatBlocMapCubit != null;
/// If we have a selected account and it is ready and not locked,
/// this will provide the unlocked account's cubits to the context
Widget provideReady({required Widget child}) {
if (isReady) {
return MultiBlocProvider(providers: [
Widget provide({required Widget child}) => MultiBlocProvider(providers: [
BlocProvider.value(value: accountInfoCubit!),
BlocProvider.value(value: accountRecordCubit!),
BlocProvider.value(value: contactInvitationListCubit!),
@ -81,9 +56,4 @@ extension PerAccountCollectionStateExt on PerAccountCollectionState {
BlocProvider.value(value: activeConversationsBlocMapCubit!),
BlocProvider.value(value: activeSingleContactChatBlocMapCubit!),
], child: child);
} else {
// Otherwise we just provide the child
return child;
}
}
}

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,94 +9,42 @@ part of 'per_account_collection_state.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$PerAccountCollectionState {
AccountInfo get accountInfo;
AsyncValue<AccountRecordState>? get avAccountRecordState;
AccountInfoCubit? get accountInfoCubit;
AccountRecordCubit? get accountRecordCubit;
ContactInvitationListCubit? get contactInvitationListCubit;
ContactListCubit? get contactListCubit;
WaitingInvitationsBlocMapCubit? get waitingInvitationsBlocMapCubit;
ActiveChatCubit? get activeChatCubit;
ChatListCubit? get chatListCubit;
ActiveConversationsBlocMapCubit? get activeConversationsBlocMapCubit;
ActiveSingleContactChatBlocMapCubit? get activeSingleContactChatBlocMapCubit;
AccountInfo get accountInfo => throw _privateConstructorUsedError;
AsyncValue<Account>? get avAccountRecordState =>
throw _privateConstructorUsedError;
AccountInfoCubit? get accountInfoCubit => throw _privateConstructorUsedError;
AccountRecordCubit? get accountRecordCubit =>
throw _privateConstructorUsedError;
ContactInvitationListCubit? get contactInvitationListCubit =>
throw _privateConstructorUsedError;
ContactListCubit? get contactListCubit => throw _privateConstructorUsedError;
WaitingInvitationsBlocMapCubit? get waitingInvitationsBlocMapCubit =>
throw _privateConstructorUsedError;
ActiveChatCubit? get activeChatCubit => throw _privateConstructorUsedError;
ChatListCubit? get chatListCubit => throw _privateConstructorUsedError;
ActiveConversationsBlocMapCubit? get activeConversationsBlocMapCubit =>
throw _privateConstructorUsedError;
ActiveSingleContactChatBlocMapCubit?
get activeSingleContactChatBlocMapCubit =>
throw _privateConstructorUsedError;
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@JsonKey(ignore: true)
$PerAccountCollectionStateCopyWith<PerAccountCollectionState> get copyWith =>
_$PerAccountCollectionStateCopyWithImpl<PerAccountCollectionState>(
this as PerAccountCollectionState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is PerAccountCollectionState &&
(identical(other.accountInfo, accountInfo) ||
other.accountInfo == accountInfo) &&
(identical(other.avAccountRecordState, avAccountRecordState) ||
other.avAccountRecordState == avAccountRecordState) &&
(identical(other.accountInfoCubit, accountInfoCubit) ||
other.accountInfoCubit == accountInfoCubit) &&
(identical(other.accountRecordCubit, accountRecordCubit) ||
other.accountRecordCubit == accountRecordCubit) &&
(identical(other.contactInvitationListCubit,
contactInvitationListCubit) ||
other.contactInvitationListCubit ==
contactInvitationListCubit) &&
(identical(other.contactListCubit, contactListCubit) ||
other.contactListCubit == contactListCubit) &&
(identical(other.waitingInvitationsBlocMapCubit,
waitingInvitationsBlocMapCubit) ||
other.waitingInvitationsBlocMapCubit ==
waitingInvitationsBlocMapCubit) &&
(identical(other.activeChatCubit, activeChatCubit) ||
other.activeChatCubit == activeChatCubit) &&
(identical(other.chatListCubit, chatListCubit) ||
other.chatListCubit == chatListCubit) &&
(identical(other.activeConversationsBlocMapCubit,
activeConversationsBlocMapCubit) ||
other.activeConversationsBlocMapCubit ==
activeConversationsBlocMapCubit) &&
(identical(other.activeSingleContactChatBlocMapCubit,
activeSingleContactChatBlocMapCubit) ||
other.activeSingleContactChatBlocMapCubit ==
activeSingleContactChatBlocMapCubit));
}
@override
int get hashCode => Object.hash(
runtimeType,
accountInfo,
avAccountRecordState,
accountInfoCubit,
accountRecordCubit,
contactInvitationListCubit,
contactListCubit,
waitingInvitationsBlocMapCubit,
activeChatCubit,
chatListCubit,
activeConversationsBlocMapCubit,
activeSingleContactChatBlocMapCubit);
@override
String toString() {
return 'PerAccountCollectionState(accountInfo: $accountInfo, avAccountRecordState: $avAccountRecordState, accountInfoCubit: $accountInfoCubit, accountRecordCubit: $accountRecordCubit, contactInvitationListCubit: $contactInvitationListCubit, contactListCubit: $contactListCubit, waitingInvitationsBlocMapCubit: $waitingInvitationsBlocMapCubit, activeChatCubit: $activeChatCubit, chatListCubit: $chatListCubit, activeConversationsBlocMapCubit: $activeConversationsBlocMapCubit, activeSingleContactChatBlocMapCubit: $activeSingleContactChatBlocMapCubit)';
}
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class $PerAccountCollectionStateCopyWith<$Res> {
abstract class $PerAccountCollectionStateCopyWith<$Res> {
factory $PerAccountCollectionStateCopyWith(PerAccountCollectionState value,
$Res Function(PerAccountCollectionState) _then) =
_$PerAccountCollectionStateCopyWithImpl;
$Res Function(PerAccountCollectionState) then) =
_$PerAccountCollectionStateCopyWithImpl<$Res, PerAccountCollectionState>;
@useResult
$Res call(
{AccountInfo accountInfo,
@ -117,15 +64,16 @@ abstract mixin class $PerAccountCollectionStateCopyWith<$Res> {
}
/// @nodoc
class _$PerAccountCollectionStateCopyWithImpl<$Res>
class _$PerAccountCollectionStateCopyWithImpl<$Res,
$Val extends PerAccountCollectionState>
implements $PerAccountCollectionStateCopyWith<$Res> {
_$PerAccountCollectionStateCopyWithImpl(this._self, this._then);
_$PerAccountCollectionStateCopyWithImpl(this._value, this._then);
final PerAccountCollectionState _self;
final $Res Function(PerAccountCollectionState) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -141,76 +89,177 @@ class _$PerAccountCollectionStateCopyWithImpl<$Res>
Object? activeConversationsBlocMapCubit = freezed,
Object? activeSingleContactChatBlocMapCubit = freezed,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
accountInfo: null == accountInfo
? _self.accountInfo
? _value.accountInfo
: accountInfo // ignore: cast_nullable_to_non_nullable
as AccountInfo,
avAccountRecordState: freezed == avAccountRecordState
? _self.avAccountRecordState!
? _value.avAccountRecordState
: avAccountRecordState // ignore: cast_nullable_to_non_nullable
as AsyncValue<Account>?,
accountInfoCubit: freezed == accountInfoCubit
? _self.accountInfoCubit
? _value.accountInfoCubit
: accountInfoCubit // ignore: cast_nullable_to_non_nullable
as AccountInfoCubit?,
accountRecordCubit: freezed == accountRecordCubit
? _self.accountRecordCubit
? _value.accountRecordCubit
: accountRecordCubit // ignore: cast_nullable_to_non_nullable
as AccountRecordCubit?,
contactInvitationListCubit: freezed == contactInvitationListCubit
? _self.contactInvitationListCubit
? _value.contactInvitationListCubit
: contactInvitationListCubit // ignore: cast_nullable_to_non_nullable
as ContactInvitationListCubit?,
contactListCubit: freezed == contactListCubit
? _self.contactListCubit
? _value.contactListCubit
: contactListCubit // ignore: cast_nullable_to_non_nullable
as ContactListCubit?,
waitingInvitationsBlocMapCubit: freezed == waitingInvitationsBlocMapCubit
? _self.waitingInvitationsBlocMapCubit
? _value.waitingInvitationsBlocMapCubit
: waitingInvitationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as WaitingInvitationsBlocMapCubit?,
activeChatCubit: freezed == activeChatCubit
? _self.activeChatCubit
? _value.activeChatCubit
: activeChatCubit // ignore: cast_nullable_to_non_nullable
as ActiveChatCubit?,
chatListCubit: freezed == chatListCubit
? _self.chatListCubit
? _value.chatListCubit
: chatListCubit // ignore: cast_nullable_to_non_nullable
as ChatListCubit?,
activeConversationsBlocMapCubit: freezed ==
activeConversationsBlocMapCubit
? _self.activeConversationsBlocMapCubit
? _value.activeConversationsBlocMapCubit
: activeConversationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveConversationsBlocMapCubit?,
activeSingleContactChatBlocMapCubit: freezed ==
activeSingleContactChatBlocMapCubit
? _self.activeSingleContactChatBlocMapCubit
? _value.activeSingleContactChatBlocMapCubit
: activeSingleContactChatBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveSingleContactChatBlocMapCubit?,
));
) as $Val);
}
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AsyncValueCopyWith<Account, $Res>? get avAccountRecordState {
if (_self.avAccountRecordState == null) {
if (_value.avAccountRecordState == null) {
return null;
}
return $AsyncValueCopyWith<Account, $Res>(_self.avAccountRecordState!,
return $AsyncValueCopyWith<Account, $Res>(_value.avAccountRecordState!,
(value) {
return _then(_self.copyWith(avAccountRecordState: value));
return _then(_value.copyWith(avAccountRecordState: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$PerAccountCollectionStateImplCopyWith<$Res>
implements $PerAccountCollectionStateCopyWith<$Res> {
factory _$$PerAccountCollectionStateImplCopyWith(
_$PerAccountCollectionStateImpl value,
$Res Function(_$PerAccountCollectionStateImpl) then) =
__$$PerAccountCollectionStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{AccountInfo accountInfo,
AsyncValue<Account>? avAccountRecordState,
AccountInfoCubit? accountInfoCubit,
AccountRecordCubit? accountRecordCubit,
ContactInvitationListCubit? contactInvitationListCubit,
ContactListCubit? contactListCubit,
WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit,
ActiveChatCubit? activeChatCubit,
ChatListCubit? chatListCubit,
ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit,
ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit});
class _PerAccountCollectionState extends PerAccountCollectionState {
const _PerAccountCollectionState(
@override
$AsyncValueCopyWith<Account, $Res>? get avAccountRecordState;
}
/// @nodoc
class __$$PerAccountCollectionStateImplCopyWithImpl<$Res>
extends _$PerAccountCollectionStateCopyWithImpl<$Res,
_$PerAccountCollectionStateImpl>
implements _$$PerAccountCollectionStateImplCopyWith<$Res> {
__$$PerAccountCollectionStateImplCopyWithImpl(
_$PerAccountCollectionStateImpl _value,
$Res Function(_$PerAccountCollectionStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? accountInfo = null,
Object? avAccountRecordState = freezed,
Object? accountInfoCubit = freezed,
Object? accountRecordCubit = freezed,
Object? contactInvitationListCubit = freezed,
Object? contactListCubit = freezed,
Object? waitingInvitationsBlocMapCubit = freezed,
Object? activeChatCubit = freezed,
Object? chatListCubit = freezed,
Object? activeConversationsBlocMapCubit = freezed,
Object? activeSingleContactChatBlocMapCubit = freezed,
}) {
return _then(_$PerAccountCollectionStateImpl(
accountInfo: null == accountInfo
? _value.accountInfo
: accountInfo // ignore: cast_nullable_to_non_nullable
as AccountInfo,
avAccountRecordState: freezed == avAccountRecordState
? _value.avAccountRecordState
: avAccountRecordState // ignore: cast_nullable_to_non_nullable
as AsyncValue<Account>?,
accountInfoCubit: freezed == accountInfoCubit
? _value.accountInfoCubit
: accountInfoCubit // ignore: cast_nullable_to_non_nullable
as AccountInfoCubit?,
accountRecordCubit: freezed == accountRecordCubit
? _value.accountRecordCubit
: accountRecordCubit // ignore: cast_nullable_to_non_nullable
as AccountRecordCubit?,
contactInvitationListCubit: freezed == contactInvitationListCubit
? _value.contactInvitationListCubit
: contactInvitationListCubit // ignore: cast_nullable_to_non_nullable
as ContactInvitationListCubit?,
contactListCubit: freezed == contactListCubit
? _value.contactListCubit
: contactListCubit // ignore: cast_nullable_to_non_nullable
as ContactListCubit?,
waitingInvitationsBlocMapCubit: freezed == waitingInvitationsBlocMapCubit
? _value.waitingInvitationsBlocMapCubit
: waitingInvitationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as WaitingInvitationsBlocMapCubit?,
activeChatCubit: freezed == activeChatCubit
? _value.activeChatCubit
: activeChatCubit // ignore: cast_nullable_to_non_nullable
as ActiveChatCubit?,
chatListCubit: freezed == chatListCubit
? _value.chatListCubit
: chatListCubit // ignore: cast_nullable_to_non_nullable
as ChatListCubit?,
activeConversationsBlocMapCubit: freezed ==
activeConversationsBlocMapCubit
? _value.activeConversationsBlocMapCubit
: activeConversationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveConversationsBlocMapCubit?,
activeSingleContactChatBlocMapCubit: freezed ==
activeSingleContactChatBlocMapCubit
? _value.activeSingleContactChatBlocMapCubit
: activeSingleContactChatBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveSingleContactChatBlocMapCubit?,
));
}
}
/// @nodoc
class _$PerAccountCollectionStateImpl implements _PerAccountCollectionState {
const _$PerAccountCollectionStateImpl(
{required this.accountInfo,
required this.avAccountRecordState,
required this.accountInfoCubit,
@ -221,8 +270,7 @@ class _PerAccountCollectionState extends PerAccountCollectionState {
required this.activeChatCubit,
required this.chatListCubit,
required this.activeConversationsBlocMapCubit,
required this.activeSingleContactChatBlocMapCubit})
: super._();
required this.activeSingleContactChatBlocMapCubit});
@override
final AccountInfo accountInfo;
@ -248,21 +296,16 @@ class _PerAccountCollectionState extends PerAccountCollectionState {
final ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit;
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$PerAccountCollectionStateCopyWith<_PerAccountCollectionState>
get copyWith =>
__$PerAccountCollectionStateCopyWithImpl<_PerAccountCollectionState>(
this, _$identity);
String toString() {
return 'PerAccountCollectionState(accountInfo: $accountInfo, avAccountRecordState: $avAccountRecordState, accountInfoCubit: $accountInfoCubit, accountRecordCubit: $accountRecordCubit, contactInvitationListCubit: $contactInvitationListCubit, contactListCubit: $contactListCubit, waitingInvitationsBlocMapCubit: $waitingInvitationsBlocMapCubit, activeChatCubit: $activeChatCubit, chatListCubit: $chatListCubit, activeConversationsBlocMapCubit: $activeConversationsBlocMapCubit, activeSingleContactChatBlocMapCubit: $activeSingleContactChatBlocMapCubit)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _PerAccountCollectionState &&
other is _$PerAccountCollectionStateImpl &&
(identical(other.accountInfo, accountInfo) ||
other.accountInfo == accountInfo) &&
(identical(other.avAccountRecordState, avAccountRecordState) ||
@ -310,127 +353,56 @@ class _PerAccountCollectionState extends PerAccountCollectionState {
activeConversationsBlocMapCubit,
activeSingleContactChatBlocMapCubit);
@override
String toString() {
return 'PerAccountCollectionState(accountInfo: $accountInfo, avAccountRecordState: $avAccountRecordState, accountInfoCubit: $accountInfoCubit, accountRecordCubit: $accountRecordCubit, contactInvitationListCubit: $contactInvitationListCubit, contactListCubit: $contactListCubit, waitingInvitationsBlocMapCubit: $waitingInvitationsBlocMapCubit, activeChatCubit: $activeChatCubit, chatListCubit: $chatListCubit, activeConversationsBlocMapCubit: $activeConversationsBlocMapCubit, activeSingleContactChatBlocMapCubit: $activeSingleContactChatBlocMapCubit)';
}
}
/// @nodoc
abstract mixin class _$PerAccountCollectionStateCopyWith<$Res>
implements $PerAccountCollectionStateCopyWith<$Res> {
factory _$PerAccountCollectionStateCopyWith(_PerAccountCollectionState value,
$Res Function(_PerAccountCollectionState) _then) =
__$PerAccountCollectionStateCopyWithImpl;
@override
@useResult
$Res call(
{AccountInfo accountInfo,
AsyncValue<Account>? avAccountRecordState,
AccountInfoCubit? accountInfoCubit,
AccountRecordCubit? accountRecordCubit,
ContactInvitationListCubit? contactInvitationListCubit,
ContactListCubit? contactListCubit,
WaitingInvitationsBlocMapCubit? waitingInvitationsBlocMapCubit,
ActiveChatCubit? activeChatCubit,
ChatListCubit? chatListCubit,
ActiveConversationsBlocMapCubit? activeConversationsBlocMapCubit,
ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit});
@override
$AsyncValueCopyWith<Account, $Res>? get avAccountRecordState;
}
/// @nodoc
class __$PerAccountCollectionStateCopyWithImpl<$Res>
implements _$PerAccountCollectionStateCopyWith<$Res> {
__$PerAccountCollectionStateCopyWithImpl(this._self, this._then);
final _PerAccountCollectionState _self;
final $Res Function(_PerAccountCollectionState) _then;
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? accountInfo = null,
Object? avAccountRecordState = freezed,
Object? accountInfoCubit = freezed,
Object? accountRecordCubit = freezed,
Object? contactInvitationListCubit = freezed,
Object? contactListCubit = freezed,
Object? waitingInvitationsBlocMapCubit = freezed,
Object? activeChatCubit = freezed,
Object? chatListCubit = freezed,
Object? activeConversationsBlocMapCubit = freezed,
Object? activeSingleContactChatBlocMapCubit = freezed,
}) {
return _then(_PerAccountCollectionState(
accountInfo: null == accountInfo
? _self.accountInfo
: accountInfo // ignore: cast_nullable_to_non_nullable
as AccountInfo,
avAccountRecordState: freezed == avAccountRecordState
? _self.avAccountRecordState
: avAccountRecordState // ignore: cast_nullable_to_non_nullable
as AsyncValue<Account>?,
accountInfoCubit: freezed == accountInfoCubit
? _self.accountInfoCubit
: accountInfoCubit // ignore: cast_nullable_to_non_nullable
as AccountInfoCubit?,
accountRecordCubit: freezed == accountRecordCubit
? _self.accountRecordCubit
: accountRecordCubit // ignore: cast_nullable_to_non_nullable
as AccountRecordCubit?,
contactInvitationListCubit: freezed == contactInvitationListCubit
? _self.contactInvitationListCubit
: contactInvitationListCubit // ignore: cast_nullable_to_non_nullable
as ContactInvitationListCubit?,
contactListCubit: freezed == contactListCubit
? _self.contactListCubit
: contactListCubit // ignore: cast_nullable_to_non_nullable
as ContactListCubit?,
waitingInvitationsBlocMapCubit: freezed == waitingInvitationsBlocMapCubit
? _self.waitingInvitationsBlocMapCubit
: waitingInvitationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as WaitingInvitationsBlocMapCubit?,
activeChatCubit: freezed == activeChatCubit
? _self.activeChatCubit
: activeChatCubit // ignore: cast_nullable_to_non_nullable
as ActiveChatCubit?,
chatListCubit: freezed == chatListCubit
? _self.chatListCubit
: chatListCubit // ignore: cast_nullable_to_non_nullable
as ChatListCubit?,
activeConversationsBlocMapCubit: freezed ==
activeConversationsBlocMapCubit
? _self.activeConversationsBlocMapCubit
: activeConversationsBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveConversationsBlocMapCubit?,
activeSingleContactChatBlocMapCubit: freezed ==
activeSingleContactChatBlocMapCubit
? _self.activeSingleContactChatBlocMapCubit
: activeSingleContactChatBlocMapCubit // ignore: cast_nullable_to_non_nullable
as ActiveSingleContactChatBlocMapCubit?,
));
}
/// Create a copy of PerAccountCollectionState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AsyncValueCopyWith<Account, $Res>? get avAccountRecordState {
if (_self.avAccountRecordState == null) {
return null;
}
return $AsyncValueCopyWith<Account, $Res>(_self.avAccountRecordState!,
(value) {
return _then(_self.copyWith(avAccountRecordState: value));
});
}
_$$PerAccountCollectionStateImplCopyWith<_$PerAccountCollectionStateImpl>
get copyWith => __$$PerAccountCollectionStateImplCopyWithImpl<
_$PerAccountCollectionStateImpl>(this, _$identity);
}
// dart format on
abstract class _PerAccountCollectionState implements PerAccountCollectionState {
const factory _PerAccountCollectionState(
{required final AccountInfo accountInfo,
required final AsyncValue<Account>? avAccountRecordState,
required final AccountInfoCubit? accountInfoCubit,
required final AccountRecordCubit? accountRecordCubit,
required final ContactInvitationListCubit? contactInvitationListCubit,
required final ContactListCubit? contactListCubit,
required final WaitingInvitationsBlocMapCubit?
waitingInvitationsBlocMapCubit,
required final ActiveChatCubit? activeChatCubit,
required final ChatListCubit? chatListCubit,
required final ActiveConversationsBlocMapCubit?
activeConversationsBlocMapCubit,
required final ActiveSingleContactChatBlocMapCubit?
activeSingleContactChatBlocMapCubit}) =
_$PerAccountCollectionStateImpl;
@override
AccountInfo get accountInfo;
@override
AsyncValue<Account>? get avAccountRecordState;
@override
AccountInfoCubit? get accountInfoCubit;
@override
AccountRecordCubit? get accountRecordCubit;
@override
ContactInvitationListCubit? get contactInvitationListCubit;
@override
ContactListCubit? get contactListCubit;
@override
WaitingInvitationsBlocMapCubit? get waitingInvitationsBlocMapCubit;
@override
ActiveChatCubit? get activeChatCubit;
@override
ChatListCubit? get chatListCubit;
@override
ActiveConversationsBlocMapCubit? get activeConversationsBlocMapCubit;
@override
ActiveSingleContactChatBlocMapCubit? get activeSingleContactChatBlocMapCubit;
@override
@JsonKey(ignore: true)
_$$PerAccountCollectionStateImplCopyWith<_$PerAccountCollectionStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -9,7 +9,7 @@ part 'user_login.g.dart';
// User logins are stored in the user_logins tablestore table
// indexed by the accountSuperIdentityRecordKey
@freezed
sealed class UserLogin with _$UserLogin {
class UserLogin with _$UserLogin {
const factory UserLogin({
// SuperIdentity record key for the user
// used to index the local accounts table
@ -23,13 +23,6 @@ sealed class UserLogin with _$UserLogin {
required Timestamp lastActive,
}) = _UserLogin;
factory UserLogin.fromJson(dynamic json) {
try {
return _$UserLoginFromJson(json as Map<String, dynamic>);
// Need to catch any errors here too
// ignore: avoid_catches_without_on_clauses
} catch (e, st) {
throw Exception('invalid user login: $e\n$st');
}
}
factory UserLogin.fromJson(dynamic json) =>
_$UserLoginFromJson(json as Map<String, dynamic>);
}

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,61 +9,37 @@ part of 'user_login.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
UserLogin _$UserLoginFromJson(Map<String, dynamic> json) {
return _UserLogin.fromJson(json);
}
/// @nodoc
mixin _$UserLogin {
// SuperIdentity record key for the user
// used to index the local accounts table
TypedKey
get superIdentityRecordKey; // The identity secret as unlocked from the local accounts table
TypedSecret
get identitySecret; // The account record key, owner key and secret pulled from the identity
AccountRecordInfo
get accountRecordInfo; // The time this login was most recently used
Timestamp get lastActive;
Typed<FixedEncodedString43> get superIdentityRecordKey =>
throw _privateConstructorUsedError; // The identity secret as unlocked from the local accounts table
Typed<FixedEncodedString43> get identitySecret =>
throw _privateConstructorUsedError; // The account record key, owner key and secret pulled from the identity
AccountRecordInfo get accountRecordInfo =>
throw _privateConstructorUsedError; // The time this login was most recently used
Timestamp get lastActive => throw _privateConstructorUsedError;
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$UserLoginCopyWith<UserLogin> get copyWith =>
_$UserLoginCopyWithImpl<UserLogin>(this as UserLogin, _$identity);
/// Serializes this UserLogin to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is UserLogin &&
(identical(other.superIdentityRecordKey, superIdentityRecordKey) ||
other.superIdentityRecordKey == superIdentityRecordKey) &&
(identical(other.identitySecret, identitySecret) ||
other.identitySecret == identitySecret) &&
(identical(other.accountRecordInfo, accountRecordInfo) ||
other.accountRecordInfo == accountRecordInfo) &&
(identical(other.lastActive, lastActive) ||
other.lastActive == lastActive));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, superIdentityRecordKey,
identitySecret, accountRecordInfo, lastActive);
@override
String toString() {
return 'UserLogin(superIdentityRecordKey: $superIdentityRecordKey, identitySecret: $identitySecret, accountRecordInfo: $accountRecordInfo, lastActive: $lastActive)';
}
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class $UserLoginCopyWith<$Res> {
factory $UserLoginCopyWith(UserLogin value, $Res Function(UserLogin) _then) =
_$UserLoginCopyWithImpl;
abstract class $UserLoginCopyWith<$Res> {
factory $UserLoginCopyWith(UserLogin value, $Res Function(UserLogin) then) =
_$UserLoginCopyWithImpl<$Res, UserLogin>;
@useResult
$Res call(
{Typed<FixedEncodedString43> superIdentityRecordKey,
@ -76,14 +51,15 @@ abstract mixin class $UserLoginCopyWith<$Res> {
}
/// @nodoc
class _$UserLoginCopyWithImpl<$Res> implements $UserLoginCopyWith<$Res> {
_$UserLoginCopyWithImpl(this._self, this._then);
class _$UserLoginCopyWithImpl<$Res, $Val extends UserLogin>
implements $UserLoginCopyWith<$Res> {
_$UserLoginCopyWithImpl(this._value, this._then);
final UserLogin _self;
final $Res Function(UserLogin) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -92,47 +68,101 @@ class _$UserLoginCopyWithImpl<$Res> implements $UserLoginCopyWith<$Res> {
Object? accountRecordInfo = null,
Object? lastActive = null,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
superIdentityRecordKey: null == superIdentityRecordKey
? _self.superIdentityRecordKey!
? _value.superIdentityRecordKey
: superIdentityRecordKey // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
identitySecret: null == identitySecret
? _self.identitySecret!
? _value.identitySecret
: identitySecret // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
accountRecordInfo: null == accountRecordInfo
? _self.accountRecordInfo
? _value.accountRecordInfo
: accountRecordInfo // ignore: cast_nullable_to_non_nullable
as AccountRecordInfo,
lastActive: null == lastActive
? _self.lastActive
? _value.lastActive
: lastActive // ignore: cast_nullable_to_non_nullable
as Timestamp,
));
) as $Val);
}
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AccountRecordInfoCopyWith<$Res> get accountRecordInfo {
return $AccountRecordInfoCopyWith<$Res>(_self.accountRecordInfo, (value) {
return _then(_self.copyWith(accountRecordInfo: value));
return $AccountRecordInfoCopyWith<$Res>(_value.accountRecordInfo, (value) {
return _then(_value.copyWith(accountRecordInfo: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$UserLoginImplCopyWith<$Res>
implements $UserLoginCopyWith<$Res> {
factory _$$UserLoginImplCopyWith(
_$UserLoginImpl value, $Res Function(_$UserLoginImpl) then) =
__$$UserLoginImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{Typed<FixedEncodedString43> superIdentityRecordKey,
Typed<FixedEncodedString43> identitySecret,
AccountRecordInfo accountRecordInfo,
Timestamp lastActive});
@override
$AccountRecordInfoCopyWith<$Res> get accountRecordInfo;
}
/// @nodoc
class __$$UserLoginImplCopyWithImpl<$Res>
extends _$UserLoginCopyWithImpl<$Res, _$UserLoginImpl>
implements _$$UserLoginImplCopyWith<$Res> {
__$$UserLoginImplCopyWithImpl(
_$UserLoginImpl _value, $Res Function(_$UserLoginImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? superIdentityRecordKey = null,
Object? identitySecret = null,
Object? accountRecordInfo = null,
Object? lastActive = null,
}) {
return _then(_$UserLoginImpl(
superIdentityRecordKey: null == superIdentityRecordKey
? _value.superIdentityRecordKey
: superIdentityRecordKey // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
identitySecret: null == identitySecret
? _value.identitySecret
: identitySecret // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
accountRecordInfo: null == accountRecordInfo
? _value.accountRecordInfo
: accountRecordInfo // ignore: cast_nullable_to_non_nullable
as AccountRecordInfo,
lastActive: null == lastActive
? _value.lastActive
: lastActive // ignore: cast_nullable_to_non_nullable
as Timestamp,
));
}
}
/// @nodoc
@JsonSerializable()
class _UserLogin implements UserLogin {
const _UserLogin(
class _$UserLoginImpl implements _UserLogin {
const _$UserLoginImpl(
{required this.superIdentityRecordKey,
required this.identitySecret,
required this.accountRecordInfo,
required this.lastActive});
factory _UserLogin.fromJson(Map<String, dynamic> json) =>
_$UserLoginFromJson(json);
factory _$UserLoginImpl.fromJson(Map<String, dynamic> json) =>
_$$UserLoginImplFromJson(json);
// SuperIdentity record key for the user
// used to index the local accounts table
@ -148,26 +178,16 @@ class _UserLogin implements UserLogin {
@override
final Timestamp lastActive;
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$UserLoginCopyWith<_UserLogin> get copyWith =>
__$UserLoginCopyWithImpl<_UserLogin>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$UserLoginToJson(
this,
);
String toString() {
return 'UserLogin(superIdentityRecordKey: $superIdentityRecordKey, identitySecret: $identitySecret, accountRecordInfo: $accountRecordInfo, lastActive: $lastActive)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _UserLogin &&
other is _$UserLoginImpl &&
(identical(other.superIdentityRecordKey, superIdentityRecordKey) ||
other.superIdentityRecordKey == superIdentityRecordKey) &&
(identical(other.identitySecret, identitySecret) ||
@ -178,81 +198,46 @@ class _UserLogin implements UserLogin {
other.lastActive == lastActive));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(runtimeType, superIdentityRecordKey,
identitySecret, accountRecordInfo, lastActive);
@override
String toString() {
return 'UserLogin(superIdentityRecordKey: $superIdentityRecordKey, identitySecret: $identitySecret, accountRecordInfo: $accountRecordInfo, lastActive: $lastActive)';
}
}
/// @nodoc
abstract mixin class _$UserLoginCopyWith<$Res>
implements $UserLoginCopyWith<$Res> {
factory _$UserLoginCopyWith(
_UserLogin value, $Res Function(_UserLogin) _then) =
__$UserLoginCopyWithImpl;
@override
@useResult
$Res call(
{Typed<FixedEncodedString43> superIdentityRecordKey,
Typed<FixedEncodedString43> identitySecret,
AccountRecordInfo accountRecordInfo,
Timestamp lastActive});
@override
$AccountRecordInfoCopyWith<$Res> get accountRecordInfo;
}
/// @nodoc
class __$UserLoginCopyWithImpl<$Res> implements _$UserLoginCopyWith<$Res> {
__$UserLoginCopyWithImpl(this._self, this._then);
final _UserLogin _self;
final $Res Function(_UserLogin) _then;
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? superIdentityRecordKey = null,
Object? identitySecret = null,
Object? accountRecordInfo = null,
Object? lastActive = null,
}) {
return _then(_UserLogin(
superIdentityRecordKey: null == superIdentityRecordKey
? _self.superIdentityRecordKey
: superIdentityRecordKey // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
identitySecret: null == identitySecret
? _self.identitySecret
: identitySecret // ignore: cast_nullable_to_non_nullable
as Typed<FixedEncodedString43>,
accountRecordInfo: null == accountRecordInfo
? _self.accountRecordInfo
: accountRecordInfo // ignore: cast_nullable_to_non_nullable
as AccountRecordInfo,
lastActive: null == lastActive
? _self.lastActive
: lastActive // ignore: cast_nullable_to_non_nullable
as Timestamp,
));
}
_$$UserLoginImplCopyWith<_$UserLoginImpl> get copyWith =>
__$$UserLoginImplCopyWithImpl<_$UserLoginImpl>(this, _$identity);
/// Create a copy of UserLogin
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AccountRecordInfoCopyWith<$Res> get accountRecordInfo {
return $AccountRecordInfoCopyWith<$Res>(_self.accountRecordInfo, (value) {
return _then(_self.copyWith(accountRecordInfo: value));
});
Map<String, dynamic> toJson() {
return _$$UserLoginImplToJson(
this,
);
}
}
// dart format on
abstract class _UserLogin implements UserLogin {
const factory _UserLogin(
{required final Typed<FixedEncodedString43> superIdentityRecordKey,
required final Typed<FixedEncodedString43> identitySecret,
required final AccountRecordInfo accountRecordInfo,
required final Timestamp lastActive}) = _$UserLoginImpl;
factory _UserLogin.fromJson(Map<String, dynamic> json) =
_$UserLoginImpl.fromJson;
@override // SuperIdentity record key for the user
// used to index the local accounts table
Typed<FixedEncodedString43> get superIdentityRecordKey;
@override // The identity secret as unlocked from the local accounts table
Typed<FixedEncodedString43> get identitySecret;
@override // The account record key, owner key and secret pulled from the identity
AccountRecordInfo get accountRecordInfo;
@override // The time this login was most recently used
Timestamp get lastActive;
@override
@JsonKey(ignore: true)
_$$UserLoginImplCopyWith<_$UserLoginImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -6,7 +6,8 @@ part of 'user_login.dart';
// JsonSerializableGenerator
// **************************************************************************
_UserLogin _$UserLoginFromJson(Map<String, dynamic> json) => _UserLogin(
_$UserLoginImpl _$$UserLoginImplFromJson(Map<String, dynamic> json) =>
_$UserLoginImpl(
superIdentityRecordKey: Typed<FixedEncodedString43>.fromJson(
json['super_identity_record_key']),
identitySecret:
@ -16,7 +17,7 @@ _UserLogin _$UserLoginFromJson(Map<String, dynamic> json) => _UserLogin(
lastActive: Timestamp.fromJson(json['last_active']),
);
Map<String, dynamic> _$UserLoginToJson(_UserLogin instance) =>
Map<String, dynamic> _$$UserLoginImplToJson(_$UserLoginImpl instance) =>
<String, dynamic>{
'super_identity_record_key': instance.superIdentityRecordKey.toJson(),
'identity_secret': instance.identitySecret.toJson(),

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -11,18 +10,17 @@ import 'package:veilid_support/veilid_support.dart';
import '../../layout/default_app_bar.dart';
import '../../notifications/notifications.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import '../../tools/tools.dart';
import '../../veilid_processor/veilid_processor.dart';
import '../account_manager.dart';
import 'edit_profile_form.dart';
const _kDoBackArrow = 'doBackArrow';
class EditAccountPage extends StatefulWidget {
const EditAccountPage(
{required this.superIdentityRecordKey,
required this.initialValue,
required this.existingAccount,
required this.accountRecord,
super.key});
@ -30,7 +28,7 @@ class EditAccountPage extends StatefulWidget {
State createState() => _EditAccountPageState();
final TypedKey superIdentityRecordKey;
final AccountSpec initialValue;
final proto.Account existingAccount;
final OwnedDHTRecordPointer accountRecord;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@ -38,7 +36,8 @@ class EditAccountPage extends StatefulWidget {
properties
..add(DiagnosticsProperty<TypedKey>(
'superIdentityRecordKey', superIdentityRecordKey))
..add(DiagnosticsProperty<AccountSpec>('initialValue', initialValue))
..add(DiagnosticsProperty<proto.Account>(
'existingAccount', existingAccount))
..add(DiagnosticsProperty<OwnedDHTRecordPointer>(
'accountRecord', accountRecord));
}
@ -50,31 +49,47 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
titleBarStyle: TitleBarStyle.normal,
orientationCapability: OrientationCapability.portraitOnly);
EditProfileForm _editAccountForm(BuildContext context) => EditProfileForm(
Widget _editAccountForm(BuildContext context,
{required Future<void> Function(AccountSpec) onUpdate}) =>
EditProfileForm(
header: translate('edit_account_page.header'),
instructions: translate('edit_account_page.instructions'),
submitText: translate('button.update'),
submitText: translate('edit_account_page.update'),
submitDisabledText: translate('button.waiting_for_network'),
onSubmit: _onSubmit,
onModifiedState: _onModifiedState,
initialValue: widget.initialValue,
onUpdate: onUpdate,
initialValueCallback: (key) => switch (key) {
EditProfileForm.formFieldName => widget.existingAccount.profile.name,
EditProfileForm.formFieldPronouns =>
widget.existingAccount.profile.pronouns,
EditProfileForm.formFieldAbout =>
widget.existingAccount.profile.about,
EditProfileForm.formFieldAvailability =>
widget.existingAccount.profile.availability,
EditProfileForm.formFieldFreeMessage =>
widget.existingAccount.freeMessage,
EditProfileForm.formFieldAwayMessage =>
widget.existingAccount.awayMessage,
EditProfileForm.formFieldBusyMessage =>
widget.existingAccount.busyMessage,
EditProfileForm.formFieldAvatar =>
widget.existingAccount.profile.avatar,
EditProfileForm.formFieldAutoAway =>
widget.existingAccount.autodetectAway,
EditProfileForm.formFieldAutoAwayTimeout =>
widget.existingAccount.autoAwayTimeoutMin.toString(),
String() => throw UnimplementedError(),
},
);
Future<void> _onRemoveAccount() async {
// dismiss the keyboard by unfocusing the textfield
FocusScope.of(context).unfocus();
await asyncSleep(const Duration(milliseconds: 250));
if (!mounted) {
return;
}
final confirmed = await StyledDialog.show<bool>(
context: context,
title: translate('edit_account_page.remove_account_confirm'),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Text(translate('edit_account_page.remove_account_confirm_message'))
.paddingLTRB(24, 24, 24, 0),
Text(translate('confirmation.are_you_sure')).paddingAll(8),
Text(translate('edit_account_page.confirm_are_you_sure'))
.paddingAll(8),
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
ElevatedButton(
onPressed: () {
@ -94,7 +109,10 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
]))
]).paddingAll(24)
]));
if (confirmed != null && confirmed) {
if (confirmed != null && confirmed && mounted) {
// dismiss the keyboard by unfocusing the textfield
FocusScope.of(context).unfocus();
try {
setState(() {
_isInAsyncCall = true;
@ -109,9 +127,9 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
.info(text: translate('edit_account_page.account_removed'));
GoRouterHelper(context).pop();
} else {
context.read<NotificationsCubit>().error(
title: translate('edit_account_page.failed_to_remove_title'),
text: translate('edit_account_page.try_again_network'));
context
.read<NotificationsCubit>()
.error(text: translate('edit_account_page.failed_to_remove'));
}
}
} finally {
@ -129,13 +147,6 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
}
Future<void> _onDestroyAccount() async {
// dismiss the keyboard by unfocusing the textfield
FocusScope.of(context).unfocus();
await asyncSleep(const Duration(milliseconds: 250));
if (!mounted) {
return;
}
final confirmed = await StyledDialog.show<bool>(
context: context,
title: translate('edit_account_page.destroy_account_confirm'),
@ -145,7 +156,8 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
Text(translate(
'edit_account_page.destroy_account_confirm_message_details'))
.paddingLTRB(24, 24, 24, 0),
Text(translate('confirmation.are_you_sure')).paddingAll(8),
Text(translate('edit_account_page.confirm_are_you_sure'))
.paddingAll(8),
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
ElevatedButton(
onPressed: () {
@ -165,7 +177,10 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
]))
]).paddingAll(24)
]));
if (confirmed != null && confirmed) {
if (confirmed != null && confirmed && mounted) {
// dismiss the keyboard by unfocusing the textfield
FocusScope.of(context).unfocus();
try {
setState(() {
_isInAsyncCall = true;
@ -181,8 +196,7 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
GoRouterHelper(context).pop();
} else {
context.read<NotificationsCubit>().error(
title: translate('edit_account_page.failed_to_destroy_title'),
text: translate('edit_account_page.try_again_network'));
text: translate('edit_account_page.failed_to_destroy'));
}
}
} finally {
@ -199,49 +213,24 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
}
}
void _onModifiedState(bool isModified) {
setState(() {
_isModified = isModified;
});
}
Future<bool> _onSubmit(AccountSpec accountSpec) async {
try {
setState(() {
_isInAsyncCall = true;
});
try {
// Look up account cubit for this specific account
final perAccountCollectionBlocMapCubit =
context.read<PerAccountCollectionBlocMapCubit>();
final accountRecordCubit = await perAccountCollectionBlocMapCubit
.operate(widget.superIdentityRecordKey,
closure: (c) async => c.accountRecordCubit);
if (accountRecordCubit == null) {
return false;
}
// Update account profile DHT record
// This triggers ConversationCubits to update
accountRecordCubit.updateAccount(accountSpec, () async {
// Update local account profile
await AccountRepository.instance
.updateLocalAccount(widget.superIdentityRecordKey, accountSpec);
});
return true;
} finally {
setState(() {
_isInAsyncCall = false;
});
}
} on Exception catch (e, st) {
if (mounted) {
await showErrorStacktraceModal(
context: context, error: e, stackTrace: st);
}
Future<void> _onUpdate(AccountSpec accountSpec) async {
// Look up account cubit for this specific account
final perAccountCollectionBlocMapCubit =
context.read<PerAccountCollectionBlocMapCubit>();
final accountRecordCubit = await perAccountCollectionBlocMapCubit.operate(
widget.superIdentityRecordKey,
closure: (c) async => c.accountRecordCubit);
if (accountRecordCubit == null) {
return;
}
return false;
// Update account profile DHT record
// This triggers ConversationCubits to update
accountRecordCubit.updateAccount(accountSpec, () async {
// Update local account profile
await AccountRepository.instance
.updateLocalAccount(widget.superIdentityRecordKey, accountSpec);
});
}
@override
@ -256,23 +245,9 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
? IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
singleFuture((this, _kDoBackArrow), () async {
if (_isModified) {
final ok = await showConfirmModal(
context: context,
title:
translate('confirmation.discard_changes'),
text: translate(
'confirmation.are_you_sure_discard'));
if (!ok) {
return;
}
}
if (context.mounted) {
Navigator.pop(context);
}
});
})
Navigator.pop(context);
},
)
: null,
actions: [
const SignalStrengthMeterWidget(),
@ -285,7 +260,10 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
]),
body: SingleChildScrollView(
child: Column(children: [
_editAccountForm(context).paddingLTRB(0, 0, 0, 32),
_editAccountForm(
context,
onUpdate: _onUpdate,
).paddingLTRB(0, 0, 0, 32),
OptionBox(
instructions:
translate('edit_account_page.remove_account_description'),
@ -307,5 +285,4 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
////////////////////////////////////////////////////////////////////////////
bool _isInAsyncCall = false;
bool _isModified = false;
}

View File

@ -13,7 +13,7 @@ import '../../theme/theme.dart';
import '../../veilid_processor/veilid_processor.dart';
import '../models/models.dart';
const _kDoSubmitEditProfile = 'doSubmitEditProfile';
const _kDoUpdateSubmit = 'doUpdateSubmit';
class EditProfileForm extends StatefulWidget {
const EditProfileForm({
@ -21,9 +21,9 @@ class EditProfileForm extends StatefulWidget {
required this.instructions,
required this.submitText,
required this.submitDisabledText,
required this.initialValue,
required this.onSubmit,
this.onModifiedState,
required this.initialValueCallback,
this.onUpdate,
this.onSubmit,
super.key,
});
@ -32,11 +32,11 @@ class EditProfileForm extends StatefulWidget {
final String header;
final String instructions;
final Future<bool> Function(AccountSpec) onSubmit;
final void Function(bool)? onModifiedState;
final Future<void> Function(AccountSpec)? onUpdate;
final Future<void> Function(AccountSpec)? onSubmit;
final String submitText;
final String submitDisabledText;
final AccountSpec initialValue;
final Object Function(String key) initialValueCallback;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@ -44,13 +44,14 @@ class EditProfileForm extends StatefulWidget {
properties
..add(StringProperty('header', header))
..add(StringProperty('instructions', instructions))
..add(ObjectFlagProperty<Future<void> Function(AccountSpec)?>.has(
'onUpdate', onUpdate))
..add(StringProperty('submitText', submitText))
..add(StringProperty('submitDisabledText', submitDisabledText))
..add(ObjectFlagProperty<Future<bool> Function(AccountSpec)>.has(
'onSubmit', onSubmit))
..add(ObjectFlagProperty<void Function(bool p1)?>.has(
'onModifiedState', onModifiedState))
..add(DiagnosticsProperty<AccountSpec>('initialValue', initialValue));
..add(ObjectFlagProperty<Object Function(String key)?>.has(
'initialValueCallback', initialValueCallback))
..add(ObjectFlagProperty<Future<void> Function(AccountSpec)?>.has(
'onSubmit', onSubmit));
}
static const String formFieldName = 'name';
@ -70,22 +71,21 @@ class _EditProfileFormState extends State<EditProfileForm> {
@override
void initState() {
_savedValue = widget.initialValue;
_currentValueName = widget.initialValue.name;
_currentValueAutoAway = widget.initialValue.autoAway;
_autoAwayEnabled =
widget.initialValueCallback(EditProfileForm.formFieldAutoAway) as bool;
super.initState();
}
FormBuilderDropdown<proto.Availability> _availabilityDropDown(
BuildContext context) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final initialValueX =
widget.initialValueCallback(EditProfileForm.formFieldAvailability)
as proto.Availability;
final initialValue =
_savedValue.availability == proto.Availability.AVAILABILITY_UNSPECIFIED
initialValueX == proto.Availability.AVAILABILITY_UNSPECIFIED
? proto.Availability.AVAILABILITY_FREE
: _savedValue.availability;
: initialValueX;
final availabilities = [
proto.Availability.AVAILABILITY_FREE,
@ -105,8 +105,7 @@ class _EditProfileFormState extends State<EditProfileForm> {
.map((x) => DropdownMenuItem<proto.Availability>(
value: x,
child: Row(mainAxisSize: MainAxisSize.min, children: [
AvailabilityWidget.availabilityIcon(
x, scale.primaryScale.appText),
AvailabilityWidget.availabilityIcon(x),
Text(x == proto.Availability.AVAILABILITY_OFFLINE
? translate('availability.always_show_offline')
: AvailabilityWidget.availabilityName(x))
@ -135,12 +134,6 @@ class _EditProfileFormState extends State<EditProfileForm> {
.fields[EditProfileForm.formFieldAwayMessage]!.value as String;
final busyMessage = _formKey.currentState!
.fields[EditProfileForm.formFieldBusyMessage]!.value as String;
const proto.DataReference? avatar = null;
// final avatar = _formKey.currentState!
// .fields[EditProfileForm.formFieldAvatar]!.value
//as proto.DataReference?;
final autoAway = _formKey
.currentState!.fields[EditProfileForm.formFieldAutoAway]!.value as bool;
final autoAwayTimeoutString = _formKey.currentState!
@ -156,21 +149,11 @@ class _EditProfileFormState extends State<EditProfileForm> {
freeMessage: freeMessage,
awayMessage: awayMessage,
busyMessage: busyMessage,
avatar: avatar,
avatar: null,
autoAway: autoAway,
autoAwayTimeout: autoAwayTimeout);
}
// Check if everything is the same and update state
void _onChanged() {
final currentValue = _makeAccountSpec();
_isModified = currentValue != _savedValue;
final onModifiedState = widget.onModifiedState;
if (onModifiedState != null) {
onModifiedState(_isModified);
}
}
Widget _editProfileForm(
BuildContext context,
) {
@ -189,34 +172,24 @@ class _EditProfileFormState extends State<EditProfileForm> {
return FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: _onChanged,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
spacing: 8,
children: [
Row(children: [
const Spacer(),
AvatarWidget(
name: _currentValueName,
size: 128,
borderColor: border,
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16),
const Spacer()
]),
AvatarWidget(
name: _formKey.currentState?.value[EditProfileForm.formFieldName]
as String? ??
'?',
size: 128,
borderColor: border,
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16),
FormBuilderTextField(
autofocus: true,
name: EditProfileForm.formFieldName,
initialValue: _savedValue.name,
onChanged: (x) {
setState(() {
_currentValueName = x ?? '';
});
},
initialValue: widget
.initialValueCallback(EditProfileForm.formFieldName) as String,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: translate('account.form_name'),
@ -227,20 +200,23 @@ class _EditProfileFormState extends State<EditProfileForm> {
FormBuilderValidators.required(),
]),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldPronouns,
initialValue: _savedValue.pronouns,
initialValue:
widget.initialValueCallback(EditProfileForm.formFieldPronouns)
as String,
maxLength: 64,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: translate('account.form_pronouns'),
hintText: translate('account.empty_pronouns')),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldAbout,
initialValue: _savedValue.about,
initialValue: widget
.initialValueCallback(EditProfileForm.formFieldAbout) as String,
maxLength: 1024,
maxLines: 8,
minLines: 1,
@ -249,66 +225,74 @@ class _EditProfileFormState extends State<EditProfileForm> {
labelText: translate('account.form_about'),
hintText: translate('account.empty_about')),
textInputAction: TextInputAction.newline,
),
_availabilityDropDown(context).paddingLTRB(0, 0, 0, 16),
).onFocusChange(_onFocusChange),
_availabilityDropDown(context)
.paddingLTRB(0, 0, 0, 16)
.onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldFreeMessage,
initialValue: _savedValue.freeMessage,
initialValue: widget.initialValueCallback(
EditProfileForm.formFieldFreeMessage) as String,
maxLength: 128,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: translate('account.form_free_message'),
hintText: translate('account.empty_free_message')),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldAwayMessage,
initialValue: _savedValue.awayMessage,
initialValue: widget.initialValueCallback(
EditProfileForm.formFieldAwayMessage) as String,
maxLength: 128,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: translate('account.form_away_message'),
hintText: translate('account.empty_away_message')),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldBusyMessage,
initialValue: _savedValue.busyMessage,
initialValue: widget.initialValueCallback(
EditProfileForm.formFieldBusyMessage) as String,
maxLength: 128,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
labelText: translate('account.form_busy_message'),
hintText: translate('account.empty_busy_message')),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
FormBuilderCheckbox(
name: EditProfileForm.formFieldAutoAway,
initialValue: _savedValue.autoAway,
initialValue:
widget.initialValueCallback(EditProfileForm.formFieldAutoAway)
as bool,
side: BorderSide(color: scale.primaryScale.border, width: 2),
title: Text(translate('account.form_auto_away'),
style: textTheme.labelMedium),
onChanged: (v) {
setState(() {
_currentValueAutoAway = v ?? false;
_autoAwayEnabled = v ?? false;
});
},
).paddingLTRB(0, 0, 0, 16),
).onFocusChange(_onFocusChange),
FormBuilderTextField(
name: EditProfileForm.formFieldAutoAwayTimeout,
enabled: _currentValueAutoAway,
initialValue: _savedValue.autoAwayTimeout.toString(),
enabled: _autoAwayEnabled,
initialValue: widget.initialValueCallback(
EditProfileForm.formFieldAutoAwayTimeout) as String,
decoration: InputDecoration(
labelText: translate('account.form_auto_away_timeout'),
),
validator: FormBuilderValidators.positiveNumber(),
textInputAction: TextInputAction.next,
),
).onFocusChange(_onFocusChange),
Row(children: [
const Spacer(),
Text(widget.instructions).toCenter().flexible(flex: 6),
const Spacer(),
]).paddingSymmetric(vertical: 16),
Row(children: [
const Spacer(),
]).paddingSymmetric(vertical: 4),
if (widget.onSubmit != null)
Builder(builder: (context) {
final networkReady = context
.watch<ConnectionStateCubit>()
@ -319,11 +303,9 @@ class _EditProfileFormState extends State<EditProfileForm> {
false;
return ElevatedButton(
onPressed: (networkReady && _isModified) ? _doSubmit : null,
onPressed: networkReady ? _doSubmit : null,
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(networkReady ? Icons.check : Icons.hourglass_empty,
size: 16)
.paddingLTRB(0, 0, 4, 0),
const Icon(Icons.check, size: 16).paddingLTRB(0, 0, 4, 0),
Text(networkReady
? widget.submitText
: widget.submitDisabledText)
@ -331,24 +313,36 @@ class _EditProfileFormState extends State<EditProfileForm> {
]),
);
}),
const Spacer()
])
],
),
);
}
void _onFocusChange(bool focused) {
if (!focused) {
_doUpdate();
}
}
void _doUpdate() {
final onUpdate = widget.onUpdate;
if (onUpdate != null) {
singleFuture((this, _kDoUpdateSubmit), () async {
if (_formKey.currentState?.saveAndValidate() ?? false) {
final aus = _makeAccountSpec();
await onUpdate(aus);
}
});
}
}
void _doSubmit() {
final onSubmit = widget.onSubmit;
if (_formKey.currentState?.saveAndValidate() ?? false) {
singleFuture((this, _kDoSubmitEditProfile), () async {
final updatedAccountSpec = _makeAccountSpec();
final saved = await onSubmit(updatedAccountSpec);
if (saved) {
setState(() {
_savedValue = updatedAccountSpec;
});
_onChanged();
if (onSubmit != null) {
singleFuture((this, _kDoUpdateSubmit), () async {
if (_formKey.currentState?.saveAndValidate() ?? false) {
final aus = _makeAccountSpec();
await onSubmit(aus);
}
});
}
@ -360,8 +354,5 @@ class _EditProfileFormState extends State<EditProfileForm> {
);
///////////////////////////////////////////////////////////////////////////
late AccountSpec _savedValue;
late bool _currentValueAutoAway;
late String _currentValueName;
bool _isModified = false;
late bool _autoAwayEnabled;
}

View File

@ -8,6 +8,7 @@ import 'package:go_router/go_router.dart';
import '../../layout/default_app_bar.dart';
import '../../notifications/cubits/notifications_cubit.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import '../../tools/tools.dart';
import '../../veilid_processor/veilid_processor.dart';
@ -27,6 +28,33 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
titleBarStyle: TitleBarStyle.normal,
orientationCapability: OrientationCapability.portraitOnly);
Object _defaultAccountValues(String key) {
switch (key) {
case EditProfileForm.formFieldName:
return '';
case EditProfileForm.formFieldPronouns:
return '';
case EditProfileForm.formFieldAbout:
return '';
case EditProfileForm.formFieldAvailability:
return proto.Availability.AVAILABILITY_FREE;
case EditProfileForm.formFieldFreeMessage:
return '';
case EditProfileForm.formFieldAwayMessage:
return '';
case EditProfileForm.formFieldBusyMessage:
return '';
// case EditProfileForm.formFieldAvatar:
// return null;
case EditProfileForm.formFieldAutoAway:
return false;
case EditProfileForm.formFieldAutoAwayTimeout:
return '15';
default:
throw StateError('missing form element');
}
}
Widget _newAccountForm(
BuildContext context,
) =>
@ -35,10 +63,10 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
instructions: translate('new_account_page.instructions'),
submitText: translate('new_account_page.create'),
submitDisabledText: translate('button.waiting_for_network'),
initialValue: const AccountSpec.empty(),
initialValueCallback: _defaultAccountValues,
onSubmit: _onSubmit);
Future<bool> _onSubmit(AccountSpec accountSpec) async {
Future<void> _onSubmit(AccountSpec accountSpec) async {
// dismiss the keyboard by unfocusing the textfield
FocusScope.of(context).unfocus();
@ -60,18 +88,13 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
context.read<NotificationsCubit>().error(
text: translate('new_account_page.network_is_offline'),
title: translate('new_account_page.error'));
return false;
return;
}
final isFirstAccount =
AccountRepository.instance.getLocalAccounts().isEmpty;
final writableSuperIdentity = await AccountRepository.instance
.createWithNewSuperIdentity(accountSpec);
GoRouterHelper(context).pushReplacement('/new_account/recovery_key',
extra: [writableSuperIdentity, accountSpec.name, isFirstAccount]);
return true;
extra: [writableSuperIdentity, accountSpec.name]);
} finally {
if (mounted) {
setState(() {
@ -85,7 +108,6 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
context: context, error: e, stackTrace: st);
}
}
return false;
}
@override
@ -95,15 +117,11 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
return StyledScaffold(
appBar: DefaultAppBar(
title: Text(translate('new_account_page.titlebar')),
leading: GoRouterHelper(context).canPop()
leading: Navigator.canPop(context)
? IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (GoRouterHelper(context).canPop()) {
GoRouterHelper(context).pop();
} else {
GoRouterHelper(context).go('/');
}
Navigator.pop(context);
},
)
: null,
@ -117,10 +135,9 @@ class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
})
]),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: _newAccountForm(
context,
)).paddingAll(2),
context,
)).paddingSymmetric(horizontal: 24, vertical: 8),
).withModalHUD(context, displayModalHUD);
}

View File

@ -43,7 +43,7 @@ class ProfileWidget extends StatelessWidget {
: scale.primaryScale.borderText,
width: 2),
borderRadius: BorderRadius.all(
Radius.circular(8 * scaleConfig.borderRadiusScale))),
Radius.circular(12 * scaleConfig.borderRadiusScale))),
),
child: Row(children: [
const Spacer(),
@ -54,7 +54,7 @@ class ProfileWidget extends StatelessWidget {
? scale.primaryScale.border
: scale.primaryScale.borderText),
textAlign: TextAlign.left,
).paddingAll(8),
).paddingAll(12),
if (_profile.pronouns.isNotEmpty && _showPronouns)
Text('(${_profile.pronouns})',
textAlign: TextAlign.right,
@ -62,7 +62,7 @@ class ProfileWidget extends StatelessWidget {
color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.primary))
.paddingAll(8),
.paddingAll(12),
const Spacer()
]),
);

View File

@ -1,11 +1,11 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:go_router/go_router.dart';
@ -25,18 +25,15 @@ class ShowRecoveryKeyPage extends StatefulWidget {
const ShowRecoveryKeyPage(
{required WritableSuperIdentity writableSuperIdentity,
required String name,
required bool isFirstAccount,
super.key})
: _writableSuperIdentity = writableSuperIdentity,
_name = name,
_isFirstAccount = isFirstAccount;
_name = name;
@override
State<ShowRecoveryKeyPage> createState() => _ShowRecoveryKeyPageState();
final WritableSuperIdentity _writableSuperIdentity;
final String _name;
final bool _isFirstAccount;
}
class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
@ -64,7 +61,7 @@ class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
_isInAsyncCall = false;
});
if (!kIsWeb && Platform.isLinux) {
if (Platform.isLinux) {
// Share plus doesn't do Linux yet
await FileSaver.instance.saveFile(name: 'recovery_key.png', bytes: bytes);
} else {
@ -251,13 +248,9 @@ class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
child: ElevatedButton(
onPressed: () {
if (context.mounted) {
if (widget._isFirstAccount) {
GoRouterHelper(context).go('/');
} else {
GoRouterHelper(context).canPop()
? GoRouterHelper(context).pop()
: GoRouterHelper(context).go('/');
}
Navigator.canPop(context)
? GoRouterHelper(context).pop()
: GoRouterHelper(context).go('/');
}
},
child: Text(translate('button.finish')).paddingAll(8))

View File

@ -1,12 +1,15 @@
import 'package:animated_theme_switcher/animated_theme_switcher.dart';
import 'package:async_tools/async_tools.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart';
import 'account_manager/account_manager.dart';
import 'init.dart';
@ -16,8 +19,17 @@ import 'router/router.dart';
import 'settings/settings.dart';
import 'theme/theme.dart';
import 'tick.dart';
import 'tools/loggy.dart';
import 'veilid_processor/veilid_processor.dart';
class ReloadThemeIntent extends Intent {
const ReloadThemeIntent();
}
class AttachDetachIntent extends Intent {
const AttachDetachIntent();
}
class ScrollBehaviorModified extends ScrollBehavior {
const ScrollBehaviorModified();
@override
@ -35,92 +47,53 @@ class VeilidChatApp extends StatelessWidget {
final ThemeData initialThemeData;
Widget appBuilder(
BuildContext context, LocalizationDelegate localizationDelegate) =>
ThemeProvider(
initTheme: initialThemeData,
builder: (context, theme) => LocalizationProvider(
state: LocalizationProvider.of(context).state,
child: MultiBlocProvider(
providers: [
BlocProvider<PreferencesCubit>(
create: (context) =>
PreferencesCubit(PreferencesRepository.instance),
),
BlocProvider<NotificationsCubit>(
create: (context) => NotificationsCubit(
const NotificationsState(queue: IList.empty()))),
BlocProvider<ConnectionStateCubit>(
create: (context) =>
ConnectionStateCubit(ProcessorRepository.instance)),
BlocProvider<RouterCubit>(
create: (context) => RouterCubit(AccountRepository.instance),
),
BlocProvider<LocalAccountsCubit>(
create: (context) =>
LocalAccountsCubit(AccountRepository.instance),
),
BlocProvider<UserLoginsCubit>(
create: (context) =>
UserLoginsCubit(AccountRepository.instance),
),
BlocProvider<ActiveLocalAccountCubit>(
create: (context) =>
ActiveLocalAccountCubit(AccountRepository.instance),
),
BlocProvider<PerAccountCollectionBlocMapCubit>(
create: (context) => PerAccountCollectionBlocMapCubit(
accountRepository: AccountRepository.instance,
locator: context.read)),
],
child: BackgroundTicker(child: Builder(builder: (context) {
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
void _reloadTheme(BuildContext context) {
log.info('Reloading theme');
final theme =
PreferencesRepository.instance.value.themePreference.themeData();
ThemeSwitcher.of(context).changeTheme(theme: theme);
final gradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: scaleConfig.preferBorders &&
theme.brightness == Brightness.light
? [
scale.grayScale.hoverElementBackground,
scale.grayScale.subtleBackground,
]
: [
scale.primaryScale.hoverElementBackground,
scale.primaryScale.subtleBackground,
]);
// Hack to reload translations
final localizationDelegate = LocalizedApp.of(context).delegate;
singleFuture(this, () async {
await LocalizationDelegate.create(
fallbackLocale: localizationDelegate.fallbackLocale.toString(),
supportedLocales: localizationDelegate.supportedLocales
.map((x) => x.toString())
.toList());
});
}
final wallpaper = PreferencesRepository
.instance.value.themePreference
.wallpaper();
void _attachDetach(BuildContext context) {
singleFuture(this, () async {
if (ProcessorRepository.instance.processorConnectionState.isAttached) {
log.info('Detaching');
await Veilid.instance.detach();
} else if (ProcessorRepository
.instance.processorConnectionState.isDetached) {
log.info('Attaching');
await Veilid.instance.attach();
}
});
}
return Stack(
fit: StackFit.expand,
alignment: Alignment.center,
children: [
wallpaper ??
DecoratedBox(
decoration: BoxDecoration(gradient: gradient)),
MaterialApp.router(
scrollBehavior: const ScrollBehaviorModified(),
debugShowCheckedModeBanner: false,
routerConfig: context.read<RouterCubit>().router(),
title: translate('app.title'),
theme: theme,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
FormBuilderLocalizations.delegate,
localizationDelegate
],
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
)
]);
})),
)),
);
Widget _buildShortcuts({required Widget Function(BuildContext) builder}) =>
ThemeSwitcher(
builder: (context) => Shortcuts(
shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(
LogicalKeyboardKey.alt, LogicalKeyboardKey.keyR):
const ReloadThemeIntent(),
LogicalKeySet(
LogicalKeyboardKey.alt, LogicalKeyboardKey.keyD):
const AttachDetachIntent(),
},
child: Actions(actions: <Type, Action<Intent>>{
ReloadThemeIntent: CallbackAction<ReloadThemeIntent>(
onInvoke: (intent) => _reloadTheme(context)),
AttachDetachIntent: CallbackAction<AttachDetachIntent>(
onInvoke: (intent) => _attachDetach(context)),
}, child: Focus(autofocus: true, child: builder(context)))));
@override
Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>(
@ -134,8 +107,82 @@ class VeilidChatApp extends StatelessWidget {
}
// Once init is done, we proceed with the app
final localizationDelegate = LocalizedApp.of(context).delegate;
return ThemeProvider(
initTheme: initialThemeData,
builder: (context, theme) => LocalizationProvider(
state: LocalizationProvider.of(context).state,
child: MultiBlocProvider(
providers: [
BlocProvider<PreferencesCubit>(
create: (context) =>
PreferencesCubit(PreferencesRepository.instance),
),
BlocProvider<NotificationsCubit>(
create: (context) => NotificationsCubit(
const NotificationsState(queue: IList.empty()))),
BlocProvider<ConnectionStateCubit>(
create: (context) =>
ConnectionStateCubit(ProcessorRepository.instance)),
BlocProvider<RouterCubit>(
create: (context) =>
RouterCubit(AccountRepository.instance),
),
BlocProvider<LocalAccountsCubit>(
create: (context) =>
LocalAccountsCubit(AccountRepository.instance),
),
BlocProvider<UserLoginsCubit>(
create: (context) =>
UserLoginsCubit(AccountRepository.instance),
),
BlocProvider<ActiveLocalAccountCubit>(
create: (context) =>
ActiveLocalAccountCubit(AccountRepository.instance),
),
BlocProvider<PerAccountCollectionBlocMapCubit>(
create: (context) => PerAccountCollectionBlocMapCubit(
accountRepository: AccountRepository.instance,
locator: context.read)),
],
child:
BackgroundTicker(child: _buildShortcuts(builder: (context) {
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return SafeArea(child: appBuilder(context, localizationDelegate));
final gradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: scaleConfig.preferBorders &&
theme.brightness == Brightness.light
? [
scale.grayScale.hoverElementBackground,
scale.grayScale.subtleBackground,
]
: [
scale.primaryScale.hoverElementBackground,
scale.primaryScale.subtleBackground,
]);
return DecoratedBox(
decoration: BoxDecoration(gradient: gradient),
child: MaterialApp.router(
scrollBehavior: const ScrollBehaviorModified(),
debugShowCheckedModeBanner: false,
routerConfig: context.read<RouterCubit>().router(),
title: translate('app.title'),
theme: theme,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
FormBuilderLocalizations.delegate,
localizationDelegate
],
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
));
})),
)),
);
});
@override

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:async_tools/async_tools.dart';
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/widgets.dart';
@ -49,11 +50,8 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
messageWindow: const AsyncLoading(),
title: '',
)) {
// Immediate Init
_init();
// Async Init
_initWait.add(_initAsync);
_initWait.add(_init);
}
factory ChatComponentCubit.singleContact(
@ -70,7 +68,7 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
messagesCubit: messagesCubit,
);
void _init() {
Future<void> _init(Completer<void> _cancel) async {
// Get local user info and account record cubit
_localUserIdentityKey = _accountInfo.identityTypedPublicKey;
@ -79,6 +77,9 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
_accountRecordCubit.stream.listen(_onChangedAccountRecord);
_onChangedAccountRecord(_accountRecordCubit.state);
// Subscribe to remote user info
await _updateConversationSubscriptions();
// Subscribe to messages
_messagesSubscription = _messagesCubit.stream.listen(_onChangedMessages);
_onChangedMessages(_messagesCubit.state);
@ -89,11 +90,6 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
_onChangedContacts(_contactListCubit.state);
}
Future<void> _initAsync(Completer<void> _cancel) async {
// Subscribe to remote user info
await _updateConversationSubscriptions();
}
@override
Future<void> close() async {
await _initWait();
@ -183,7 +179,9 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
emit(_convertMessages(state, avMessagesState));
}
void _onChangedContacts(DHTShortArrayCubitState<proto.Contact> bavContacts) {
void _onChangedContacts(
BlocBusyState<AsyncValue<IList<DHTShortArrayElementState<proto.Contact>>>>
bavContacts) {
// Rewrite users when contacts change
singleFuture((this, _sfChangedContacts), _updateConversationSubscriptions);
}
@ -350,7 +348,6 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
case proto.Message_Kind.membership:
case proto.Message_Kind.moderation:
case proto.Message_Kind.notSet:
case proto.Message_Kind.readReceipt:
return (currentState, null);
}
}
@ -438,7 +435,9 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
final Map<TypedKey, StreamSubscription<AsyncValue<ActiveConversationState>>>
_conversationSubscriptions = {};
late StreamSubscription<SingleContactMessagesState> _messagesSubscription;
late StreamSubscription<DHTShortArrayCubitState<proto.Contact>>
late StreamSubscription<
BlocBusyState<
AsyncValue<IList<DHTShortArrayElementState<proto.Contact>>>>>
_contactListSubscription;
double scrollOffset = 0;
}

View File

@ -13,7 +13,7 @@ import 'window_state.dart';
part 'chat_component_state.freezed.dart';
@freezed
sealed class ChatComponentState with _$ChatComponentState {
class ChatComponentState with _$ChatComponentState {
const factory ChatComponentState(
{
// GlobalKey for the chat

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,78 +9,42 @@ part of 'chat_component_state.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$ChatComponentState {
// GlobalKey for the chat
GlobalKey<ChatState> get chatKey; // ScrollController for the chat
AutoScrollController
get scrollController; // TextEditingController for the chat
InputTextFieldController get textEditingController; // Local user
User? get localUser; // Active remote users
IMap<TypedKey, User> get remoteUsers; // Historical remote users
IMap<TypedKey, User> get historicalRemoteUsers; // Unknown users
IMap<TypedKey, User> get unknownUsers; // Messages state
AsyncValue<WindowState<Message>> get messageWindow; // Title of the chat
String get title;
GlobalKey<ChatState> get chatKey =>
throw _privateConstructorUsedError; // ScrollController for the chat
AutoScrollController get scrollController =>
throw _privateConstructorUsedError; // TextEditingController for the chat
InputTextFieldController get textEditingController =>
throw _privateConstructorUsedError; // Local user
User? get localUser =>
throw _privateConstructorUsedError; // Active remote users
IMap<Typed<FixedEncodedString43>, User> get remoteUsers =>
throw _privateConstructorUsedError; // Historical remote users
IMap<Typed<FixedEncodedString43>, User> get historicalRemoteUsers =>
throw _privateConstructorUsedError; // Unknown users
IMap<Typed<FixedEncodedString43>, User> get unknownUsers =>
throw _privateConstructorUsedError; // Messages state
AsyncValue<WindowState<Message>> get messageWindow =>
throw _privateConstructorUsedError; // Title of the chat
String get title => throw _privateConstructorUsedError;
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@JsonKey(ignore: true)
$ChatComponentStateCopyWith<ChatComponentState> get copyWith =>
_$ChatComponentStateCopyWithImpl<ChatComponentState>(
this as ChatComponentState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is ChatComponentState &&
(identical(other.chatKey, chatKey) || other.chatKey == chatKey) &&
(identical(other.scrollController, scrollController) ||
other.scrollController == scrollController) &&
(identical(other.textEditingController, textEditingController) ||
other.textEditingController == textEditingController) &&
(identical(other.localUser, localUser) ||
other.localUser == localUser) &&
(identical(other.remoteUsers, remoteUsers) ||
other.remoteUsers == remoteUsers) &&
(identical(other.historicalRemoteUsers, historicalRemoteUsers) ||
other.historicalRemoteUsers == historicalRemoteUsers) &&
(identical(other.unknownUsers, unknownUsers) ||
other.unknownUsers == unknownUsers) &&
(identical(other.messageWindow, messageWindow) ||
other.messageWindow == messageWindow) &&
(identical(other.title, title) || other.title == title));
}
@override
int get hashCode => Object.hash(
runtimeType,
chatKey,
scrollController,
textEditingController,
localUser,
remoteUsers,
historicalRemoteUsers,
unknownUsers,
messageWindow,
title);
@override
String toString() {
return 'ChatComponentState(chatKey: $chatKey, scrollController: $scrollController, textEditingController: $textEditingController, localUser: $localUser, remoteUsers: $remoteUsers, historicalRemoteUsers: $historicalRemoteUsers, unknownUsers: $unknownUsers, messageWindow: $messageWindow, title: $title)';
}
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class $ChatComponentStateCopyWith<$Res> {
abstract class $ChatComponentStateCopyWith<$Res> {
factory $ChatComponentStateCopyWith(
ChatComponentState value, $Res Function(ChatComponentState) _then) =
_$ChatComponentStateCopyWithImpl;
ChatComponentState value, $Res Function(ChatComponentState) then) =
_$ChatComponentStateCopyWithImpl<$Res, ChatComponentState>;
@useResult
$Res call(
{GlobalKey<ChatState> chatKey,
@ -98,15 +61,15 @@ abstract mixin class $ChatComponentStateCopyWith<$Res> {
}
/// @nodoc
class _$ChatComponentStateCopyWithImpl<$Res>
class _$ChatComponentStateCopyWithImpl<$Res, $Val extends ChatComponentState>
implements $ChatComponentStateCopyWith<$Res> {
_$ChatComponentStateCopyWithImpl(this._self, this._then);
_$ChatComponentStateCopyWithImpl(this._value, this._then);
final ChatComponentState _self;
final $Res Function(ChatComponentState) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -120,62 +83,145 @@ class _$ChatComponentStateCopyWithImpl<$Res>
Object? messageWindow = null,
Object? title = null,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
chatKey: null == chatKey
? _self.chatKey
? _value.chatKey
: chatKey // ignore: cast_nullable_to_non_nullable
as GlobalKey<ChatState>,
scrollController: null == scrollController
? _self.scrollController
? _value.scrollController
: scrollController // ignore: cast_nullable_to_non_nullable
as AutoScrollController,
textEditingController: null == textEditingController
? _self.textEditingController
? _value.textEditingController
: textEditingController // ignore: cast_nullable_to_non_nullable
as InputTextFieldController,
localUser: freezed == localUser
? _self.localUser
? _value.localUser
: localUser // ignore: cast_nullable_to_non_nullable
as User?,
remoteUsers: null == remoteUsers
? _self.remoteUsers!
? _value.remoteUsers
: remoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
historicalRemoteUsers: null == historicalRemoteUsers
? _self.historicalRemoteUsers!
? _value.historicalRemoteUsers
: historicalRemoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
unknownUsers: null == unknownUsers
? _self.unknownUsers!
? _value.unknownUsers
: unknownUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
messageWindow: null == messageWindow
? _self.messageWindow
? _value.messageWindow
: messageWindow // ignore: cast_nullable_to_non_nullable
as AsyncValue<WindowState<Message>>,
title: null == title
? _self.title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
));
) as $Val);
}
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AsyncValueCopyWith<WindowState<Message>, $Res> get messageWindow {
return $AsyncValueCopyWith<WindowState<Message>, $Res>(_self.messageWindow,
return $AsyncValueCopyWith<WindowState<Message>, $Res>(_value.messageWindow,
(value) {
return _then(_self.copyWith(messageWindow: value));
return _then(_value.copyWith(messageWindow: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$ChatComponentStateImplCopyWith<$Res>
implements $ChatComponentStateCopyWith<$Res> {
factory _$$ChatComponentStateImplCopyWith(_$ChatComponentStateImpl value,
$Res Function(_$ChatComponentStateImpl) then) =
__$$ChatComponentStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{GlobalKey<ChatState> chatKey,
AutoScrollController scrollController,
InputTextFieldController textEditingController,
User? localUser,
IMap<Typed<FixedEncodedString43>, User> remoteUsers,
IMap<Typed<FixedEncodedString43>, User> historicalRemoteUsers,
IMap<Typed<FixedEncodedString43>, User> unknownUsers,
AsyncValue<WindowState<Message>> messageWindow,
String title});
class _ChatComponentState implements ChatComponentState {
const _ChatComponentState(
@override
$AsyncValueCopyWith<WindowState<Message>, $Res> get messageWindow;
}
/// @nodoc
class __$$ChatComponentStateImplCopyWithImpl<$Res>
extends _$ChatComponentStateCopyWithImpl<$Res, _$ChatComponentStateImpl>
implements _$$ChatComponentStateImplCopyWith<$Res> {
__$$ChatComponentStateImplCopyWithImpl(_$ChatComponentStateImpl _value,
$Res Function(_$ChatComponentStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? chatKey = null,
Object? scrollController = null,
Object? textEditingController = null,
Object? localUser = freezed,
Object? remoteUsers = null,
Object? historicalRemoteUsers = null,
Object? unknownUsers = null,
Object? messageWindow = null,
Object? title = null,
}) {
return _then(_$ChatComponentStateImpl(
chatKey: null == chatKey
? _value.chatKey
: chatKey // ignore: cast_nullable_to_non_nullable
as GlobalKey<ChatState>,
scrollController: null == scrollController
? _value.scrollController
: scrollController // ignore: cast_nullable_to_non_nullable
as AutoScrollController,
textEditingController: null == textEditingController
? _value.textEditingController
: textEditingController // ignore: cast_nullable_to_non_nullable
as InputTextFieldController,
localUser: freezed == localUser
? _value.localUser
: localUser // ignore: cast_nullable_to_non_nullable
as User?,
remoteUsers: null == remoteUsers
? _value.remoteUsers
: remoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
historicalRemoteUsers: null == historicalRemoteUsers
? _value.historicalRemoteUsers
: historicalRemoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
unknownUsers: null == unknownUsers
? _value.unknownUsers
: unknownUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
messageWindow: null == messageWindow
? _value.messageWindow
: messageWindow // ignore: cast_nullable_to_non_nullable
as AsyncValue<WindowState<Message>>,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$ChatComponentStateImpl implements _ChatComponentState {
const _$ChatComponentStateImpl(
{required this.chatKey,
required this.scrollController,
required this.textEditingController,
@ -214,19 +260,16 @@ class _ChatComponentState implements ChatComponentState {
@override
final String title;
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ChatComponentStateCopyWith<_ChatComponentState> get copyWith =>
__$ChatComponentStateCopyWithImpl<_ChatComponentState>(this, _$identity);
String toString() {
return 'ChatComponentState(chatKey: $chatKey, scrollController: $scrollController, textEditingController: $textEditingController, localUser: $localUser, remoteUsers: $remoteUsers, historicalRemoteUsers: $historicalRemoteUsers, unknownUsers: $unknownUsers, messageWindow: $messageWindow, title: $title)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _ChatComponentState &&
other is _$ChatComponentStateImpl &&
(identical(other.chatKey, chatKey) || other.chatKey == chatKey) &&
(identical(other.scrollController, scrollController) ||
other.scrollController == scrollController) &&
@ -258,108 +301,47 @@ class _ChatComponentState implements ChatComponentState {
messageWindow,
title);
@override
String toString() {
return 'ChatComponentState(chatKey: $chatKey, scrollController: $scrollController, textEditingController: $textEditingController, localUser: $localUser, remoteUsers: $remoteUsers, historicalRemoteUsers: $historicalRemoteUsers, unknownUsers: $unknownUsers, messageWindow: $messageWindow, title: $title)';
}
}
/// @nodoc
abstract mixin class _$ChatComponentStateCopyWith<$Res>
implements $ChatComponentStateCopyWith<$Res> {
factory _$ChatComponentStateCopyWith(
_ChatComponentState value, $Res Function(_ChatComponentState) _then) =
__$ChatComponentStateCopyWithImpl;
@override
@useResult
$Res call(
{GlobalKey<ChatState> chatKey,
AutoScrollController scrollController,
InputTextFieldController textEditingController,
User? localUser,
IMap<Typed<FixedEncodedString43>, User> remoteUsers,
IMap<Typed<FixedEncodedString43>, User> historicalRemoteUsers,
IMap<Typed<FixedEncodedString43>, User> unknownUsers,
AsyncValue<WindowState<Message>> messageWindow,
String title});
@override
$AsyncValueCopyWith<WindowState<Message>, $Res> get messageWindow;
}
/// @nodoc
class __$ChatComponentStateCopyWithImpl<$Res>
implements _$ChatComponentStateCopyWith<$Res> {
__$ChatComponentStateCopyWithImpl(this._self, this._then);
final _ChatComponentState _self;
final $Res Function(_ChatComponentState) _then;
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? chatKey = null,
Object? scrollController = null,
Object? textEditingController = null,
Object? localUser = freezed,
Object? remoteUsers = null,
Object? historicalRemoteUsers = null,
Object? unknownUsers = null,
Object? messageWindow = null,
Object? title = null,
}) {
return _then(_ChatComponentState(
chatKey: null == chatKey
? _self.chatKey
: chatKey // ignore: cast_nullable_to_non_nullable
as GlobalKey<ChatState>,
scrollController: null == scrollController
? _self.scrollController
: scrollController // ignore: cast_nullable_to_non_nullable
as AutoScrollController,
textEditingController: null == textEditingController
? _self.textEditingController
: textEditingController // ignore: cast_nullable_to_non_nullable
as InputTextFieldController,
localUser: freezed == localUser
? _self.localUser
: localUser // ignore: cast_nullable_to_non_nullable
as User?,
remoteUsers: null == remoteUsers
? _self.remoteUsers
: remoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
historicalRemoteUsers: null == historicalRemoteUsers
? _self.historicalRemoteUsers
: historicalRemoteUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
unknownUsers: null == unknownUsers
? _self.unknownUsers
: unknownUsers // ignore: cast_nullable_to_non_nullable
as IMap<Typed<FixedEncodedString43>, User>,
messageWindow: null == messageWindow
? _self.messageWindow
: messageWindow // ignore: cast_nullable_to_non_nullable
as AsyncValue<WindowState<Message>>,
title: null == title
? _self.title
: title // ignore: cast_nullable_to_non_nullable
as String,
));
}
/// Create a copy of ChatComponentState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AsyncValueCopyWith<WindowState<Message>, $Res> get messageWindow {
return $AsyncValueCopyWith<WindowState<Message>, $Res>(_self.messageWindow,
(value) {
return _then(_self.copyWith(messageWindow: value));
});
}
_$$ChatComponentStateImplCopyWith<_$ChatComponentStateImpl> get copyWith =>
__$$ChatComponentStateImplCopyWithImpl<_$ChatComponentStateImpl>(
this, _$identity);
}
// dart format on
abstract class _ChatComponentState implements ChatComponentState {
const factory _ChatComponentState(
{required final GlobalKey<ChatState> chatKey,
required final AutoScrollController scrollController,
required final InputTextFieldController textEditingController,
required final User? localUser,
required final IMap<Typed<FixedEncodedString43>, User> remoteUsers,
required final IMap<Typed<FixedEncodedString43>, User>
historicalRemoteUsers,
required final IMap<Typed<FixedEncodedString43>, User> unknownUsers,
required final AsyncValue<WindowState<Message>> messageWindow,
required final String title}) = _$ChatComponentStateImpl;
@override // GlobalKey for the chat
GlobalKey<ChatState> get chatKey;
@override // ScrollController for the chat
AutoScrollController get scrollController;
@override // TextEditingController for the chat
InputTextFieldController get textEditingController;
@override // Local user
User? get localUser;
@override // Active remote users
IMap<Typed<FixedEncodedString43>, User> get remoteUsers;
@override // Historical remote users
IMap<Typed<FixedEncodedString43>, User> get historicalRemoteUsers;
@override // Unknown users
IMap<Typed<FixedEncodedString43>, User> get unknownUsers;
@override // Messages state
AsyncValue<WindowState<Message>> get messageWindow;
@override // Title of the chat
String get title;
@override
@JsonKey(ignore: true)
_$$ChatComponentStateImplCopyWith<_$ChatComponentStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -24,7 +24,7 @@ enum MessageSendState {
}
@freezed
sealed class MessageState with _$MessageState {
class MessageState with _$MessageState {
const factory MessageState({
// Content of the message
@JsonKey(fromJson: messageFromJson, toJson: messageToJson)

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,69 +9,38 @@ part of 'message_state.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$MessageState implements DiagnosticableTreeMixin {
// Content of the message
@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
proto.Message get content; // Sent timestamp
Timestamp get sentTimestamp; // Reconciled timestamp
Timestamp? get reconciledTimestamp; // The state of the message
MessageSendState? get sendState;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// Create a copy of MessageState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$MessageStateCopyWith<MessageState> get copyWith =>
_$MessageStateCopyWithImpl<MessageState>(
this as MessageState, _$identity);
/// Serializes this MessageState to a JSON map.
Map<String, dynamic> toJson();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'MessageState'))
..add(DiagnosticsProperty('content', content))
..add(DiagnosticsProperty('sentTimestamp', sentTimestamp))
..add(DiagnosticsProperty('reconciledTimestamp', reconciledTimestamp))
..add(DiagnosticsProperty('sendState', sendState));
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is MessageState &&
(identical(other.content, content) || other.content == content) &&
(identical(other.sentTimestamp, sentTimestamp) ||
other.sentTimestamp == sentTimestamp) &&
(identical(other.reconciledTimestamp, reconciledTimestamp) ||
other.reconciledTimestamp == reconciledTimestamp) &&
(identical(other.sendState, sendState) ||
other.sendState == sendState));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType, content, sentTimestamp, reconciledTimestamp, sendState);
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'MessageState(content: $content, sentTimestamp: $sentTimestamp, reconciledTimestamp: $reconciledTimestamp, sendState: $sendState)';
}
MessageState _$MessageStateFromJson(Map<String, dynamic> json) {
return _MessageState.fromJson(json);
}
/// @nodoc
abstract mixin class $MessageStateCopyWith<$Res> {
mixin _$MessageState {
// Content of the message
@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
proto.Message get content =>
throw _privateConstructorUsedError; // Sent timestamp
Timestamp get sentTimestamp =>
throw _privateConstructorUsedError; // Reconciled timestamp
Timestamp? get reconciledTimestamp =>
throw _privateConstructorUsedError; // The state of the message
MessageSendState? get sendState => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$MessageStateCopyWith<MessageState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MessageStateCopyWith<$Res> {
factory $MessageStateCopyWith(
MessageState value, $Res Function(MessageState) _then) =
_$MessageStateCopyWithImpl;
MessageState value, $Res Function(MessageState) then) =
_$MessageStateCopyWithImpl<$Res, MessageState>;
@useResult
$Res call(
{@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
@ -83,14 +51,15 @@ abstract mixin class $MessageStateCopyWith<$Res> {
}
/// @nodoc
class _$MessageStateCopyWithImpl<$Res> implements $MessageStateCopyWith<$Res> {
_$MessageStateCopyWithImpl(this._self, this._then);
class _$MessageStateCopyWithImpl<$Res, $Val extends MessageState>
implements $MessageStateCopyWith<$Res> {
_$MessageStateCopyWithImpl(this._value, this._then);
final MessageState _self;
final $Res Function(MessageState) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of MessageState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -99,21 +68,74 @@ class _$MessageStateCopyWithImpl<$Res> implements $MessageStateCopyWith<$Res> {
Object? reconciledTimestamp = freezed,
Object? sendState = freezed,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
content: null == content
? _self.content
? _value.content
: content // ignore: cast_nullable_to_non_nullable
as proto.Message,
sentTimestamp: null == sentTimestamp
? _self.sentTimestamp
? _value.sentTimestamp
: sentTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp,
reconciledTimestamp: freezed == reconciledTimestamp
? _self.reconciledTimestamp
? _value.reconciledTimestamp
: reconciledTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp?,
sendState: freezed == sendState
? _self.sendState
? _value.sendState
: sendState // ignore: cast_nullable_to_non_nullable
as MessageSendState?,
) as $Val);
}
}
/// @nodoc
abstract class _$$MessageStateImplCopyWith<$Res>
implements $MessageStateCopyWith<$Res> {
factory _$$MessageStateImplCopyWith(
_$MessageStateImpl value, $Res Function(_$MessageStateImpl) then) =
__$$MessageStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
proto.Message content,
Timestamp sentTimestamp,
Timestamp? reconciledTimestamp,
MessageSendState? sendState});
}
/// @nodoc
class __$$MessageStateImplCopyWithImpl<$Res>
extends _$MessageStateCopyWithImpl<$Res, _$MessageStateImpl>
implements _$$MessageStateImplCopyWith<$Res> {
__$$MessageStateImplCopyWithImpl(
_$MessageStateImpl _value, $Res Function(_$MessageStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? content = null,
Object? sentTimestamp = null,
Object? reconciledTimestamp = freezed,
Object? sendState = freezed,
}) {
return _then(_$MessageStateImpl(
content: null == content
? _value.content
: content // ignore: cast_nullable_to_non_nullable
as proto.Message,
sentTimestamp: null == sentTimestamp
? _value.sentTimestamp
: sentTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp,
reconciledTimestamp: freezed == reconciledTimestamp
? _value.reconciledTimestamp
: reconciledTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp?,
sendState: freezed == sendState
? _value.sendState
: sendState // ignore: cast_nullable_to_non_nullable
as MessageSendState?,
));
@ -122,15 +144,16 @@ class _$MessageStateCopyWithImpl<$Res> implements $MessageStateCopyWith<$Res> {
/// @nodoc
@JsonSerializable()
class _MessageState with DiagnosticableTreeMixin implements MessageState {
const _MessageState(
class _$MessageStateImpl with DiagnosticableTreeMixin implements _MessageState {
const _$MessageStateImpl(
{@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
required this.content,
required this.sentTimestamp,
required this.reconciledTimestamp,
required this.sendState});
factory _MessageState.fromJson(Map<String, dynamic> json) =>
_$MessageStateFromJson(json);
factory _$MessageStateImpl.fromJson(Map<String, dynamic> json) =>
_$$MessageStateImplFromJson(json);
// Content of the message
@override
@ -146,23 +169,14 @@ class _MessageState with DiagnosticableTreeMixin implements MessageState {
@override
final MessageSendState? sendState;
/// Create a copy of MessageState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$MessageStateCopyWith<_MessageState> get copyWith =>
__$MessageStateCopyWithImpl<_MessageState>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$MessageStateToJson(
this,
);
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'MessageState(content: $content, sentTimestamp: $sentTimestamp, reconciledTimestamp: $reconciledTimestamp, sendState: $sendState)';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('type', 'MessageState'))
..add(DiagnosticsProperty('content', content))
@ -175,7 +189,7 @@ class _MessageState with DiagnosticableTreeMixin implements MessageState {
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _MessageState &&
other is _$MessageStateImpl &&
(identical(other.content, content) || other.content == content) &&
(identical(other.sentTimestamp, sentTimestamp) ||
other.sentTimestamp == sentTimestamp) &&
@ -185,70 +199,47 @@ class _MessageState with DiagnosticableTreeMixin implements MessageState {
other.sendState == sendState));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(
runtimeType, content, sentTimestamp, reconciledTimestamp, sendState);
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'MessageState(content: $content, sentTimestamp: $sentTimestamp, reconciledTimestamp: $reconciledTimestamp, sendState: $sendState)';
}
}
/// @nodoc
abstract mixin class _$MessageStateCopyWith<$Res>
implements $MessageStateCopyWith<$Res> {
factory _$MessageStateCopyWith(
_MessageState value, $Res Function(_MessageState) _then) =
__$MessageStateCopyWithImpl;
@override
@useResult
$Res call(
{@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
proto.Message content,
Timestamp sentTimestamp,
Timestamp? reconciledTimestamp,
MessageSendState? sendState});
}
/// @nodoc
class __$MessageStateCopyWithImpl<$Res>
implements _$MessageStateCopyWith<$Res> {
__$MessageStateCopyWithImpl(this._self, this._then);
final _MessageState _self;
final $Res Function(_MessageState) _then;
/// Create a copy of MessageState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? content = null,
Object? sentTimestamp = null,
Object? reconciledTimestamp = freezed,
Object? sendState = freezed,
}) {
return _then(_MessageState(
content: null == content
? _self.content
: content // ignore: cast_nullable_to_non_nullable
as proto.Message,
sentTimestamp: null == sentTimestamp
? _self.sentTimestamp
: sentTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp,
reconciledTimestamp: freezed == reconciledTimestamp
? _self.reconciledTimestamp
: reconciledTimestamp // ignore: cast_nullable_to_non_nullable
as Timestamp?,
sendState: freezed == sendState
? _self.sendState
: sendState // ignore: cast_nullable_to_non_nullable
as MessageSendState?,
));
_$$MessageStateImplCopyWith<_$MessageStateImpl> get copyWith =>
__$$MessageStateImplCopyWithImpl<_$MessageStateImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$MessageStateImplToJson(
this,
);
}
}
// dart format on
abstract class _MessageState implements MessageState {
const factory _MessageState(
{@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
required final proto.Message content,
required final Timestamp sentTimestamp,
required final Timestamp? reconciledTimestamp,
required final MessageSendState? sendState}) = _$MessageStateImpl;
factory _MessageState.fromJson(Map<String, dynamic> json) =
_$MessageStateImpl.fromJson;
@override // Content of the message
@JsonKey(fromJson: messageFromJson, toJson: messageToJson)
proto.Message get content;
@override // Sent timestamp
Timestamp get sentTimestamp;
@override // Reconciled timestamp
Timestamp? get reconciledTimestamp;
@override // The state of the message
MessageSendState? get sendState;
@override
@JsonKey(ignore: true)
_$$MessageStateImplCopyWith<_$MessageStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -6,8 +6,8 @@ part of 'message_state.dart';
// JsonSerializableGenerator
// **************************************************************************
_MessageState _$MessageStateFromJson(Map<String, dynamic> json) =>
_MessageState(
_$MessageStateImpl _$$MessageStateImplFromJson(Map<String, dynamic> json) =>
_$MessageStateImpl(
content: messageFromJson(json['content'] as Map<String, dynamic>),
sentTimestamp: Timestamp.fromJson(json['sent_timestamp']),
reconciledTimestamp: json['reconciled_timestamp'] == null
@ -18,7 +18,7 @@ _MessageState _$MessageStateFromJson(Map<String, dynamic> json) =>
: MessageSendState.fromJson(json['send_state']),
);
Map<String, dynamic> _$MessageStateToJson(_MessageState instance) =>
Map<String, dynamic> _$$MessageStateImplToJson(_$MessageStateImpl instance) =>
<String, dynamic>{
'content': messageToJson(instance.content),
'sent_timestamp': instance.sentTimestamp.toJson(),

View File

@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'window_state.freezed.dart';
@freezed
sealed class WindowState<T> with _$WindowState<T> {
class WindowState<T> with _$WindowState<T> {
const factory WindowState({
// List of objects in the window
required IList<T> window,

View File

@ -1,4 +1,3 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
@ -10,71 +9,34 @@ part of 'window_state.dart';
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$WindowState<T> implements DiagnosticableTreeMixin {
mixin _$WindowState<T> {
// List of objects in the window
IList<T> get window; // Total number of objects (windowTail max)
int get length; // One past the end of the last element
int get windowTail; // The total number of elements to try to keep in the window
int get windowCount; // If we should have the tail following the array
bool get follow;
IList<T> get window =>
throw _privateConstructorUsedError; // Total number of objects (windowTail max)
int get length =>
throw _privateConstructorUsedError; // One past the end of the last element
int get windowTail =>
throw _privateConstructorUsedError; // The total number of elements to try to keep in the window
int get windowCount =>
throw _privateConstructorUsedError; // If we should have the tail following the array
bool get follow => throw _privateConstructorUsedError;
/// Create a copy of WindowState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@JsonKey(ignore: true)
$WindowStateCopyWith<T, WindowState<T>> get copyWith =>
_$WindowStateCopyWithImpl<T, WindowState<T>>(
this as WindowState<T>, _$identity);
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'WindowState<$T>'))
..add(DiagnosticsProperty('window', window))
..add(DiagnosticsProperty('length', length))
..add(DiagnosticsProperty('windowTail', windowTail))
..add(DiagnosticsProperty('windowCount', windowCount))
..add(DiagnosticsProperty('follow', follow));
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is WindowState<T> &&
const DeepCollectionEquality().equals(other.window, window) &&
(identical(other.length, length) || other.length == length) &&
(identical(other.windowTail, windowTail) ||
other.windowTail == windowTail) &&
(identical(other.windowCount, windowCount) ||
other.windowCount == windowCount) &&
(identical(other.follow, follow) || other.follow == follow));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(window),
length,
windowTail,
windowCount,
follow);
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'WindowState<$T>(window: $window, length: $length, windowTail: $windowTail, windowCount: $windowCount, follow: $follow)';
}
throw _privateConstructorUsedError;
}
/// @nodoc
abstract mixin class $WindowStateCopyWith<T, $Res> {
abstract class $WindowStateCopyWith<T, $Res> {
factory $WindowStateCopyWith(
WindowState<T> value, $Res Function(WindowState<T>) _then) =
_$WindowStateCopyWithImpl;
WindowState<T> value, $Res Function(WindowState<T>) then) =
_$WindowStateCopyWithImpl<T, $Res, WindowState<T>>;
@useResult
$Res call(
{IList<T> window,
@ -85,15 +47,15 @@ abstract mixin class $WindowStateCopyWith<T, $Res> {
}
/// @nodoc
class _$WindowStateCopyWithImpl<T, $Res>
class _$WindowStateCopyWithImpl<T, $Res, $Val extends WindowState<T>>
implements $WindowStateCopyWith<T, $Res> {
_$WindowStateCopyWithImpl(this._self, this._then);
_$WindowStateCopyWithImpl(this._value, this._then);
final WindowState<T> _self;
final $Res Function(WindowState<T>) _then;
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of WindowState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
@ -103,25 +65,83 @@ class _$WindowStateCopyWithImpl<T, $Res>
Object? windowCount = null,
Object? follow = null,
}) {
return _then(_self.copyWith(
return _then(_value.copyWith(
window: null == window
? _self.window
? _value.window
: window // ignore: cast_nullable_to_non_nullable
as IList<T>,
length: null == length
? _self.length
? _value.length
: length // ignore: cast_nullable_to_non_nullable
as int,
windowTail: null == windowTail
? _self.windowTail
? _value.windowTail
: windowTail // ignore: cast_nullable_to_non_nullable
as int,
windowCount: null == windowCount
? _self.windowCount
? _value.windowCount
: windowCount // ignore: cast_nullable_to_non_nullable
as int,
follow: null == follow
? _self.follow
? _value.follow
: follow // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}
/// @nodoc
abstract class _$$WindowStateImplCopyWith<T, $Res>
implements $WindowStateCopyWith<T, $Res> {
factory _$$WindowStateImplCopyWith(_$WindowStateImpl<T> value,
$Res Function(_$WindowStateImpl<T>) then) =
__$$WindowStateImplCopyWithImpl<T, $Res>;
@override
@useResult
$Res call(
{IList<T> window,
int length,
int windowTail,
int windowCount,
bool follow});
}
/// @nodoc
class __$$WindowStateImplCopyWithImpl<T, $Res>
extends _$WindowStateCopyWithImpl<T, $Res, _$WindowStateImpl<T>>
implements _$$WindowStateImplCopyWith<T, $Res> {
__$$WindowStateImplCopyWithImpl(
_$WindowStateImpl<T> _value, $Res Function(_$WindowStateImpl<T>) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? window = null,
Object? length = null,
Object? windowTail = null,
Object? windowCount = null,
Object? follow = null,
}) {
return _then(_$WindowStateImpl<T>(
window: null == window
? _value.window
: window // ignore: cast_nullable_to_non_nullable
as IList<T>,
length: null == length
? _value.length
: length // ignore: cast_nullable_to_non_nullable
as int,
windowTail: null == windowTail
? _value.windowTail
: windowTail // ignore: cast_nullable_to_non_nullable
as int,
windowCount: null == windowCount
? _value.windowCount
: windowCount // ignore: cast_nullable_to_non_nullable
as int,
follow: null == follow
? _value.follow
: follow // ignore: cast_nullable_to_non_nullable
as bool,
));
@ -130,8 +150,10 @@ class _$WindowStateCopyWithImpl<T, $Res>
/// @nodoc
class _WindowState<T> with DiagnosticableTreeMixin implements WindowState<T> {
const _WindowState(
class _$WindowStateImpl<T>
with DiagnosticableTreeMixin
implements _WindowState<T> {
const _$WindowStateImpl(
{required this.window,
required this.length,
required this.windowTail,
@ -154,16 +176,14 @@ class _WindowState<T> with DiagnosticableTreeMixin implements WindowState<T> {
@override
final bool follow;
/// Create a copy of WindowState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$WindowStateCopyWith<T, _WindowState<T>> get copyWith =>
__$WindowStateCopyWithImpl<T, _WindowState<T>>(this, _$identity);
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'WindowState<$T>(window: $window, length: $length, windowTail: $windowTail, windowCount: $windowCount, follow: $follow)';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('type', 'WindowState<$T>'))
..add(DiagnosticsProperty('window', window))
@ -177,7 +197,7 @@ class _WindowState<T> with DiagnosticableTreeMixin implements WindowState<T> {
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _WindowState<T> &&
other is _$WindowStateImpl<T> &&
const DeepCollectionEquality().equals(other.window, window) &&
(identical(other.length, length) || other.length == length) &&
(identical(other.windowTail, windowTail) ||
@ -196,70 +216,34 @@ class _WindowState<T> with DiagnosticableTreeMixin implements WindowState<T> {
windowCount,
follow);
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'WindowState<$T>(window: $window, length: $length, windowTail: $windowTail, windowCount: $windowCount, follow: $follow)';
}
}
/// @nodoc
abstract mixin class _$WindowStateCopyWith<T, $Res>
implements $WindowStateCopyWith<T, $Res> {
factory _$WindowStateCopyWith(
_WindowState<T> value, $Res Function(_WindowState<T>) _then) =
__$WindowStateCopyWithImpl;
@override
@useResult
$Res call(
{IList<T> window,
int length,
int windowTail,
int windowCount,
bool follow});
}
/// @nodoc
class __$WindowStateCopyWithImpl<T, $Res>
implements _$WindowStateCopyWith<T, $Res> {
__$WindowStateCopyWithImpl(this._self, this._then);
final _WindowState<T> _self;
final $Res Function(_WindowState<T>) _then;
/// Create a copy of WindowState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
$Res call({
Object? window = null,
Object? length = null,
Object? windowTail = null,
Object? windowCount = null,
Object? follow = null,
}) {
return _then(_WindowState<T>(
window: null == window
? _self.window
: window // ignore: cast_nullable_to_non_nullable
as IList<T>,
length: null == length
? _self.length
: length // ignore: cast_nullable_to_non_nullable
as int,
windowTail: null == windowTail
? _self.windowTail
: windowTail // ignore: cast_nullable_to_non_nullable
as int,
windowCount: null == windowCount
? _self.windowCount
: windowCount // ignore: cast_nullable_to_non_nullable
as int,
follow: null == follow
? _self.follow
: follow // ignore: cast_nullable_to_non_nullable
as bool,
));
}
_$$WindowStateImplCopyWith<T, _$WindowStateImpl<T>> get copyWith =>
__$$WindowStateImplCopyWithImpl<T, _$WindowStateImpl<T>>(
this, _$identity);
}
// dart format on
abstract class _WindowState<T> implements WindowState<T> {
const factory _WindowState(
{required final IList<T> window,
required final int length,
required final int windowTail,
required final int windowCount,
required final bool follow}) = _$WindowStateImpl<T>;
@override // List of objects in the window
IList<T> get window;
@override // Total number of objects (windowTail max)
int get length;
@override // One past the end of the last element
int get windowTail;
@override // The total number of elements to try to keep in the window
int get windowCount;
@override // If we should have the tail following the array
bool get follow;
@override
@JsonKey(ignore: true)
_$$WindowStateImplCopyWith<T, _$WindowStateImpl<T>> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -33,6 +33,11 @@ class ChatComponentWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final theme = Theme.of(context);
// final scale = theme.extension<ScaleScheme>()!;
// final scaleConfig = theme.extension<ScaleConfig>()!;
// final textTheme = theme.textTheme;
// Get the account info
final accountInfo = context.watch<AccountInfoCubit>().state;
@ -77,16 +82,15 @@ class ChatComponentWidget extends StatelessWidget {
Widget _buildChatComponent(BuildContext context) {
final theme = Theme.of(context);
final scaleScheme = theme.extension<ScaleScheme>()!;
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final scale = scaleScheme.scale(ScaleKind.primary);
final textTheme = theme.textTheme;
final chatTheme = makeChatTheme(scaleScheme, scaleConfig, textTheme);
final chatTheme = makeChatTheme(scale, scaleConfig, textTheme);
final errorChatTheme = (ChatThemeEditor(chatTheme)
..inputTextColor = scaleScheme.errorScale.primary
..inputTextColor = scale.errorScale.primary
..sendButtonIcon = Image.asset(
'assets/icon-send.png',
color: scaleScheme.errorScale.primary,
color: scale.errorScale.primary,
package: 'flutter_chat_ui',
))
.commit();
@ -122,7 +126,7 @@ class ChatComponentWidget extends StatelessWidget {
Container(
height: 48,
decoration: BoxDecoration(
color: scale.border,
color: scale.primaryScale.subtleBorder,
),
child: Row(children: [
Align(
@ -132,18 +136,19 @@ class ChatComponentWidget extends StatelessWidget {
child: Text(title,
textAlign: TextAlign.start,
style: textTheme.titleMedium!
.copyWith(color: scale.borderText)),
.copyWith(color: scale.primaryScale.borderText)),
)),
const Spacer(),
IconButton(
iconSize: 24,
icon: Icon(Icons.close, color: scale.borderText),
icon:
Icon(Icons.close, color: scale.primaryScale.borderText),
onPressed: _onClose)
.paddingLTRB(0, 0, 8, 0)
.paddingLTRB(16, 0, 16, 0)
]),
),
DecoratedBox(
decoration: const BoxDecoration(color: Colors.transparent),
decoration:
BoxDecoration(color: scale.primaryScale.subtleBackground),
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (chatComponentCubit.scrollOffset != 0) {
@ -197,51 +202,53 @@ class ChatComponentWidget extends StatelessWidget {
2048;
return Chat(
key: chatComponentState.chatKey,
theme: messageIsValid ? chatTheme : errorChatTheme,
messages: messageWindow.window.toList(),
scrollToBottomOnSend: isFirstPage,
scrollController: chatComponentState.scrollController,
inputOptions: InputOptions(
inputClearMode: messageIsValid
? InputClearMode.always
: InputClearMode.never,
textEditingController:
chatComponentState.textEditingController),
// isLastPage: isLastPage,
// onEndReached: () async {
// await _handlePageBackward(
// chatComponentCubit, messageWindow);
// },
//onEndReachedThreshold: onEndReachedThreshold,
//onAttachmentPressed: _handleAttachmentPressed,
//onMessageTap: _handleMessageTap,
//onPreviewDataFetched: _handlePreviewDataFetched,
usePreviewData: false, //
onSendPressed: (pt) {
try {
if (!messageIsValid) {
context.read<NotificationsCubit>().error(
text: translate('chat.message_too_long'));
return;
}
_handleSendPressed(chatComponentCubit, pt);
} on FormatException {
context.read<NotificationsCubit>().error(
text: translate('chat.message_too_long'));
}
},
listBottomWidget: messageIsValid
? null
: Text(translate('chat.message_too_long'),
style: TextStyle(
color:
scaleScheme.errorScale.primary))
.toCenter(),
//showUserAvatars: false,
//showUserNames: true,
user: localUser,
emptyState: const EmptyChatWidget());
key: chatComponentState.chatKey,
theme:
messageIsValid ? chatTheme : errorChatTheme,
messages: messageWindow.window.toList(),
scrollToBottomOnSend: isFirstPage,
scrollController:
chatComponentState.scrollController,
inputOptions: InputOptions(
inputClearMode: messageIsValid
? InputClearMode.always
: InputClearMode.never,
textEditingController:
chatComponentState.textEditingController),
// isLastPage: isLastPage,
// onEndReached: () async {
// await _handlePageBackward(
// chatComponentCubit, messageWindow);
// },
//onEndReachedThreshold: onEndReachedThreshold,
//onAttachmentPressed: _handleAttachmentPressed,
//onMessageTap: _handleMessageTap,
//onPreviewDataFetched: _handlePreviewDataFetched,
onSendPressed: (pt) {
try {
if (!messageIsValid) {
context.read<NotificationsCubit>().error(
text:
translate('chat.message_too_long'));
return;
}
_handleSendPressed(chatComponentCubit, pt);
} on FormatException {
context.read<NotificationsCubit>().error(
text: translate('chat.message_too_long'));
}
},
listBottomWidget: messageIsValid
? null
: Text(translate('chat.message_too_long'),
style: TextStyle(
color: scale.errorScale.primary))
.toCenter(),
//showUserAvatars: false,
//showUserNames: true,
user: localUser,
emptyState: const EmptyChatWidget())
.paddingLTRB(0, 2, 0, 0);
}))).expanded(),
],
);

View File

@ -17,7 +17,7 @@ class EmptyChatWidget extends StatelessWidget {
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: scale.primaryScale.appBackground,
color: Theme.of(context).scaffoldBackgroundColor,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,

View File

@ -0,0 +1,31 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../theme/theme.dart';
Widget newChatBottomSheetBuilder(
BuildContext sheetContext, BuildContext context) {
//final theme = Theme.of(sheetContext);
//final scale = theme.extension<ScaleScheme>()!;
return KeyboardListener(
focusNode: FocusNode(),
onKeyEvent: (ke) {
if (ke.logicalKey == LogicalKeyboardKey.escape) {
Navigator.pop(sheetContext);
}
},
child: styledBottomSheet(
context: context,
title: translate('add_chat_sheet.new_chat'),
child: SizedBox(
height: 160,
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Group and custom chat functionality is not available yet')
]).paddingAll(16))));
}

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../theme/theme.dart';
import '../../theme/models/scale_scheme.dart';
class NoConversationWidget extends StatelessWidget {
const NoConversationWidget({super.key});
@ -12,31 +12,30 @@ class NoConversationWidget extends StatelessWidget {
BuildContext context,
) {
final theme = Theme.of(context);
final scaleScheme = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final scale = scaleScheme.scale(ScaleKind.primary);
final scale = theme.extension<ScaleScheme>()!;
return DecoratedBox(
decoration: BoxDecoration(
color: scale.appBackground.withAlpha(scaleConfig.wallpaperAlpha),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.diversity_3,
color: scale.appText.withAlpha(127),
size: 48,
),
Text(
textAlign: TextAlign.center,
translate('chat.start_a_conversation'),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: scale.appText.withAlpha(127),
),
),
],
));
decoration: BoxDecoration(
color: scale.primaryScale.appBackground,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.diversity_3,
color: scale.primaryScale.subtleBorder,
size: 48,
),
Text(
textAlign: TextAlign.center,
translate('chat.start_a_conversation'),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: scale.primaryScale.subtleBorder,
),
),
],
),
);
}
}

View File

@ -1,3 +1,4 @@
export 'chat_component_widget.dart';
export 'empty_chat_widget.dart';
export 'new_chat_bottom_sheet.dart';
export 'no_conversation_widget.dart';

View File

@ -13,7 +13,7 @@ import '../../proto/proto.dart' as proto;
//////////////////////////////////////////////////
// Mutable state for per-account chat list
typedef ChatListCubitState = DHTShortArrayCubitState<proto.Chat>;
typedef ChatListCubitState = DHTShortArrayBusyState<proto.Chat>;
class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
with StateMapFollowable<ChatListCubitState, TypedKey, proto.Chat> {
@ -86,12 +86,14 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
// Nothing to do here
return;
}
break;
case proto.Chat_Kind.group:
if (c.group.localConversationRecordKey ==
contact.localConversationRecordKey) {
throw StateError('direct conversation record key should'
' not be used for group chats!');
}
break;
case proto.Chat_Kind.notSet:
throw StateError('unknown chat kind');
}

View File

@ -8,6 +8,7 @@ import 'package:veilid_support/veilid_support.dart';
import '../../contacts/contacts.dart';
import '../../proto/proto.dart' as proto;
import '../../proto/proto.dart';
import '../../theme/theme.dart';
import '../chat_list.dart';
@ -25,7 +26,7 @@ class ChatListWidget extends StatelessWidget {
}
List<proto.Chat> _itemFilter(IMap<proto.TypedKey, proto.Contact> contactMap,
IList<OnlineElementState<proto.Chat>> chatList, String filter) {
IList<DHTShortArrayElementState<Chat>> chatList, String filter) {
final lowerValue = filter.toLowerCase();
return chatList.map((x) => x.value).where((c) {
switch (c.whichKind()) {
@ -47,6 +48,7 @@ class ChatListWidget extends StatelessWidget {
}
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
final contactListV = context.watch<ContactListCubit>().state;
@ -81,8 +83,7 @@ class ChatListWidget extends StatelessWidget {
},
filter: (value) =>
_itemFilter(contactMap, chatList, value),
searchFieldPadding:
const EdgeInsets.fromLTRB(0, 0, 0, 4),
spaceBetweenSearchAndList: 4,
inputDecoration: InputDecoration(
labelText: translate('chat_list.search'),
),

View File

@ -29,7 +29,8 @@ class ChatSingleContactItemWidget extends StatelessWidget {
BuildContext context,
) {
final theme = Theme.of(context);
final scaleTheme = Theme.of(context).extension<ScaleTheme>()!;
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final activeChatCubit = context.watch<ActiveChatCubit>();
final selected = activeChatCubit.state == _localConversationRecordKey;
@ -43,24 +44,18 @@ class ChatSingleContactItemWidget extends StatelessWidget {
? proto.Availability.AVAILABILITY_UNSPECIFIED
: _contact.profile.availability;
final scaleTileTheme = scaleTheme.tileTheme(
disabled: _disabled,
selected: selected,
);
final avatar = AvatarWidget(
name: name,
size: 32,
borderColor: scaleTheme.config.useVisualIndicators
? scaleTheme.scheme.primaryScale.primaryText
: scaleTheme.scheme.primaryScale.subtleBorder,
size: 34,
borderColor: _disabled
? scale.grayScale.primaryText
: scale.secondaryScale.primaryText,
foregroundColor: _disabled
? scaleTheme.scheme.grayScale.primaryText
: scaleTheme.scheme.primaryScale.primaryText,
backgroundColor: _disabled
? scaleTheme.scheme.grayScale.primary
: scaleTheme.scheme.primaryScale.primary,
scaleConfig: scaleTheme.config,
? scale.grayScale.primaryText
: scale.secondaryScale.primaryText,
backgroundColor:
_disabled ? scale.grayScale.primary : scale.secondaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!,
);
@ -68,14 +63,11 @@ class ChatSingleContactItemWidget extends StatelessWidget {
key: ValueKey(_localConversationRecordKey),
disabled: _disabled,
selected: selected,
tileScale: ScaleKind.primary,
tileScale: ScaleKind.secondary,
title: title,
subtitle: subtitle,
leading: avatar,
trailing: AvailabilityWidget(
availability: availability,
color: scaleTileTheme.textColor,
).fit(fit: BoxFit.scaleDown),
trailing: AvailabilityWidget(availability: availability),
onTap: () {
singleFuture(activeChatCubit, () async {
activeChatCubit.setActiveChat(_localConversationRecordKey);
@ -83,7 +75,7 @@ class ChatSingleContactItemWidget extends StatelessWidget {
},
endActions: [
SliderTileAction(
//icon: Icons.delete,
icon: Icons.delete,
label: translate('button.delete'),
actionScale: ScaleKind.tertiary,
onPressed: (context) async {

View File

@ -27,7 +27,7 @@ typedef GetEncryptionKeyCallback = Future<SecretKey?> Function(
//////////////////////////////////////////////////
typedef ContactInvitiationListState
= DHTShortArrayCubitState<proto.ContactInvitationRecord>;
= DHTShortArrayBusyState<proto.ContactInvitationRecord>;
//////////////////////////////////////////////////
// Mutable state for per-account contact invitations
@ -59,7 +59,6 @@ class ContactInvitationListCubit
{required proto.Profile profile,
required EncryptionKeyType encryptionKeyType,
required String encryptionKey,
required String recipient,
required String message,
required Timestamp? expiration}) async {
final pool = DHTRecordPool.instance;
@ -155,8 +154,7 @@ class ContactInvitationListCubit
..localConversationRecordKey = localConversation.key.toProto()
..expiration = expiration?.toInt64() ?? Int64.ZERO
..invitation = signedContactInvitationBytes
..message = message
..recipient = recipient;
..message = message;
// Add ContactInvitationRecord to account's list
await operateWriteEventual((writer) async {

View File

@ -5,5 +5,5 @@ import 'package:veilid_support/veilid_support.dart';
class InvitationGeneratorCubit extends FutureCubit<(Uint8List, TypedKey)> {
InvitationGeneratorCubit(super.fut);
InvitationGeneratorCubit.value(super.state) : super.value();
InvitationGeneratorCubit.value(super.v) : super.value();
}

View File

@ -18,7 +18,7 @@ typedef WaitingInvitationsBlocMapState
class WaitingInvitationsBlocMapCubit extends BlocMapCubit<TypedKey,
AsyncValue<InvitationStatus>, WaitingInvitationCubit>
with
StateMapFollower<DHTShortArrayCubitState<proto.ContactInvitationRecord>,
StateMapFollower<DHTShortArrayBusyState<proto.ContactInvitationRecord>,
TypedKey, proto.ContactInvitationRecord> {
WaitingInvitationsBlocMapCubit(
{required AccountInfo accountInfo,

View File

@ -1,6 +1,5 @@
import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:basic_utils/basic_utils.dart';
import 'package:flutter/foundation.dart';
@ -21,13 +20,11 @@ import '../contact_invitation.dart';
class ContactInvitationDisplayDialog extends StatelessWidget {
const ContactInvitationDisplayDialog._({
required this.locator,
required this.recipient,
required this.message,
required this.fingerprint,
});
final Locator locator;
final String recipient;
final String message;
final String fingerprint;
@ -35,22 +32,18 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(StringProperty('recipient', recipient))
..add(StringProperty('message', message))
..add(DiagnosticsProperty<Locator>('locator', locator))
..add(StringProperty('fingerprint', fingerprint));
}
String makeTextInvite(String recipient, String message, Uint8List data) {
String makeTextInvite(String message, Uint8List data) {
final invite = StringUtils.addCharAtPosition(
base64UrlNoPadEncode(data), '\n', 40,
repeat: true);
final to = recipient.isNotEmpty
? '${translate('invitiation_dialog.to')}: $recipient\n'
: '';
final msg = message.isNotEmpty ? '$message\n' : '';
return '$to'
'$msg'
return '$msg'
'--- BEGIN VEILIDCHAT CONTACT INVITE ----\n'
'$invite\n'
'---- END VEILIDCHAT CONTACT INVITE -----\n'
@ -69,10 +62,6 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
final cardsize =
min<double>(MediaQuery.of(context).size.shortestSide - 48.0, 400);
final fingerprintText =
'${translate('create_invitation_dialog.fingerprint')}\n'
'$fingerprint';
return BlocListener<ContactInvitationListCubit,
ContactInvitiationListState>(
bloc: locator<ContactInvitationListCubit>(),
@ -121,21 +110,14 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
errorCorrectLevel:
QrErrorCorrectLevel.L)),
).expanded(),
if (recipient.isNotEmpty)
AutoSizeText(recipient,
softWrap: true,
maxLines: 2,
style: textTheme.labelLarge!
.copyWith(color: Colors.black))
.paddingAll(8),
if (message.isNotEmpty)
Text(message,
softWrap: true,
maxLines: 2,
style: textTheme.labelMedium!
.copyWith(color: Colors.black))
.paddingAll(8),
Text(fingerprintText,
Text(message,
softWrap: true,
style: textTheme.labelLarge!
.copyWith(color: Colors.black))
.paddingAll(8),
Text(
'${translate('create_invitation_dialog.fingerprint')}\n'
'$fingerprint',
softWrap: true,
textAlign: TextAlign.center,
style: textTheme.labelSmall!.copyWith(
@ -155,8 +137,7 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
text: translate('create_invitation_dialog'
'.invitation_copied'));
await Clipboard.setData(ClipboardData(
text: makeTextInvite(
recipient, message, data.$1)));
text: makeTextInvite(message, data.$1)));
},
).paddingAll(16),
]),
@ -167,7 +148,6 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
required BuildContext context,
required Locator locator,
required InvitationGeneratorCubit Function(BuildContext) create,
required String recipient,
required String message,
}) async {
final fingerprint =
@ -179,7 +159,6 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
create: create,
child: ContactInvitationDisplayDialog._(
locator: locator,
recipient: recipient,
message: message,
fingerprint: fingerprint,
)));

View File

@ -37,19 +37,14 @@ class ContactInvitationItemWidget extends StatelessWidget {
final tileDisabled =
disabled || context.watch<ContactInvitationListCubit>().isBusy;
var title = translate('contact_list.invitation');
if (contactInvitationRecord.recipient.isNotEmpty) {
title = contactInvitationRecord.recipient;
} else if (contactInvitationRecord.message.isNotEmpty) {
title = contactInvitationRecord.message;
}
return SliderTile(
key: ObjectKey(contactInvitationRecord),
disabled: tileDisabled,
selected: selected,
tileScale: ScaleKind.secondary,
title: title,
tileScale: ScaleKind.primary,
title: contactInvitationRecord.message.isEmpty
? translate('contact_list.invitation')
: contactInvitationRecord.message,
leading: const Icon(Icons.person_add),
onTap: () async {
if (!context.mounted) {
@ -58,7 +53,6 @@ class ContactInvitationItemWidget extends StatelessWidget {
await ContactInvitationDisplayDialog.show(
context: context,
locator: context.read,
recipient: contactInvitationRecord.recipient,
message: contactInvitationRecord.message,
create: (context) => InvitationGeneratorCubit.value((
Uint8List.fromList(contactInvitationRecord.invitation),
@ -68,7 +62,7 @@ class ContactInvitationItemWidget extends StatelessWidget {
},
endActions: [
SliderTileAction(
// icon: Icons.delete,
icon: Icons.delete,
label: translate('button.delete'),
actionScale: ScaleKind.tertiary,
onPressed: (context) async {

View File

@ -18,7 +18,7 @@ class CreateInvitationDialog extends StatefulWidget {
const CreateInvitationDialog._({required this.locator});
@override
State<CreateInvitationDialog> createState() => _CreateInvitationDialogState();
CreateInvitationDialogState createState() => CreateInvitationDialogState();
static Future<void> show(BuildContext context) async {
await StyledDialog.show<void>(
@ -36,9 +36,8 @@ class CreateInvitationDialog extends StatefulWidget {
}
}
class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
class CreateInvitationDialogState extends State<CreateInvitationDialog> {
late final TextEditingController _messageTextController;
late final TextEditingController _recipientTextController;
EncryptionKeyType _encryptionKeyType = EncryptionKeyType.none;
String _encryptionKey = '';
@ -52,7 +51,6 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
_messageTextController = TextEditingController(
text: translate('create_invitation_dialog.connect_with_me',
args: {'name': name}));
_recipientTextController = TextEditingController();
super.initState();
}
@ -156,7 +154,6 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
profile: profile,
encryptionKeyType: _encryptionKeyType,
encryptionKey: _encryptionKey,
recipient: _recipientTextController.text,
message: _messageTextController.text,
expiration: _expiration);
@ -165,7 +162,6 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
await ContactInvitationDisplayDialog.show(
context: context,
locator: widget.locator,
recipient: _recipientTextController.text,
message: _messageTextController.text,
create: (context) => InvitationGeneratorCubit(generator));
}
@ -180,7 +176,6 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
final theme = Theme.of(context);
//final scale = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme;
return ConstrainedBox(
constraints:
BoxConstraints(maxHeight: maxDialogHeight, maxWidth: maxDialogWidth),
@ -190,35 +185,19 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
autofocus: true,
controller: _recipientTextController,
onChanged: (value) {
setState(() {});
},
inputFormatters: [
LengthLimitingTextInputFormatter(128),
],
decoration: InputDecoration(
hintText:
translate('create_invitation_dialog.recipient_hint'),
labelText:
translate('create_invitation_dialog.recipient_name'),
helperText:
translate('create_invitation_dialog.recipient_helper')),
Text(
translate('create_invitation_dialog.message_to_contact'),
).paddingAll(8),
const SizedBox(height: 10),
TextField(
controller: _messageTextController,
inputFormatters: [
LengthLimitingTextInputFormatter(128),
],
decoration: InputDecoration(
hintText: translate('create_invitation_dialog.message_hint'),
labelText:
translate('create_invitation_dialog.message_label'),
helperText:
translate('create_invitation_dialog.message_helper')),
//border: const OutlineInputBorder(),
hintText:
translate('create_invitation_dialog.enter_message_hint'),
labelText: translate('create_invitation_dialog.message')),
).paddingAll(8),
const SizedBox(height: 10),
Text(translate('create_invitation_dialog.protect_this_invitation'),
@ -249,9 +228,7 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
Container(
padding: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: _recipientTextController.text.isNotEmpty
? _onGenerateButtonPressed
: null,
onPressed: _onGenerateButtonPressed,
child: Text(
translate('create_invitation_dialog.generate'),
).paddingAll(16),
@ -267,4 +244,11 @@ class _CreateInvitationDialogState extends State<CreateInvitationDialog> {
),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<TextEditingController>(
'messageTextController', _messageTextController));
}
}

View File

@ -0,0 +1,71 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../theme/theme.dart';
import 'create_invitation_dialog.dart';
import 'paste_invitation_dialog.dart';
import 'scan_invitation_dialog.dart';
Widget newContactBottomSheetBuilder(
BuildContext sheetContext, BuildContext context) {
final theme = Theme.of(sheetContext);
final scale = theme.extension<ScaleScheme>()!;
return KeyboardListener(
focusNode: FocusNode(),
onKeyEvent: (ke) {
if (ke.logicalKey == LogicalKeyboardKey.escape) {
Navigator.pop(sheetContext);
}
},
child: styledBottomSheet(
context: context,
title: translate('add_contact_sheet.new_contact'),
child: SizedBox(
height: 160,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(children: [
IconButton(
onPressed: () async {
Navigator.pop(sheetContext);
await CreateInvitationDialog.show(context);
},
iconSize: 64,
icon: const Icon(Icons.contact_page),
color: scale.primaryScale.hoverBorder),
Text(
translate('add_contact_sheet.create_invite'),
)
]),
Column(children: [
IconButton(
onPressed: () async {
Navigator.pop(sheetContext);
await ScanInvitationDialog.show(context);
},
iconSize: 64,
icon: const Icon(Icons.qr_code_scanner),
color: scale.primaryScale.hoverBorder),
Text(
translate('add_contact_sheet.scan_invite'),
)
]),
Column(children: [
IconButton(
onPressed: () async {
Navigator.pop(sheetContext);
await PasteInvitationDialog.show(context);
},
iconSize: 64,
icon: const Icon(Icons.paste),
color: scale.primaryScale.hoverBorder),
Text(
translate('add_contact_sheet.paste_invite'),
)
])
]).paddingAll(16))));
}

View File

@ -86,7 +86,7 @@ class ScannerOverlay extends CustomPainter {
final cutoutPath = Path()..addRect(scanWindow);
final backgroundPaint = Paint()
..color = Colors.black.withAlpha(127)
..color = Colors.black.withOpacity(0.5)
..style = PaintingStyle.fill
..blendMode = BlendMode.dstOut;
@ -188,7 +188,7 @@ class ScanInvitationDialogState extends State<ScanInvitationDialog> {
child: Container(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withAlpha(127),
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [

View File

@ -3,5 +3,6 @@ export 'contact_invitation_item_widget.dart';
export 'contact_invitation_list_widget.dart';
export 'create_invitation_dialog.dart';
export 'invitation_dialog.dart';
export 'new_contact_bottom_sheet.dart';
export 'paste_invitation_dialog.dart';
export 'scan_invitation_dialog.dart';

View File

@ -1,3 +1,2 @@
export 'cubits/cubits.dart';
export 'models/models.dart';
export 'views/views.dart';

View File

@ -8,7 +8,6 @@ import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart';
import '../../proto/proto.dart' as proto;
import '../../tools/tools.dart';
import '../models/models.dart';
//////////////////////////////////////////////////
// Mutable state for per-account contacts
@ -82,7 +81,9 @@ class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
Future<void> updateContactFields({
required TypedKey localConversationRecordKey,
required ContactSpec updatedContactSpec,
String? nickname,
String? notes,
bool? showAvailability,
}) async {
// Update contact's locally-modifiable fields
await operateWriteEventual((writer) async {
@ -91,7 +92,17 @@ class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
if (c != null &&
c.localConversationRecordKey.toVeilid() ==
localConversationRecordKey) {
final newContact = await updatedContactSpec.updateProto(c);
final newContact = c.deepCopy();
if (nickname != null) {
newContact.nickname = nickname;
}
if (notes != null) {
newContact.notes = notes;
}
if (showAvailability != null) {
newContact.showAvailability = showAvailability;
}
final updated = await writer.tryWriteItemProtobuf(
proto.Contact.fromBuffer, pos, newContact);
@ -149,14 +160,10 @@ class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
// Mark the conversation records for deletion
await DHTRecordPool.instance
.deleteRecord(deletedItem.localConversationRecordKey.toVeilid());
} on Exception catch (e) {
log.debug('error deleting local conversation record: $e', e);
}
try {
await DHTRecordPool.instance
.deleteRecord(deletedItem.remoteConversationRecordKey.toVeilid());
} on Exception catch (e) {
log.debug('error deleting remote conversation record: $e', e);
log.debug('error deleting conversation records: $e', e);
}
}
}

View File

@ -1,37 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:protobuf/protobuf.dart';
import '../../proto/proto.dart' as proto;
@immutable
class ContactSpec extends Equatable {
const ContactSpec({
required this.nickname,
required this.notes,
required this.showAvailability,
});
ContactSpec.fromProto(proto.Contact p)
: nickname = p.nickname,
notes = p.notes,
showAvailability = p.showAvailability;
Future<proto.Contact> updateProto(proto.Contact old) async {
final newProto = old.deepCopy()
..nickname = nickname
..notes = notes
..showAvailability = showAvailability;
return newProto;
}
////////////////////////////////////////////////////////////////////////////
final String nickname;
final String notes;
final bool showAvailability;
@override
List<Object?> get props => [nickname, notes, showAvailability];
}

View File

@ -1 +0,0 @@
export 'contact_spec.dart';

View File

@ -1,39 +1,34 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
class AvailabilityWidget extends StatelessWidget {
const AvailabilityWidget(
{required this.availability,
required this.color,
this.vertical = true,
this.size = 32,
this.iconSize = 32,
super.key});
static Widget availabilityIcon(proto.Availability availability, Color color,
{double size = 24}) {
late final Widget icon;
static Widget availabilityIcon(proto.Availability availability,
{double size = 32}) {
late final Widget iconData;
switch (availability) {
case proto.Availability.AVAILABILITY_AWAY:
icon = SvgPicture.asset('assets/images/toilet.svg',
width: size,
height: size,
colorFilter: ColorFilter.mode(color, BlendMode.srcATop));
iconData =
ImageIcon(const AssetImage('assets/images/toilet.png'), size: size);
case proto.Availability.AVAILABILITY_BUSY:
icon = Icon(Icons.event_busy, size: size);
iconData = Icon(Icons.event_busy, size: size);
case proto.Availability.AVAILABILITY_FREE:
icon = Icon(Icons.event_available, size: size);
iconData = Icon(Icons.event_available, size: size);
case proto.Availability.AVAILABILITY_OFFLINE:
icon = Icon(Icons.cloud_off, size: size);
iconData = Icon(Icons.cloud_off, size: size);
case proto.Availability.AVAILABILITY_UNSPECIFIED:
icon = Icon(Icons.question_mark, size: size);
iconData = Icon(Icons.question_mark, size: size);
}
return icon;
return iconData;
}
static String availabilityName(proto.Availability availability) {
@ -57,33 +52,31 @@ class AvailabilityWidget extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final textTheme = theme.textTheme;
// final scale = theme.extension<ScaleScheme>()!;
// final scaleConfig = theme.extension<ScaleConfig>()!;
final name = availabilityName(availability);
final icon = availabilityIcon(availability, color, size: size * 2 / 3);
final icon = availabilityIcon(availability, size: iconSize);
return vertical
? ConstrainedBox(
constraints: BoxConstraints.tightFor(width: size),
child: Column(mainAxisSize: MainAxisSize.min, children: [
icon,
Text(name, style: textTheme.labelSmall!.copyWith(color: color))
.fit(fit: BoxFit.scaleDown)
]))
: ConstrainedBox(
constraints: BoxConstraints.tightFor(height: size),
child: Row(mainAxisSize: MainAxisSize.min, children: [
icon,
Text(name, style: textTheme.labelLarge!.copyWith(color: color))
.paddingLTRB(size / 4, 0, 0, 0)
]));
? Column(
mainAxisSize: MainAxisSize.min,
//mainAxisAlignment: MainAxisAlignment.center,
children: [
icon,
Text(name, style: textTheme.labelSmall).paddingLTRB(0, 0, 0, 0)
])
: Row(mainAxisSize: MainAxisSize.min, children: [
icon,
Text(name, style: textTheme.labelSmall).paddingLTRB(8, 0, 0, 0)
]);
}
////////////////////////////////////////////////////////////////////////////
final proto.Availability availability;
final Color color;
final bool vertical;
final double size;
final double iconSize;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@ -92,7 +85,6 @@ class AvailabilityWidget extends StatelessWidget {
..add(
DiagnosticsProperty<proto.Availability>('availability', availability))
..add(DiagnosticsProperty<bool>('vertical', vertical))
..add(DoubleProperty('size', size))
..add(ColorProperty('color', color));
..add(DoubleProperty('iconSize', iconSize));
}
}

View File

@ -1,15 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../proto/proto.dart' as proto;
import '../../tools/tools.dart';
import '../contacts.dart';
class ContactDetailsWidget extends StatefulWidget {
const ContactDetailsWidget(
{required this.contact, this.onModifiedState, super.key});
const ContactDetailsWidget({required this.contact, super.key});
final proto.Contact contact;
@override
State<ContactDetailsWidget> createState() => _ContactDetailsWidgetState();
@ -17,14 +15,8 @@ class ContactDetailsWidget extends StatefulWidget {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty<proto.Contact>('contact', contact))
..add(ObjectFlagProperty<void Function(bool p1)?>.has(
'onModifiedState', onModifiedState));
properties.add(DiagnosticsProperty<proto.Contact>('contact', contact));
}
final proto.Contact contact;
final void Function(bool)? onModifiedState;
}
class _ContactDetailsWidgetState extends State<ContactDetailsWidget>
@ -32,21 +24,18 @@ class _ContactDetailsWidgetState extends State<ContactDetailsWidget>
@override
Widget build(BuildContext context) => SingleChildScrollView(
child: EditContactForm(
formKey: GlobalKey(),
contact: widget.contact,
submitText: translate('button.update'),
submitDisabledText: translate('button.waiting_for_network'),
onModifiedState: widget.onModifiedState,
onSubmit: (updatedContactSpec) async {
onSubmit: (fbs) async {
final contactList = context.read<ContactListCubit>();
try {
await contactList.updateContactFields(
localConversationRecordKey:
widget.contact.localConversationRecordKey.toVeilid(),
updatedContactSpec: updatedContactSpec);
} on Exception catch (e) {
log.debug('error updating contact: $e', e);
return false;
}
return true;
await contactList.updateContactFields(
localConversationRecordKey:
widget.contact.localConversationRecordKey.toVeilid(),
nickname: fbs.currentState
?.value[EditContactForm.formFieldNickname] as String,
notes: fbs.currentState?.value[EditContactForm.formFieldNotes]
as String,
showAvailability: fbs.currentState
?.value[EditContactForm.formFieldShowAvailability] as bool);
}));
}

View File

@ -40,7 +40,7 @@ class ContactItemWidget extends StatelessWidget {
size: 34,
borderColor: _disabled
? scale.grayScale.primaryText
: scale.primaryScale.subtleBorder,
: scale.primaryScale.primaryText,
foregroundColor: _disabled
? scale.grayScale.primaryText
: scale.primaryScale.primaryText,
@ -68,32 +68,20 @@ class ContactItemWidget extends StatelessWidget {
: () => singleFuture<void>((this, _kOnTap), () async {
await _onTap(_contact);
}),
startActions: [
endActions: [
if (_onDoubleTap != null)
SliderTileAction(
//icon: Icons.edit,
label: translate('button.chat'),
icon: Icons.edit,
label: translate('button.edit'),
actionScale: ScaleKind.secondary,
onPressed: (_context) =>
singleFuture<void>((this, _kOnTap), () async {
await _onDoubleTap(_contact);
}),
),
],
endActions: [
if (_onTap != null)
SliderTileAction(
//icon: Icons.edit,
label: translate('button.edit'),
actionScale: ScaleKind.secondary,
onPressed: (_context) =>
singleFuture<void>((this, _kOnTap), () async {
await _onTap(_contact);
}),
),
if (_onDelete != null)
SliderTileAction(
//icon: Icons.delete,
icon: Icons.delete,
label: translate('button.delete'),
actionScale: ScaleKind.tertiary,
onPressed: (_context) =>

View File

@ -17,25 +17,19 @@ import 'contact_item_widget.dart';
import 'empty_contact_list_widget.dart';
enum ContactsBrowserElementKind {
contact,
invitation,
contact,
}
class ContactsBrowserElement {
ContactsBrowserElement.contact(proto.Contact c)
: kind = ContactsBrowserElementKind.contact,
invitation = null,
contact = c;
ContactsBrowserElement.invitation(proto.ContactInvitationRecord i)
: kind = ContactsBrowserElementKind.invitation,
contact = null,
invitation = i;
String get sortKey => switch (kind) {
ContactsBrowserElementKind.contact => contact!.displayName,
ContactsBrowserElementKind.invitation =>
invitation!.recipient + invitation!.message
};
ContactsBrowserElement.contact(proto.Contact c)
: kind = ContactsBrowserElementKind.contact,
invitation = null,
contact = c;
final ContactsBrowserElementKind kind;
final proto.ContactInvitationRecord? invitation;
@ -45,14 +39,14 @@ class ContactsBrowserElement {
class ContactsBrowser extends StatefulWidget {
const ContactsBrowser(
{required this.onContactSelected,
required this.onStartChat,
required this.onChatStarted,
this.selectedContactRecordKey,
super.key});
@override
State<ContactsBrowser> createState() => _ContactsBrowserState();
final Future<void> Function(proto.Contact? contact) onContactSelected;
final Future<void> Function(proto.Contact contact) onStartChat;
final Future<void> Function(proto.Contact contact) onChatStarted;
final TypedKey? selectedContactRecordKey;
@override
@ -66,31 +60,36 @@ class ContactsBrowser extends StatefulWidget {
'onContactSelected', onContactSelected))
..add(
ObjectFlagProperty<Future<void> Function(proto.Contact contact)>.has(
'onStartChat', onStartChat));
'onChatStarted', onChatStarted));
}
}
class _ContactsBrowserState extends State<ContactsBrowser>
with SingleTickerProviderStateMixin {
Widget buildInvitationButton(BuildContext context) {
Widget buildInvitationBar(BuildContext context) {
final theme = Theme.of(context);
final scaleScheme = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final menuIconColor = scaleConfig.preferBorders
? scaleScheme.primaryScale.hoverBorder
: scaleScheme.primaryScale.hoverBorder;
? scale.primaryScale.hoverBorder
: scale.primaryScale.borderText;
final menuBackgroundColor = scaleConfig.preferBorders
? scaleScheme.primaryScale.activeElementBackground
: scaleScheme.primaryScale.activeElementBackground;
? scale.primaryScale.elementBackground
: scale.primaryScale.border;
// final menuHoverColor = scaleConfig.preferBorders
// ? scale.primaryScale.hoverElementBackground
// : scale.primaryScale.hoverBorder;
final menuBorderColor = scaleScheme.primaryScale.hoverBorder;
final menuBorderColor = scale.primaryScale.hoverBorder;
final menuParams = StarMenuParameters(
shape: MenuShape.linear,
shape: MenuShape.grid,
checkItemsScreenBoundaries: true,
centerOffset: const Offset(0, 64),
// backgroundParams:
// BackgroundParams(backgroundColor: theme.shadowColor.withAlpha(128)),
backgroundParams:
BackgroundParams(backgroundColor: theme.shadowColor.withAlpha(128)),
boundaryBackground: BoundaryBackground(
color: menuBackgroundColor,
decoration: ShapeDecoration(
@ -103,64 +102,91 @@ class _ContactsBrowserState extends State<ContactsBrowser>
borderRadius: BorderRadius.circular(
8 * scaleConfig.borderRadiusScale)))));
ElevatedButton makeMenuButton(
{required IconData iconData,
required String text,
required void Function()? onPressed}) =>
ElevatedButton.icon(
onPressed: onPressed,
icon: Icon(
iconData,
size: 32,
).paddingSTEB(0, 8, 0, 8),
label: Text(
text,
maxLines: 2,
textAlign: TextAlign.center,
).paddingSTEB(0, 8, 0, 8));
final inviteMenuItems = [
makeMenuButton(
iconData: Icons.paste,
text: translate('add_contact_sheet.paste_invite'),
final receiveInviteMenuItems = [
Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
onPressed: () async {
_invitationMenuController.closeMenu!();
await PasteInvitationDialog.show(context);
}),
makeMenuButton(
iconData: Icons.qr_code_scanner,
text: translate('add_contact_sheet.scan_invite'),
onPressed: () async {
_invitationMenuController.closeMenu!();
_receiveInviteMenuController.closeMenu!();
await ScanInvitationDialog.show(context);
}).paddingLTRB(0, 0, 0, 8),
makeMenuButton(
iconData: Icons.contact_page,
text: translate('add_contact_sheet.create_invite'),
},
iconSize: 32,
icon: Icon(
Icons.qr_code_scanner,
size: 32,
color: menuIconColor,
),
),
Text(translate('add_contact_sheet.scan_invite'),
maxLines: 2,
textAlign: TextAlign.center,
style: textTheme.labelSmall!.copyWith(color: menuIconColor))
]).paddingAll(4),
Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
onPressed: () async {
_invitationMenuController.closeMenu!();
await CreateInvitationDialog.show(context);
}).paddingLTRB(0, 0, 0, 8),
_receiveInviteMenuController.closeMenu!();
await PasteInvitationDialog.show(context);
},
iconSize: 32,
icon: Icon(
Icons.paste,
size: 32,
color: menuIconColor,
),
),
Text(translate('add_contact_sheet.paste_invite'),
maxLines: 2,
textAlign: TextAlign.center,
style: textTheme.labelSmall!.copyWith(color: menuIconColor))
]).paddingAll(4)
];
return StarMenu(
items: inviteMenuItems,
onItemTapped: (_index, controller) {
controller.closeMenu!();
},
controller: _invitationMenuController,
params: menuParams,
child: IconButton(
onPressed: () {},
iconSize: 24,
icon: Icon(Icons.person_add, color: menuIconColor),
tooltip: translate('add_contact_sheet.add_contact')),
);
return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
onPressed: () async {
await CreateInvitationDialog.show(context);
},
iconSize: 32,
icon: const Icon(Icons.contact_page),
color: scale.primaryScale.hoverBorder,
),
Text(translate('add_contact_sheet.create_invite'),
maxLines: 2,
textAlign: TextAlign.center,
style: textTheme.labelSmall!
.copyWith(color: scale.primaryScale.hoverBorder))
]),
StarMenu(
items: receiveInviteMenuItems,
onItemTapped: (_index, controller) {
controller.closeMenu!();
},
controller: _receiveInviteMenuController,
params: menuParams,
child: Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
onPressed: () {},
iconSize: 32,
icon: ImageIcon(
const AssetImage('assets/images/handshake.png'),
size: 32,
color: scale.primaryScale.hoverBorder,
)),
Text(translate('add_contact_sheet.receive_invite'),
maxLines: 2,
textAlign: TextAlign.center,
style: textTheme.labelSmall!
.copyWith(color: scale.primaryScale.hoverBorder))
]),
),
]).paddingAll(16);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!;
//final scaleConfig = theme.extension<ScaleConfig>()!;
@ -175,98 +201,108 @@ class _ContactsBrowserState extends State<ContactsBrowser>
final contactList =
ciState.state.asData?.value.map((x) => x.value).toIList();
final initialList = <ContactsBrowserElement>[];
if (contactList != null) {
initialList
.addAll(contactList.toList().map(ContactsBrowserElement.contact));
}
final expansionListData =
<ContactsBrowserElementKind, List<ContactsBrowserElement>>{};
if (contactInvitationRecordList.isNotEmpty) {
initialList.addAll(contactInvitationRecordList
.toList()
.map(ContactsBrowserElement.invitation));
expansionListData[ContactsBrowserElementKind.invitation] =
contactInvitationRecordList
.toList()
.map(ContactsBrowserElement.invitation)
.toList();
}
if (contactList != null) {
expansionListData[ContactsBrowserElementKind.contact] =
contactList.toList().map(ContactsBrowserElement.contact).toList();
}
initialList.sort((a, b) => a.sortKey.compareTo(b.sortKey));
return Column(children: [
SearchableList<ContactsBrowserElement>(
initialList: initialList,
itemBuilder: (element) {
buildInvitationBar(context),
SearchableList<ContactsBrowserElement>.expansion(
expansionListData: expansionListData,
expansionTitleBuilder: (k) {
final kind = k as ContactsBrowserElementKind;
late final String title;
switch (kind) {
case ContactsBrowserElementKind.contact:
title = translate('contacts_dialog.contacts');
case ContactsBrowserElementKind.invitation:
title = translate('contacts_dialog.invitations');
}
return Center(
child: Text(title, style: textTheme.titleSmall),
);
},
expansionInitiallyExpanded: (k) => true,
expansionListBuilder: (_index, element) {
switch (element.kind) {
case ContactsBrowserElementKind.contact:
final contact = element.contact!;
return ContactItemWidget(
contact: contact,
selected: widget.selectedContactRecordKey ==
contact.localConversationRecordKey.toVeilid(),
disabled: false,
onDoubleTap: _onTapContact,
onTap: _onStartChat,
onDelete: _onDeleteContact)
.paddingLTRB(0, 4, 0, 0);
case ContactsBrowserElementKind.invitation:
final invitation = element.invitation!;
return ContactInvitationItemWidget(
contactInvitationRecord: invitation, disabled: false)
.paddingLTRB(0, 4, 0, 0);
}
},
filterExpansionData: (value) {
final lowerValue = value.toLowerCase();
final filteredMap = {
for (final entry in expansionListData.entries)
entry.key: (expansionListData[entry.key] ?? []).where((element) {
switch (element.kind) {
case ContactsBrowserElementKind.contact:
final contact = element.contact!;
return ContactItemWidget(
contact: contact,
selected: widget.selectedContactRecordKey ==
contact.localConversationRecordKey.toVeilid(),
disabled: false,
onDoubleTap: _onStartChat,
onTap: _onSelectContact,
onDelete: _onDeleteContact)
.paddingLTRB(0, 4, 0, 0);
return contact.nickname
.toLowerCase()
.contains(lowerValue) ||
contact.profile.name
.toLowerCase()
.contains(lowerValue) ||
contact.profile.pronouns
.toLowerCase()
.contains(lowerValue);
case ContactsBrowserElementKind.invitation:
final invitation = element.invitation!;
return ContactInvitationItemWidget(
contactInvitationRecord: invitation,
disabled: false)
.paddingLTRB(0, 4, 0, 0);
return invitation.message
.toLowerCase()
.contains(lowerValue);
}
},
filter: (value) {
final lowerValue = value.toLowerCase();
final filtered = <ContactsBrowserElement>[];
for (final element in initialList) {
switch (element.kind) {
case ContactsBrowserElementKind.contact:
final contact = element.contact!;
if (contact.nickname.toLowerCase().contains(lowerValue) ||
contact.profile.name
.toLowerCase()
.contains(lowerValue) ||
contact.profile.pronouns
.toLowerCase()
.contains(lowerValue)) {
filtered.add(element);
}
case ContactsBrowserElementKind.invitation:
final invitation = element.invitation!;
if (invitation.message
.toLowerCase()
.contains(lowerValue) ||
invitation.recipient
.toLowerCase()
.contains(lowerValue)) {
filtered.add(element);
}
}
}
return filtered;
},
searchFieldHeight: 40,
listViewPadding: const EdgeInsets.fromLTRB(4, 0, 4, 4),
searchFieldPadding: const EdgeInsets.fromLTRB(4, 8, 4, 4),
emptyWidget: contactList == null
? waitingPage(
text: translate('contact_list.loading_contacts'))
: const EmptyContactListWidget(),
defaultSuffixIconColor: scale.primaryScale.border,
closeKeyboardWhenScrolling: true,
searchFieldEnabled: contactList != null,
inputDecoration:
InputDecoration(labelText: translate('contact_list.search')),
secondaryWidget:
buildInvitationButton(context).paddingLTRB(4, 0, 0, 0))
.expanded()
}).toList()
};
return filteredMap;
},
hideEmptyExpansionItems: true,
searchFieldHeight: 40,
listViewPadding: const EdgeInsets.all(4),
spaceBetweenSearchAndList: 4,
emptyWidget: contactList == null
? waitingPage(text: translate('contact_list.loading_contacts'))
: const EmptyContactListWidget(),
defaultSuffixIconColor: scale.primaryScale.border,
closeKeyboardWhenScrolling: true,
searchFieldEnabled: contactList != null,
inputDecoration:
InputDecoration(labelText: translate('contact_list.search')),
).expanded()
]);
}
Future<void> _onSelectContact(proto.Contact contact) async {
Future<void> _onTapContact(proto.Contact contact) async {
await widget.onContactSelected(contact);
}
Future<void> _onStartChat(proto.Contact contact) async {
await widget.onStartChat(contact);
await widget.onChatStarted(contact);
}
Future<void> _onDeleteContact(proto.Contact contact) async {
@ -286,5 +322,5 @@ class _ContactsBrowserState extends State<ContactsBrowser>
}
////////////////////////////////////////////////////////////////////////////
final _invitationMenuController = StarMenuController();
final _receiveInviteMenuController = StarMenuController();
}

View File

@ -0,0 +1,166 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:provider/provider.dart';
import '../../chat/chat.dart';
import '../../chat_list/chat_list.dart';
import '../../layout/layout.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import '../contacts.dart';
class ContactsDialog extends StatefulWidget {
const ContactsDialog._({required this.modalContext});
@override
State<ContactsDialog> createState() => _ContactsDialogState();
static Future<void> show(BuildContext modalContext) async {
await showDialog<void>(
context: modalContext,
barrierDismissible: false,
useRootNavigator: false,
builder: (context) => ContactsDialog._(modalContext: modalContext));
}
final BuildContext modalContext;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
.add(DiagnosticsProperty<BuildContext>('modalContext', modalContext));
}
}
class _ContactsDialogState extends State<ContactsDialog> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
// final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final appBarIconColor = scaleConfig.useVisualIndicators
? scale.secondaryScale.border
: scale.secondaryScale.borderText;
final enableSplit = !isMobileWidth(context);
final enableLeft = enableSplit || _selectedContact == null;
final enableRight = enableSplit || _selectedContact != null;
return SizedBox(
width: MediaQuery.of(context).size.width,
child: StyledScaffold(
appBar: DefaultAppBar(
title: Text(!enableSplit && enableRight
? translate('contacts_dialog.edit_contact')
: translate('contacts_dialog.contacts')),
leading: Navigator.canPop(context)
? IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (!enableSplit && enableRight) {
setState(() {
_selectedContact = null;
});
} else {
Navigator.pop(context);
}
},
)
: null,
actions: [
if (_selectedContact != null)
FittedBox(
fit: BoxFit.scaleDown,
child:
Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
icon: const Icon(Icons.chat_bubble),
tooltip: translate('contacts_dialog.new_chat'),
onPressed: () async {
await onChatStarted(_selectedContact!);
}),
Text(translate('contacts_dialog.new_chat'),
style: theme.textTheme.labelSmall!
.copyWith(color: appBarIconColor)),
])).paddingLTRB(8, 0, 8, 0),
if (enableSplit && _selectedContact != null)
FittedBox(
fit: BoxFit.scaleDown,
child:
Column(mainAxisSize: MainAxisSize.min, children: [
IconButton(
icon: const Icon(Icons.close),
tooltip:
translate('contacts_dialog.close_contact'),
onPressed: () async {
await onContactSelected(null);
}),
Text(translate('contacts_dialog.close_contact'),
style: theme.textTheme.labelSmall!
.copyWith(color: appBarIconColor)),
])).paddingLTRB(8, 0, 8, 0),
]),
body: LayoutBuilder(builder: (context, constraint) {
final maxWidth = constraint.maxWidth;
return ColoredBox(
color: scale.primaryScale.appBackground,
child: Row(children: [
Offstage(
offstage: !enableLeft,
child: SizedBox(
width: enableLeft && !enableRight
? maxWidth
: (maxWidth / 3).clamp(200, 500),
child: DecoratedBox(
decoration: BoxDecoration(
color: scale.primaryScale.subtleBackground),
child: ContactsBrowser(
selectedContactRecordKey: _selectedContact
?.localConversationRecordKey
.toVeilid(),
onContactSelected: onContactSelected,
onChatStarted: onChatStarted,
).paddingLTRB(8, 0, 8, 8)))),
if (enableRight)
if (_selectedContact == null)
const NoContactWidget().expanded()
else
ContactDetailsWidget(contact: _selectedContact!)
.paddingAll(8)
.expanded(),
]));
})));
}
Future<void> onContactSelected(proto.Contact? contact) async {
setState(() {
_selectedContact = contact;
});
}
Future<void> onChatStarted(proto.Contact contact) async {
final chatListCubit = context.read<ChatListCubit>();
await chatListCubit.getOrCreateChatSingleContact(contact: contact);
if (mounted) {
context
.read<ActiveChatCubit>()
.setActiveChat(contact.localConversationRecordKey.toVeilid());
Navigator.pop(context);
}
}
proto.Contact? _selectedContact;
}

View File

@ -1,162 +0,0 @@
import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:provider/provider.dart';
import '../../chat/chat.dart';
import '../../chat_list/chat_list.dart';
import '../../layout/layout.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import '../contacts.dart';
const _kDoBackArrow = 'doBackArrow';
class ContactsPage extends StatefulWidget {
const ContactsPage({super.key});
@override
State<ContactsPage> createState() => _ContactsPageState();
}
class _ContactsPageState extends State<ContactsPage> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scaleTheme = theme.extension<ScaleTheme>()!;
final appBarTheme = scaleTheme.appBarTheme();
final scaleScheme = theme.extension<ScaleScheme>()!;
final scale = scaleScheme.scale(ScaleKind.primary);
final enableSplit = !isMobileSize(context);
final enableLeft = enableSplit || _selectedContact == null;
final enableRight = enableSplit || _selectedContact != null;
return StyledScaffold(
appBar: DefaultAppBar(
title: Text(
!enableSplit && enableRight
? translate('contacts_dialog.edit_contact')
: translate('contacts_dialog.contacts'),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
singleFuture((this, _kDoBackArrow), () async {
final confirmed = await _onContactSelected(null);
if (!enableSplit && enableRight) {
} else {
if (confirmed) {
if (context.mounted) {
Navigator.pop(context);
}
}
}
});
},
),
actions: [
if (_selectedContact != null)
IconButton(
icon: const Icon(Icons.chat_bubble),
iconSize: 24,
color: appBarTheme.iconColor,
tooltip: translate('contacts_dialog.new_chat'),
onPressed: () async {
await _onChatStarted(_selectedContact!);
}).paddingLTRB(8, 0, 8, 0),
if (enableSplit && _selectedContact != null)
IconButton(
icon: const Icon(Icons.close),
iconSize: 24,
color: appBarTheme.iconColor,
tooltip: translate('contacts_dialog.close_contact'),
onPressed: () async {
await _onContactSelected(null);
}).paddingLTRB(8, 0, 8, 0),
]),
body: LayoutBuilder(builder: (context, constraint) {
final maxWidth = constraint.maxWidth;
return ColoredBox(
color: scale.appBackground,
child:
Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
Offstage(
offstage: !enableLeft,
child: SizedBox(
width: enableLeft && !enableRight
? maxWidth
: (maxWidth / 3).clamp(200, 500),
child: DecoratedBox(
decoration:
BoxDecoration(color: scale.subtleBackground),
child: ContactsBrowser(
selectedContactRecordKey: _selectedContact
?.localConversationRecordKey
.toVeilid(),
onContactSelected: _onContactSelected,
onStartChat: _onChatStarted,
).paddingLTRB(4, 0, 4, 8)))),
if (enableRight && enableLeft)
Container(
constraints:
const BoxConstraints(minWidth: 1, maxWidth: 1),
color: scale.subtleBorder),
if (enableRight)
if (_selectedContact == null)
const NoContactWidget().expanded()
else
ContactDetailsWidget(
contact: _selectedContact!,
onModifiedState: _onModifiedState)
.paddingLTRB(16, 16, 16, 16)
.expanded(),
]));
}));
}
void _onModifiedState(bool isModified) {
setState(() {
_isModified = isModified;
});
}
Future<bool> _onContactSelected(proto.Contact? contact) async {
if (contact != _selectedContact && _isModified) {
final ok = await showConfirmModal(
context: context,
title: translate('confirmation.discard_changes'),
text: translate('confirmation.are_you_sure_discard'));
if (!ok) {
return false;
}
}
setState(() {
_selectedContact = contact;
_isModified = false;
});
return true;
}
Future<void> _onChatStarted(proto.Contact contact) async {
final chatListCubit = context.read<ChatListCubit>();
await chatListCubit.getOrCreateChatSingleContact(contact: contact);
if (mounted) {
context
.read<ActiveChatCubit>()
.setActiveChat(contact.localConversationRecordKey.toVeilid());
Navigator.pop(context);
}
}
proto.Contact? _selectedContact;
bool _isModified = false;
}

View File

@ -1,4 +1,3 @@
import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -7,18 +6,13 @@ import 'package:flutter_translate/flutter_translate.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import '../models/contact_spec.dart';
import 'availability_widget.dart';
const _kDoSubmitEditContact = 'doSubmitEditContact';
class EditContactForm extends StatefulWidget {
const EditContactForm({
required this.formKey,
required this.contact,
required this.onSubmit,
required this.submitText,
required this.submitDisabledText,
this.onModifiedState,
this.onSubmit,
super.key,
});
@ -26,22 +20,19 @@ class EditContactForm extends StatefulWidget {
State createState() => _EditContactFormState();
final proto.Contact contact;
final String submitText;
final String submitDisabledText;
final Future<bool> Function(ContactSpec) onSubmit;
final void Function(bool)? onModifiedState;
final Future<void> Function(GlobalKey<FormBuilderState>)? onSubmit;
final GlobalKey<FormBuilderState> formKey;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(ObjectFlagProperty<Future<bool> Function(ContactSpec p1)>.has(
'onSubmit', onSubmit))
..add(ObjectFlagProperty<void Function(bool p1)?>.has(
'onModifiedState', onModifiedState))
..add(ObjectFlagProperty<
Future<void> Function(
GlobalKey<FormBuilderState> p1)?>.has('onSubmit', onSubmit))
..add(DiagnosticsProperty<proto.Contact>('contact', contact))
..add(StringProperty('submitText', submitText))
..add(StringProperty('submitDisabledText', submitDisabledText));
..add(
DiagnosticsProperty<GlobalKey<FormBuilderState>>('formKey', formKey));
}
static const String formFieldNickname = 'nickname';
@ -50,46 +41,17 @@ class EditContactForm extends StatefulWidget {
}
class _EditContactFormState extends State<EditContactForm> {
final _formKey = GlobalKey<FormBuilderState>();
@override
void initState() {
_savedValue = ContactSpec.fromProto(widget.contact);
_currentValueNickname = _savedValue.nickname;
super.initState();
}
ContactSpec _makeContactSpec() {
final nickname = _formKey.currentState!
.fields[EditContactForm.formFieldNickname]!.value as String;
final notes = _formKey
.currentState!.fields[EditContactForm.formFieldNotes]!.value as String;
final showAvailability = _formKey.currentState!
.fields[EditContactForm.formFieldShowAvailability]!.value as bool;
Widget _availabilityWidget(
BuildContext context, proto.Availability availability) =>
AvailabilityWidget(availability: availability);
return ContactSpec(
nickname: nickname, notes: notes, showAvailability: showAvailability);
}
// Check if everything is the same and update state
void _onChanged() {
final currentValue = _makeContactSpec();
_isModified = currentValue != _savedValue;
final onModifiedState = widget.onModifiedState;
if (onModifiedState != null) {
onModifiedState(_isModified);
}
}
Widget _availabilityWidget(proto.Availability availability, Color color) =>
AvailabilityWidget(
availability: availability,
color: color,
vertical: false,
);
Widget _editContactForm(BuildContext context) {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
@ -99,94 +61,74 @@ class _EditContactFormState extends State<EditContactForm> {
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
border = scale.primaryScale.elementBackground;
} else {
border = scale.primaryScale.subtleBorder;
border = scale.primaryScale.border;
}
return FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: _onChanged,
key: widget.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
styledCard(
context: context,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(children: [
const Spacer(),
AvatarWidget(
name: _currentValueNickname.isNotEmpty
? _currentValueNickname
: widget.contact.profile.name,
size: 128,
borderColor: border,
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!
.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16),
const Spacer()
]),
SelectableText(widget.contact.profile.name,
style: textTheme.bodyLarge)
.noEditDecoratorLabel(
context,
translate('contact_form.form_name'),
)
.paddingSymmetric(vertical: 4),
SelectableText(widget.contact.profile.pronouns,
style: textTheme.bodyLarge)
.noEditDecoratorLabel(
context,
translate('contact_form.form_pronouns'),
)
.paddingSymmetric(vertical: 4),
Row(mainAxisSize: MainAxisSize.min, children: [
_availabilityWidget(
widget.contact.profile.availability,
scale.primaryScale.appText),
SelectableText(widget.contact.profile.status,
style: textTheme.bodyMedium)
.paddingSymmetric(horizontal: 8)
])
.noEditDecoratorLabel(
context,
translate('contact_form.form_status'),
)
.paddingSymmetric(vertical: 4),
SelectableText(widget.contact.profile.about,
minLines: 1,
maxLines: 8,
style: textTheme.bodyMedium)
.noEditDecoratorLabel(
context,
translate('contact_form.form_about'),
)
.paddingSymmetric(vertical: 4),
SelectableText(
widget.contact.identityPublicKey.value
.toVeilid()
.toString(),
style: textTheme.bodyMedium!
.copyWith(fontFamily: 'Source Code Pro'))
.noEditDecoratorLabel(
context,
translate('contact_form.form_fingerprint'),
)
.paddingSymmetric(vertical: 4),
]).paddingAll(16))
.paddingLTRB(0, 0, 0, 16),
AvatarWidget(
name: widget.contact.profile.name,
size: 128,
borderColor: border,
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16),
SelectableText(widget.contact.profile.name,
style: textTheme.headlineMedium)
.noEditDecoratorLabel(
context,
translate('contact_form.form_name'),
scale: scale.secondaryScale,
)
.paddingSymmetric(vertical: 4),
SelectableText(widget.contact.profile.pronouns,
style: textTheme.headlineSmall)
.noEditDecoratorLabel(
context,
translate('contact_form.form_pronouns'),
scale: scale.secondaryScale,
)
.paddingSymmetric(vertical: 4),
Row(mainAxisSize: MainAxisSize.min, children: [
_availabilityWidget(context, widget.contact.profile.availability),
SelectableText(widget.contact.profile.status,
style: textTheme.bodyMedium)
.paddingSymmetric(horizontal: 8)
])
.noEditDecoratorLabel(
context,
translate('contact_form.form_status'),
scale: scale.secondaryScale,
)
.paddingSymmetric(vertical: 4),
SelectableText(widget.contact.profile.about,
minLines: 1, maxLines: 8, style: textTheme.bodyMedium)
.noEditDecoratorLabel(
context,
translate('contact_form.form_about'),
scale: scale.secondaryScale,
)
.paddingSymmetric(vertical: 4),
SelectableText(
widget.contact.identityPublicKey.value.toVeilid().toString(),
style: textTheme.labelMedium!
.copyWith(fontFamily: 'Source Code Pro'))
.noEditDecoratorLabel(
context,
translate('contact_form.form_fingerprint'),
scale: scale.secondaryScale,
)
.paddingSymmetric(vertical: 4),
Divider(color: border).paddingLTRB(8, 0, 8, 8),
FormBuilderTextField(
//autofocus: true,
name: EditContactForm.formFieldNickname,
initialValue: _currentValueNickname,
onChanged: (x) {
setState(() {
_currentValueNickname = x ?? '';
});
},
initialValue: widget.contact.nickname,
decoration: InputDecoration(
labelText: translate('contact_form.form_nickname')),
maxLength: 64,
@ -194,13 +136,14 @@ class _EditContactFormState extends State<EditContactForm> {
),
FormBuilderCheckbox(
name: EditContactForm.formFieldShowAvailability,
initialValue: _savedValue.showAvailability,
initialValue: widget.contact.showAvailability,
side: BorderSide(color: scale.primaryScale.border, width: 2),
title: Text(translate('contact_form.form_show_availability'),
style: textTheme.labelMedium),
),
FormBuilderTextField(
name: EditContactForm.formFieldNotes,
initialValue: _savedValue.notes,
initialValue: widget.contact.notes,
minLines: 1,
maxLines: 8,
maxLength: 1024,
@ -209,38 +152,24 @@ class _EditContactFormState extends State<EditContactForm> {
textInputAction: TextInputAction.newline,
),
ElevatedButton(
onPressed: _isModified ? _doSubmit : null,
onPressed: widget.onSubmit == null
? null
: () async {
if (widget.formKey.currentState?.saveAndValidate() ??
false) {
await widget.onSubmit!(widget.formKey);
}
},
child: Row(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.check, size: 16).paddingLTRB(0, 0, 4, 0),
Text(widget.submitText).paddingLTRB(0, 0, 4, 0)
Text((widget.onSubmit == null)
? translate('contact_form.save')
: translate('contact_form.save'))
.paddingLTRB(0, 0, 4, 0)
]),
).paddingSymmetric(vertical: 4).alignAtCenter(),
).paddingSymmetric(vertical: 4).alignAtCenterRight(),
],
),
);
}
void _doSubmit() {
final onSubmit = widget.onSubmit;
if (_formKey.currentState?.saveAndValidate() ?? false) {
singleFuture((this, _kDoSubmitEditContact), () async {
final updatedContactSpec = _makeContactSpec();
final saved = await onSubmit(updatedContactSpec);
if (saved) {
setState(() {
_savedValue = updatedContactSpec;
});
_onChanged();
}
});
}
}
@override
Widget build(BuildContext context) => _editContactForm(context);
///////////////////////////////////////////////////////////////////////////
late ContactSpec _savedValue;
late String _currentValueNickname;
bool _isModified = false;
}

View File

@ -15,7 +15,8 @@ class EmptyContactListWidget extends StatelessWidget {
final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!;
return Column(
return Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
@ -34,6 +35,6 @@ class EmptyContactListWidget extends StatelessWidget {
),
),
],
);
));
}
}

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../theme/models/scale_theme/scale_scheme.dart';
import '../../theme/models/scale_scheme.dart';
class NoContactWidget extends StatelessWidget {
const NoContactWidget({super.key});

View File

@ -2,7 +2,7 @@ export 'availability_widget.dart';
export 'contact_details_widget.dart';
export 'contact_item_widget.dart';
export 'contacts_browser.dart';
export 'contacts_page.dart';
export 'contacts_dialog.dart';
export 'edit_contact_form.dart';
export 'empty_contact_list_widget.dart';
export 'no_contact_widget.dart';

View File

@ -50,7 +50,7 @@ typedef ActiveConversationsBlocMapState
// We currently only build the cubits for the chats that are active, not
// archived chats or contacts that are not actively in a chat.
//
// TODO(crioux): Polling contacts for new inactive chats is yet to be done
// TODO: Polling contacts for new inactive chats is yet to be done
//
class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
AsyncValue<ActiveConversationState>, ActiveConversationCubit>
@ -166,6 +166,7 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
localConversationRecordKey: localConversationRecordKey,
remoteConversationRecordKey: remoteConversationRecordKey);
break;
case proto.Chat_Kind.group:
break;
}

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:veilid_support/veilid_support.dart';
import 'account_manager/account_manager.dart';
@ -9,8 +8,6 @@ import 'app.dart';
import 'tools/tools.dart';
import 'veilid_processor/veilid_processor.dart';
List<String> rootAssets = [];
class VeilidChatGlobalInit {
VeilidChatGlobalInit._();
@ -31,22 +28,14 @@ class VeilidChatGlobalInit {
logger: (message) => log.debug('DHTRecordPool: $message'));
}
// Initialize repositories
// Initialize repositories
Future<void> _initializeRepositories() async {
await AccountRepository.instance.init();
}
// Initialize asset manifest
static Future<void> loadAssetManifest() async {
final assetManifest = await AssetManifest.loadFromAssetBundle(rootBundle);
rootAssets = assetManifest.listAssets();
}
static Future<VeilidChatGlobalInit> initialize() async {
final veilidChatGlobalInit = VeilidChatGlobalInit._();
await loadAssetManifest();
log.info('Initializing Veilid');
await veilidChatGlobalInit._initializeVeilid();
log.info('Initializing Repositories');

Some files were not shown because too many files have changed in this diff Show More