56
.github/workflows/wasm_test.yml.disabled
vendored
|
@ -1,56 +0,0 @@
|
|||
---
|
||||
name: WASM Testing
|
||||
|
||||
# Trigger the workflow on push or pull request
|
||||
"on": [push, pull_request]
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
wasm_test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# - name: Check arch
|
||||
# run: |
|
||||
# uname -a
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.5
|
||||
with:
|
||||
version: "v0.4.2"
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Install wasm-pack
|
||||
run: cargo install wasm-pack
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
scripts/install_ubuntu_dependencies.sh
|
||||
# https://github.com/browser-actions/setup-chrome
|
||||
- name: Install Chrome Headless
|
||||
uses: browser-actions/setup-chrome@latest
|
||||
with:
|
||||
chrome-version: latest
|
||||
# https://github.com/marketplace/actions/setup-chromedriver
|
||||
- uses: nanasess/setup-chromedriver@v2
|
||||
# with:
|
||||
# Optional: do not specify to match Chrome's version
|
||||
# chromedriver-version: '88.0.4324.96'
|
||||
|
||||
# - run: make webui
|
||||
- name: "Run wasm-pack test"
|
||||
# https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/browsers.html
|
||||
run: |
|
||||
rustup target add wasm32-unknown-unknown
|
||||
make webui/test
|
||||
|
||||
- name: "Run webdriver tests"
|
||||
run: |
|
||||
chromedriver &
|
||||
cargo test -p kanidmd_testkit --features webdriver test_webdriver
|
||||
env:
|
||||
DISPLAY: ":99"
|
1
.gitignore
vendored
|
@ -19,7 +19,6 @@ tools/orca/example_profiles/small/orca-edited.toml
|
|||
*.d.ts
|
||||
|
||||
server/web_ui/*/pkg/*.js
|
||||
server/web_ui/*/pkg/*.wasm
|
||||
|
||||
# kanidm simple packaging
|
||||
deployment-config/
|
||||
|
|
851
Cargo.lock
generated
20
Cargo.toml
|
@ -23,10 +23,6 @@ members = [
|
|||
"unix_integration/nss_kanidm",
|
||||
"unix_integration/pam_kanidm",
|
||||
"unix_integration/resolver",
|
||||
"server/web_ui/admin",
|
||||
"server/web_ui/login_flows",
|
||||
"server/web_ui/user",
|
||||
"server/web_ui/shared",
|
||||
"server/daemon",
|
||||
"server/lib",
|
||||
"server/lib-macros",
|
||||
|
@ -169,7 +165,6 @@ compact_jwt = { version = "^0.4.2", default-features = false }
|
|||
concread = "^0.5.3"
|
||||
cron = "0.12.1"
|
||||
crossbeam = "0.8.4"
|
||||
criterion = "^0.5.1"
|
||||
csv = "1.3.0"
|
||||
dialoguer = "0.10.4"
|
||||
dhat = "0.3.3"
|
||||
|
@ -178,11 +173,8 @@ fernet = "^0.2.1"
|
|||
filetime = "^0.2.24"
|
||||
fs4 = "^0.8.3"
|
||||
futures = "^0.3.31"
|
||||
futures-concurrency = "^3.1.0"
|
||||
futures-util = { version = "^0.3.30", features = ["sink"] }
|
||||
gix = { version = "0.64.0", default-features = false }
|
||||
gloo = "^0.8.1"
|
||||
gloo-utils = "0.2.0"
|
||||
hashbrown = { version = "0.14.3", features = ["serde", "inline-more", "ahash"] }
|
||||
hex = "^0.4.3"
|
||||
http = "1.1.0"
|
||||
|
@ -198,7 +190,6 @@ image = { version = "0.24.9", default-features = false, features = [
|
|||
] }
|
||||
itertools = "0.13.0"
|
||||
enum-iterator = "2.1.0"
|
||||
js-sys = "^0.3.70"
|
||||
kanidmd_web_ui_shared = { path = "./server/web_ui/shared" }
|
||||
# REMOVE this
|
||||
lazy_static = "^1.5.0"
|
||||
|
@ -247,7 +238,6 @@ reqwest = { version = "0.12.8", default-features = false, features = [
|
|||
"gzip",
|
||||
"rustls-tls-native-roots",
|
||||
] }
|
||||
rpassword = "^7.3.1"
|
||||
rusqlite = { version = "^0.28.0", features = ["array", "bundled"] }
|
||||
rustls = { version = "0.23.13", default-features = false, features = [
|
||||
"aws_lc_rs",
|
||||
|
@ -259,7 +249,6 @@ serde = "^1.0.210"
|
|||
serde_cbor = { version = "0.12.0-dev", package = "serde_cbor_2" }
|
||||
serde_json = "^1.0.132"
|
||||
serde_urlencoded = "^0.7.1"
|
||||
serde-wasm-bindgen = "0.5"
|
||||
serde_with = "3.11.0"
|
||||
sha-crypt = "0.5.0"
|
||||
sha2 = "0.10.8"
|
||||
|
@ -283,7 +272,6 @@ tracing = { version = "^0.1.40", features = [
|
|||
"max_level_trace",
|
||||
"release_max_level_debug",
|
||||
] }
|
||||
# tracing = { version = "^0.1.37" }
|
||||
tracing-subscriber = { version = "^0.3.18", features = ["env-filter"] }
|
||||
tracing-forest = "^0.1.6"
|
||||
|
||||
|
@ -293,10 +281,6 @@ utoipa = { version = "4.2.0", features = ["url", "uuid"] }
|
|||
utoipa-swagger-ui = "6.0.0"
|
||||
uuid = "^1.11.0"
|
||||
|
||||
wasm-bindgen = "^0.2.95"
|
||||
wasm-bindgen-futures = "^0.4.45"
|
||||
wasm-bindgen-test = "0.3.45"
|
||||
|
||||
webauthn-authenticator-rs = { version = "0.5.0", features = [
|
||||
"softpasskey",
|
||||
"softtoken",
|
||||
|
@ -306,14 +290,12 @@ webauthn-rs = { version = "0.5.0", features = ["preview-features"] }
|
|||
webauthn-rs-core = "0.5.0"
|
||||
webauthn-rs-proto = "0.5.0"
|
||||
|
||||
web-sys = "^0.3.72"
|
||||
whoami = "^1.5.2"
|
||||
walkdir = "2"
|
||||
|
||||
x509-cert = "0.2.5"
|
||||
|
||||
yew = "^0.20.0"
|
||||
yew-router = "^0.17.0"
|
||||
zxcvbn = "^2.2.2"
|
||||
|
||||
nonempty = "0.8.1"
|
||||
|
||||
|
|
8
Makefile
|
@ -316,14 +316,6 @@ cert/clean:
|
|||
rm -f /tmp/kanidm/ca.txt*
|
||||
rm -f /tmp/kanidm/ca.{cnf,srl,srl.old}
|
||||
|
||||
.PHONY: webui
|
||||
webui: ## Build the WASM web frontend
|
||||
cd server/web_ui && ./build_wasm.sh
|
||||
|
||||
.PHONY: webui/test
|
||||
webui/test: ## Run wasm-pack test
|
||||
cd server/web_ui/shared/ && wasm-pack test --headless --chrome --mode no-install
|
||||
|
||||
.PHONY: rust/coverage
|
||||
coverage/test: ## Run coverage tests
|
||||
coverage/test:
|
||||
|
|
|
@ -114,21 +114,3 @@ When a service like sudo, sshd, su, etc. wants to authenticate someone, it opens
|
|||
that service, then performs authentication according to the modules defined in the pam.d config. For
|
||||
example, if you run `ls -al /etc/pam.d /usr/etc/pam.d` in SUSE, you can see the services and their
|
||||
respective pam.d config.
|
||||
|
||||
## Troubleshooting builds
|
||||
|
||||
### WASM Build failures due to "Error: Not able to find or install a local wasm-bindgen."
|
||||
|
||||
This seems to relate to a version mismatch error in `wasm-pack` as seen in
|
||||
[this thread in the wasm-pack repository](https://github.com/rustwasm/wasm-pack/issues/1138).
|
||||
|
||||
Try reinstalling `wasm-bindgen-cli` by running the following (the `--force` is important):
|
||||
|
||||
```shell
|
||||
cargo install --force wasm-bindgen-cli
|
||||
```
|
||||
|
||||
Or reinstalling `wasm-pack` similarly.
|
||||
|
||||
If that doesn't work, try running the build with the `RUST_LOG=debug` environment variable to
|
||||
investigate further.
|
||||
|
|
|
@ -98,9 +98,6 @@ git and compiler tools. You should install this first.
|
|||
|
||||
You will need [rustup](https://rustup.rs/) to install a Rust toolchain.
|
||||
|
||||
To build the Web UI you'll need [wasm-pack](https://rustwasm.github.io/wasm-pack/)
|
||||
(`cargo install wasm-pack`).
|
||||
|
||||
### SUSE / OpenSUSE
|
||||
|
||||
You will need to install rustup and our build dependencies with:
|
||||
|
@ -326,31 +323,6 @@ For example, this will set the CPU flags to "none" and the location for the Web
|
|||
KANIDM_BUILD_PROFILE=release_linux cargo build --release --bin kanidmd
|
||||
```
|
||||
|
||||
### Building the Web UI
|
||||
|
||||
> [!NOTE:]
|
||||
>
|
||||
> There is a pre-packaged version of the Web UI at `/server/web_ui/pkg/`, which can be used
|
||||
> directly. This means you don't need to build the Web UI yourself.
|
||||
|
||||
The Web UI uses Rust WebAssembly rather than Javascript. To build this you need to set up the
|
||||
environment:
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
Then you are able to build the UI:
|
||||
|
||||
```bash
|
||||
cd server/web_ui/
|
||||
./build_wasm_dev.sh
|
||||
```
|
||||
|
||||
To build for release, run `build_wasm.sh`, or `make webui` from the project root.
|
||||
|
||||
The "developer" profile for kanidmd will automatically use the pkg output in this folder.
|
||||
|
||||
### Development Server for Interactive Testing
|
||||
|
||||
Especially if you wish to develop the WebUI then the ability to run the server from the source tree
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
cargo install cargo-audit
|
||||
cargo install cargo-outdated
|
||||
cargo install cargo-udeps
|
||||
cargo install wasm-bindgen-cli
|
||||
```
|
||||
|
||||
## Pre Release Check List
|
||||
|
@ -34,7 +33,6 @@ cargo install wasm-bindgen-cli
|
|||
|
||||
### Administration
|
||||
|
||||
- [ ] build wasm components with release profile
|
||||
- [ ] Update `RELEASE_NOTES.md`
|
||||
- [ ] Update `README.md`
|
||||
- [ ] cargo test
|
||||
|
@ -70,7 +68,7 @@ cargo install wasm-bindgen-cli
|
|||
|
||||
## Final Release Check List
|
||||
|
||||
### Git Management
|
||||
### Git Management Part Deux
|
||||
|
||||
- [ ] git checkout 1.1.x
|
||||
- [ ] git pull origin 1.1.x
|
||||
|
|
|
@ -41,5 +41,4 @@ tokio = { workspace = true, features = [
|
|||
toml = { workspace = true }
|
||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
webauthn-rs-proto = { workspace = true, features = ["wasm"] }
|
||||
# hyper = { workspace = true }
|
||||
webauthn-rs-proto = { workspace = true }
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
web_ui_pkg_path = "/pkg"
|
||||
htmx_ui_pkg_path = "/hpkg"
|
||||
# Don't set the cpu_flags to autodetect for this platform
|
||||
# cpu_flags = "none"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
web_ui_pkg_path = "../web_ui/pkg"
|
||||
htmx_ui_pkg_path = "../core/static"
|
||||
# Set to native for developer machines.
|
||||
cpu_flags = "native"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
web_ui_pkg_path = "/usr/share/kanidm/ui/pkg"
|
||||
htmx_ui_pkg_path = "/usr/share/kanidm/ui/hpkg"
|
||||
# Don't set the value for autodetect
|
||||
# cpu_flags = "none"
|
||||
|
|
|
@ -54,7 +54,6 @@ impl std::fmt::Display for CpuOptLevel {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ProfileConfig {
|
||||
web_ui_pkg_path: String,
|
||||
htmx_ui_pkg_path: String,
|
||||
#[serde(default)]
|
||||
cpu_flags: CpuOptLevel,
|
||||
|
@ -127,10 +126,6 @@ pub fn apply_profile() {
|
|||
}
|
||||
println!("cargo:rustc-env=KANIDM_PROFILE_NAME={}", profile);
|
||||
println!("cargo:rustc-env=KANIDM_CPU_FLAGS={}", profile_cfg.cpu_flags);
|
||||
println!(
|
||||
"cargo:rustc-env=KANIDM_WEB_UI_PKG_PATH={}",
|
||||
profile_cfg.web_ui_pkg_path
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=KANIDM_HTMX_UI_PKG_PATH={}",
|
||||
profile_cfg.htmx_ui_pkg_path
|
||||
|
|
|
@ -28,7 +28,6 @@ opentelemetry-otlp = { workspace = true, default-features = false, features = [
|
|||
"grpc-tonic",
|
||||
] }
|
||||
opentelemetry_sdk = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tracing = { workspace = true, features = ["attributes"] }
|
||||
tracing-forest = { workspace = true, features = [
|
||||
|
@ -39,4 +38,3 @@ tracing-forest = { workspace = true, features = [
|
|||
] }
|
||||
tracing-opentelemetry = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
uuid = { workspace = true, features = ["v4"] }
|
||||
|
|
|
@ -16,10 +16,8 @@ test = true
|
|||
doctest = true
|
||||
|
||||
[features]
|
||||
# default = ["dev-oauth2-device-flow"]
|
||||
wasm = ["webauthn-rs-proto/wasm"]
|
||||
default = []
|
||||
test = []
|
||||
|
||||
dev-oauth2-device-flow = []
|
||||
|
||||
[dependencies]
|
||||
|
@ -33,7 +31,6 @@ serde_json = { workspace = true }
|
|||
serde_with = { workspace = true, features = ["time_0_3", "base64", "hex"] }
|
||||
smartstring = { workspace = true, features = ["serde"] }
|
||||
time = { workspace = true, features = ["serde", "std"] }
|
||||
tracing = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
urlencoding = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
|
|
|
@ -9,11 +9,6 @@ if [ -z "$(which cargo)" ]; then
|
|||
ERROR=1
|
||||
fi
|
||||
|
||||
if [ -z "$(which wasm-pack)" ]; then
|
||||
echo "You don't have wasm-pack installed! Installing it now..."
|
||||
cargo install wasm-pack
|
||||
fi
|
||||
|
||||
if [ $ERROR -eq 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -9,18 +9,18 @@ else
|
|||
fi
|
||||
|
||||
${SUDOCMD} apt-get update &&
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g-dev \
|
||||
libudev-dev \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
curl \
|
||||
rsync \
|
||||
git \
|
||||
cmake \
|
||||
build-essential \
|
||||
jq \
|
||||
tpm-udev
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g-dev \
|
||||
libudev-dev \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
curl \
|
||||
rsync \
|
||||
git \
|
||||
cmake \
|
||||
build-essential \
|
||||
jq \
|
||||
tpm-udev
|
||||
|
||||
if [ -z "${PACKAGING}" ]; then
|
||||
PACKAGING=0
|
||||
|
@ -31,17 +31,18 @@ if [ "${PACKAGING}" -eq 1 ]; then
|
|||
# This works in Debian, but not in Ubuntu because they do multiarch weird.
|
||||
# It would be too invasive to config a daily driver Ubuntu install for multiarch,
|
||||
# so instead we don't, and just warn.
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/os-release
|
||||
if [[ "$ID" == "ubuntu" ]]; then
|
||||
2>&1 echo "You're running Ubuntu, so we're skipping enabling multiarch for you because it would be too invasive. You won't be able to build valid debs for other than your native architecture."
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g \
|
||||
libssl3
|
||||
echo 2>&1 "You're running Ubuntu, so we're skipping enabling multiarch for you because it would be too invasive. You won't be able to build valid debs for other than your native architecture."
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g \
|
||||
libssl3
|
||||
elif [[ "$ID" == "debian" ]]; then
|
||||
${SUDOCMD} dpkg --add-architecture arm64 && ${SUDOCMD} apt-get update
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g:{amd64,arm64} \
|
||||
libssl3:{amd64,arm64}
|
||||
${SUDOCMD} dpkg --add-architecture arm64 && ${SUDOCMD} apt-get update
|
||||
${SUDOCMD} apt-get install -y \
|
||||
libpam0g:{amd64,arm64} \
|
||||
libssl3:{amd64,arm64}
|
||||
fi
|
||||
export INSTALL_RUST=1
|
||||
fi
|
||||
|
@ -71,14 +72,6 @@ if [ -z "$(which cargo)" ]; then
|
|||
ERROR=1
|
||||
fi
|
||||
|
||||
if [ $ERROR -eq 0 ] && [ -z "$(which wasm-pack)" ]; then
|
||||
echo "You don't have wasm-pack installed! Installing it now..."
|
||||
cargo install wasm-pack
|
||||
fi
|
||||
if [ $ERROR -eq 0 ] && [ -z "$(which wasm-bindgen)" ]; then
|
||||
echo "You don't have wasm-bindgen installed! Installing it now..."
|
||||
cargo install -f wasm-bindgen-cli
|
||||
fi
|
||||
if [ $ERROR -eq 0 ] && [ -z "$(which cross)" ]; then
|
||||
echo "You don't have cross installed! Installing it now..."
|
||||
cargo install -f cross
|
||||
|
@ -88,7 +81,6 @@ if [ $ERROR -eq 0 ] && [ -z "$(which cargo-deb)" ]; then
|
|||
cargo install -f cargo-deb
|
||||
fi
|
||||
|
||||
|
||||
if [ $ERROR -eq 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -38,13 +38,6 @@ COPY . /usr/src/kanidm
|
|||
|
||||
# ======================
|
||||
|
||||
# WORKDIR /usr/src/kanidm/server/web_ui
|
||||
# # This can't be used in the wasm build for now.
|
||||
# # ENV RUSTFLAGS="-Clinker=clang"
|
||||
# RUN ./build_wasm.sh
|
||||
|
||||
# ======================
|
||||
|
||||
WORKDIR /usr/src/kanidm/kanidmd/daemon
|
||||
|
||||
# Exports don't persist through RUN statements.
|
||||
|
@ -72,7 +65,6 @@ RUN \
|
|||
pam
|
||||
|
||||
COPY --from=builder /usr/src/kanidm/target/release/kanidmd /sbin/
|
||||
COPY --from=builder /usr/src/kanidm/server/web_ui/pkg /pkg
|
||||
COPY --from=builder /usr/src/kanidm/server/core/static /hpkg
|
||||
RUN chmod +x /sbin/kanidmd
|
||||
|
||||
|
|
|
@ -16,19 +16,17 @@ test = true
|
|||
doctest = false
|
||||
|
||||
[features]
|
||||
default = ["ui_htmx"]
|
||||
ui_htmx = []
|
||||
default = []
|
||||
dev-oauth2-device-flow = []
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
askama = { workspace = true, features = ["with-axum"] }
|
||||
askama_axum = { workspace = true }
|
||||
axum = { workspace = true }
|
||||
axum-htmx = { workspace = true }
|
||||
axum-extra = { version = "0.9.4", features = ["cookie"] }
|
||||
axum-macros = "0.4.1"
|
||||
axum-server = { version = "0.7.1", features = ["tls-openssl"] }
|
||||
axum-server = { version = "0.7.1", default-features = false }
|
||||
bytes = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
compact_jwt = { workspace = true }
|
||||
|
@ -36,7 +34,6 @@ cron = { workspace = true }
|
|||
filetime = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
hyper = { workspace = true }
|
||||
hyper-util = { workspace = true }
|
||||
kanidm_proto = { workspace = true }
|
||||
|
@ -50,7 +47,6 @@ openssl = { workspace = true }
|
|||
opentelemetry = { workspace = true, features = ["logs"] }
|
||||
# opentelemetry_api = { workspace = true, features = ["logs"] }
|
||||
qrcode = { workspace = true, features = ["svg"] }
|
||||
rand = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
@ -71,8 +67,6 @@ tower-http = { version = "0.6.1", features = [
|
|||
"uuid",
|
||||
] }
|
||||
tracing = { workspace = true, features = ["attributes"] }
|
||||
tracing-subscriber = { workspace = true, features = ["time", "json"] }
|
||||
urlencoding = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
||||
utoipa = { workspace = true, features = [
|
||||
|
|
|
@ -12,7 +12,6 @@ use time::OffsetDateTime;
|
|||
use tracing::{info, instrument, trace};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
use kanidmd_lib::{
|
||||
event::{CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent},
|
||||
filter::{Filter, FilterInvalid},
|
||||
|
|
|
@ -266,7 +266,6 @@ impl ServerConfig {
|
|||
"KANIDM_PKG_VERSION",
|
||||
"KANIDM_PRE_RELEASE",
|
||||
"KANIDM_PROFILE_NAME",
|
||||
"KANIDM_WEB_UI_PKG_PATH",
|
||||
];
|
||||
|
||||
if ignorable_build_fields.contains(&key.as_str()) {
|
||||
|
|
|
@ -2,28 +2,22 @@ use std::path::PathBuf;
|
|||
|
||||
/// Generates the integrity hash for a file based on a filename
|
||||
pub fn generate_integrity_hash(filename: String) -> Result<String, String> {
|
||||
let wasm_filepath = PathBuf::from(filename);
|
||||
match wasm_filepath.exists() {
|
||||
false => Err(format!(
|
||||
"Can't find {:?} to generate file hash",
|
||||
&wasm_filepath
|
||||
)),
|
||||
let filepath = PathBuf::from(filename);
|
||||
match filepath.exists() {
|
||||
false => Err(format!("Can't find {:?} to generate file hash", &filepath)),
|
||||
true => {
|
||||
let filecontents = match std::fs::read(&wasm_filepath) {
|
||||
let filecontents = match std::fs::read(&filepath) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(format!(
|
||||
"Failed to read {:?}, skipping: {:?}",
|
||||
wasm_filepath, error
|
||||
filepath, error
|
||||
));
|
||||
}
|
||||
};
|
||||
let shasum = openssl::hash::hash(openssl::hash::MessageDigest::sha384(), &filecontents)
|
||||
.map_err(|_| {
|
||||
format!(
|
||||
"Failed to generate SHA384 hash for WASM at {:?}",
|
||||
wasm_filepath
|
||||
)
|
||||
format!("Failed to generate SHA384 hash for file at {:?}", filepath)
|
||||
})?;
|
||||
Ok(openssl::base64::encode_block(&shasum))
|
||||
}
|
||||
|
@ -32,35 +26,6 @@ pub fn generate_integrity_hash(filename: String) -> Result<String, String> {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct JavaScriptFile {
|
||||
// Relative to the pkg/ dir
|
||||
pub filepath: &'static str,
|
||||
// Dynamic
|
||||
pub dynamic: bool,
|
||||
// SHA384 hash of the file
|
||||
pub hash: String,
|
||||
// if it's a module add the "type"
|
||||
pub filetype: Option<String>,
|
||||
}
|
||||
|
||||
impl JavaScriptFile {
|
||||
/// returns a `<script>` or `<meta>` HTML tag, includes the hash as a query value as a cache-busting mechanism
|
||||
pub fn as_tag(&self) -> String {
|
||||
let filetype = match &self.filetype {
|
||||
Some(val) => {
|
||||
format!(" type=\"{}\"", val.as_str())
|
||||
}
|
||||
_ => String::from(""),
|
||||
};
|
||||
if self.dynamic {
|
||||
format!(
|
||||
r#"<meta async src="/pkg/{}?hash={}" integrity="sha384-{}"{} />"#,
|
||||
self.filepath, &self.hash, &self.hash, &filetype,
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
r#"<script async src="/pkg/{}?hash={}" integrity="sha384-{}"{}></script>"#,
|
||||
self.filepath, &self.hash, &self.hash, &filetype,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@ mod javascript;
|
|||
mod manifest;
|
||||
pub(crate) mod middleware;
|
||||
mod oauth2;
|
||||
mod tests;
|
||||
pub(crate) mod trace;
|
||||
mod ui;
|
||||
mod v1;
|
||||
mod v1_domain;
|
||||
mod v1_oauth2;
|
||||
|
@ -35,7 +33,6 @@ use axum::{
|
|||
use axum_extra::extract::cookie::CookieJar;
|
||||
use compact_jwt::{JwsCompact, JwsHs256Signer, JwsVerifier};
|
||||
use futures::pin_mut;
|
||||
use hashbrown::HashMap;
|
||||
use hyper::body::Incoming;
|
||||
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||
use kanidm_proto::{constants::KSESSIONID, internal::COOKIE_AUTH_SESSION_ID};
|
||||
|
@ -70,8 +67,6 @@ pub struct ServerState {
|
|||
pub qe_r_ref: &'static QueryServerReadV1,
|
||||
// Store the token management parts.
|
||||
pub jws_signer: JwsHs256Signer,
|
||||
// The SHA384 hashes of javascript files we're going to serve to users
|
||||
pub js_files: JavaScriptFiles,
|
||||
pub(crate) trust_x_forward_for: bool,
|
||||
pub csp_header: HeaderValue,
|
||||
pub domain: String,
|
||||
|
@ -117,73 +112,27 @@ impl ServerState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JavaScriptFiles {
|
||||
all_pages: Vec<JavaScriptFile>,
|
||||
selected: HashMap<String, JavaScriptFile>,
|
||||
}
|
||||
|
||||
pub fn get_js_files(role: ServerRole) -> Result<JavaScriptFiles, ()> {
|
||||
pub(crate) fn get_js_files(role: ServerRole) -> Result<Vec<JavaScriptFile>, ()> {
|
||||
let mut all_pages: Vec<JavaScriptFile> = Vec::new();
|
||||
let mut selected: HashMap<String, JavaScriptFile> = HashMap::new();
|
||||
|
||||
if !matches!(role, ServerRole::WriteReplicaNoUI) {
|
||||
// let's set up the list of js module hashes
|
||||
let pkg_path = if cfg!(feature = "ui_htmx") {
|
||||
env!("KANIDM_HTMX_UI_PKG_PATH").to_owned()
|
||||
} else {
|
||||
env!("KANIDM_WEB_UI_PKG_PATH").to_owned()
|
||||
};
|
||||
let pkg_path = env!("KANIDM_HTMX_UI_PKG_PATH").to_owned();
|
||||
|
||||
let filelist = if cfg!(feature = "ui_htmx") {
|
||||
vec![
|
||||
("external/bootstrap.bundle.min.js", None, false, false),
|
||||
("external/htmx.min.1.9.12.js", None, false, false),
|
||||
("external/confetti.js", None, false, false),
|
||||
("external/base64.js", None, false, false),
|
||||
("modules/cred_update.mjs", None, false, false),
|
||||
("pkhtml.js", None, false, false),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
(
|
||||
"wasmloader_admin.js",
|
||||
Some("module".to_string()),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
(
|
||||
"wasmloader_login_flows.js",
|
||||
Some("module".to_string()),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
(
|
||||
"wasmloader_user.js",
|
||||
Some("module".to_string()),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
("shared.js", Some("module".to_string()), false, false),
|
||||
("external/bootstrap.bundle.min.js", None, false, false),
|
||||
("external/viz.js", None, true, false),
|
||||
]
|
||||
};
|
||||
let filelist = [
|
||||
"external/bootstrap.bundle.min.js",
|
||||
"external/htmx.min.1.9.12.js",
|
||||
"external/confetti.js",
|
||||
"external/base64.js",
|
||||
"modules/cred_update.mjs",
|
||||
"pkhtml.js",
|
||||
];
|
||||
|
||||
for (filepath, filetype, dynamic, select) in filelist {
|
||||
for filepath in filelist {
|
||||
match generate_integrity_hash(format!("{}/{}", pkg_path, filepath,)) {
|
||||
Ok(hash) => {
|
||||
let js = JavaScriptFile {
|
||||
filepath,
|
||||
dynamic,
|
||||
hash,
|
||||
filetype,
|
||||
};
|
||||
if select {
|
||||
selected.insert(filepath.to_string(), js);
|
||||
} else {
|
||||
all_pages.push(js)
|
||||
}
|
||||
let js = JavaScriptFile { hash };
|
||||
all_pages.push(js)
|
||||
}
|
||||
Err(err) => {
|
||||
admin_error!(
|
||||
|
@ -196,10 +145,7 @@ pub fn get_js_files(role: ServerRole) -> Result<JavaScriptFiles, ()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(JavaScriptFiles {
|
||||
all_pages,
|
||||
selected,
|
||||
})
|
||||
Ok(all_pages)
|
||||
}
|
||||
|
||||
pub async fn create_https_server(
|
||||
|
@ -214,16 +160,11 @@ pub async fn create_https_server(
|
|||
) -> Result<task::JoinHandle<()>, ()> {
|
||||
let rx = server_message_tx.subscribe();
|
||||
|
||||
let js_files = get_js_files(config.role)?;
|
||||
let all_js_files = get_js_files(config.role)?;
|
||||
// set up the CSP headers
|
||||
// script-src 'self'
|
||||
// 'sha384-Zao7ExRXVZOJobzS/uMp0P1jtJz3TTqJU4nYXkdmsjpiVD+/wcwCyX7FGqRIqvIz'
|
||||
// 'sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM'
|
||||
// 'unsafe-eval';
|
||||
let mut all_js_files = js_files.all_pages.clone();
|
||||
for (_, jsfile) in js_files.selected.clone() {
|
||||
all_js_files.push(jsfile);
|
||||
}
|
||||
// 'sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM';
|
||||
|
||||
let js_directives = all_js_files
|
||||
.into_iter()
|
||||
|
@ -245,7 +186,7 @@ pub async fn create_https_server(
|
|||
"frame-ancestors 'none'; ",
|
||||
"img-src 'self' data:; ",
|
||||
"worker-src 'none'; ",
|
||||
"script-src 'self' 'unsafe-eval'{};",
|
||||
"script-src 'self'{};",
|
||||
),
|
||||
js_checksums
|
||||
);
|
||||
|
@ -261,7 +202,6 @@ pub async fn create_https_server(
|
|||
qe_w_ref,
|
||||
qe_r_ref,
|
||||
jws_signer,
|
||||
js_files,
|
||||
trust_x_forward_for,
|
||||
csp_header,
|
||||
domain: config.domain.clone(),
|
||||
|
@ -270,36 +210,17 @@ pub async fn create_https_server(
|
|||
|
||||
let static_routes = match config.role {
|
||||
ServerRole::WriteReplica | ServerRole::ReadOnlyReplica => {
|
||||
// Create a spa router that captures everything at ui without key extraction.
|
||||
if cfg!(feature = "ui_htmx") {
|
||||
Router::new()
|
||||
.route("/ui/images/oauth2/:rs_name", get(oauth2::oauth2_image_get))
|
||||
.route("/ui/images/domain", get(v1_domain::image_get))
|
||||
// Layers only apply to routes that are *already* added, not the ones
|
||||
// added after.
|
||||
.layer(middleware::compression::new())
|
||||
.layer(from_fn(middleware::caching::cache_me_short))
|
||||
.route("/", get(|| async { Redirect::to("/ui") }))
|
||||
.route("/manifest.webmanifest", get(manifest::manifest)) // skip_route_check
|
||||
.nest("/ui", views::view_router())
|
||||
} else {
|
||||
Router::new()
|
||||
.route("/ui/images/oauth2/:rs_name", get(oauth2::oauth2_image_get))
|
||||
.layer(middleware::compression::new())
|
||||
// Direct users to the base app page. If a login is required,
|
||||
// then views will take care of redirection.
|
||||
.route("/", get(|| async { Redirect::temporary("/ui") }))
|
||||
.route("/manifest.webmanifest", get(manifest::manifest)) // skip_route_check
|
||||
// user UI app is the catch-all
|
||||
.nest("/ui", ui::spa_router_user_ui())
|
||||
// login flows app
|
||||
.nest("/ui/login", ui::spa_router_login_flows())
|
||||
.nest("/ui/reauth", ui::spa_router_login_flows())
|
||||
.nest("/ui/oauth2", ui::spa_router_login_flows())
|
||||
// admin app
|
||||
.nest("/ui/admin", ui::spa_router_admin())
|
||||
// skip_route_check
|
||||
}
|
||||
Router::new()
|
||||
.route("/ui/images/oauth2/:rs_name", get(oauth2::oauth2_image_get))
|
||||
.route("/ui/images/domain", get(v1_domain::image_get))
|
||||
.route("/manifest.webmanifest", get(manifest::manifest)) // skip_route_check
|
||||
// Layers only apply to routes that are *already* added, not the ones
|
||||
// added after.
|
||||
.layer(middleware::compression::new())
|
||||
.layer(from_fn(middleware::caching::cache_me_short))
|
||||
.route("/", get(|| async { Redirect::to("/ui") }))
|
||||
.nest("/ui", views::view_router())
|
||||
// Can't compress on anything that changes
|
||||
}
|
||||
ServerRole::WriteReplicaNoUI => Router::new(),
|
||||
};
|
||||
|
@ -312,32 +233,18 @@ pub async fn create_https_server(
|
|||
let app = match config.role {
|
||||
ServerRole::WriteReplicaNoUI => app,
|
||||
ServerRole::WriteReplica | ServerRole::ReadOnlyReplica => {
|
||||
let pkg_router = if cfg!(feature = "ui_htmx") {
|
||||
let pkg_path = PathBuf::from(env!("KANIDM_HTMX_UI_PKG_PATH"));
|
||||
if !pkg_path.exists() {
|
||||
eprintln!(
|
||||
"Couldn't find htmx UI package path: ({}), quitting.",
|
||||
env!("KANIDM_HTMX_UI_PKG_PATH")
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Router::new().nest_service("/pkg", ServeDir::new(pkg_path))
|
||||
// TODO: Add in the br precompress
|
||||
} else {
|
||||
let pkg_path = PathBuf::from(env!("KANIDM_WEB_UI_PKG_PATH"));
|
||||
if !pkg_path.exists() {
|
||||
eprintln!(
|
||||
"Couldn't find Web UI package path: ({}), quitting.",
|
||||
env!("KANIDM_WEB_UI_PKG_PATH")
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Router::new()
|
||||
.nest_service("/pkg", ServeDir::new(pkg_path).precompressed_br())
|
||||
.layer(middleware::compression::new())
|
||||
let pkg_path = PathBuf::from(env!("KANIDM_HTMX_UI_PKG_PATH"));
|
||||
if !pkg_path.exists() {
|
||||
eprintln!(
|
||||
"Couldn't find htmx UI package path: ({}), quitting.",
|
||||
env!("KANIDM_HTMX_UI_PKG_PATH")
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
.layer(from_fn(middleware::caching::cache_me_short));
|
||||
let pkg_router = Router::new()
|
||||
.nest_service("/pkg", ServeDir::new(pkg_path))
|
||||
// TODO: Add in the br precompress
|
||||
.layer(from_fn(middleware::caching::cache_me_short));
|
||||
|
||||
app.merge(pkg_router)
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#[test]
|
||||
fn test_javscriptfile() {
|
||||
// make sure it outputs what we think it does
|
||||
use crate::https::JavaScriptFile;
|
||||
let jsf = JavaScriptFile {
|
||||
filepath: "wasmloader_admin.js",
|
||||
dynamic: false,
|
||||
hash: "1234567890".to_string(),
|
||||
filetype: Some("module".to_string()),
|
||||
};
|
||||
assert_eq!(
|
||||
jsf.as_tag(),
|
||||
r#"<script async src="/pkg/wasmloader_admin.js?hash=1234567890" integrity="sha384-1234567890" type="module"></script>"#
|
||||
);
|
||||
let jsf = JavaScriptFile {
|
||||
filepath: "wasmloader_admin.js",
|
||||
dynamic: false,
|
||||
hash: "1234567890".to_string(),
|
||||
filetype: None,
|
||||
};
|
||||
assert_eq!(
|
||||
jsf.as_tag(),
|
||||
r#"<script async src="/pkg/wasmloader_admin.js?hash=1234567890" integrity="sha384-1234567890"></script>"#
|
||||
);
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
use axum::extract::State;
|
||||
use axum::http::header::CONTENT_TYPE;
|
||||
use axum::http::HeaderValue;
|
||||
use axum::response::Response;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
use super::ServerState;
|
||||
|
||||
use crate::https::extractors::{DomainInfo, DomainInfoRead};
|
||||
|
||||
pub const CSS_NAVBAR_NAV: &str = "navbar navbar-expand-md navbar-dark bg-dark mb-4";
|
||||
pub const CSS_NAVBAR_BRAND: &str = "navbar-brand d-flex align-items-center";
|
||||
pub const CSS_NAVBAR_LINKS_UL: &str = "navbar-nav";
|
||||
|
||||
pub(crate) fn spa_router_user_ui() -> Router<ServerState> {
|
||||
Router::new()
|
||||
.route("/", get(ui_handler_user_ui))
|
||||
.fallback(ui_handler_user_ui)
|
||||
}
|
||||
|
||||
/// This handles /ui/admin and all sub-paths
|
||||
pub(crate) fn spa_router_admin() -> Router<ServerState> {
|
||||
Router::new()
|
||||
.route("/", get(ui_handler_admin))
|
||||
.fallback(ui_handler_admin)
|
||||
}
|
||||
|
||||
/// This handles the following base paths:
|
||||
/// - /ui/login
|
||||
/// - /ui/reauth
|
||||
/// - /ui/oauth2
|
||||
pub(crate) fn spa_router_login_flows() -> Router<ServerState> {
|
||||
Router::new()
|
||||
.route("/", get(ui_handler_login_flows))
|
||||
.fallback(ui_handler_login_flows)
|
||||
}
|
||||
|
||||
pub(crate) async fn ui_handler_user_ui(
|
||||
State(state): State<ServerState>,
|
||||
DomainInfo(domain_info): DomainInfo,
|
||||
) -> Response<String> {
|
||||
ui_handler_generic(state, "wasmloader_user.js", domain_info).await
|
||||
}
|
||||
|
||||
pub(crate) async fn ui_handler_admin(
|
||||
State(state): State<ServerState>,
|
||||
DomainInfo(domain_info): DomainInfo,
|
||||
) -> Response<String> {
|
||||
ui_handler_generic(state, "wasmloader_admin.js", domain_info).await
|
||||
}
|
||||
|
||||
pub(crate) async fn ui_handler_login_flows(
|
||||
State(state): State<ServerState>,
|
||||
DomainInfo(domain_info): DomainInfo,
|
||||
) -> Response<String> {
|
||||
ui_handler_generic(state, "wasmloader_login_flows.js", domain_info).await
|
||||
}
|
||||
|
||||
pub(crate) async fn ui_handler_generic(
|
||||
state: ServerState,
|
||||
wasmloader: &str,
|
||||
domain_info: DomainInfoRead,
|
||||
) -> Response<String> {
|
||||
// let's get the tags we want to load the javascript files
|
||||
let mut jsfiles: Vec<String> = state
|
||||
.js_files
|
||||
.all_pages
|
||||
.into_iter()
|
||||
.map(|j| j.as_tag())
|
||||
.collect();
|
||||
if let Some(jsfile) = state.js_files.selected.get(wasmloader) {
|
||||
jsfiles.push(jsfile.clone().as_tag())
|
||||
};
|
||||
|
||||
let body: String = format!(
|
||||
include_str!("ui_html.html"),
|
||||
jstags = jsfiles.join("\n"),
|
||||
cache_buster_key = crate::https::cache_buster::get_cache_buster_key(),
|
||||
display_name = domain_info.display_name()
|
||||
);
|
||||
|
||||
let mut res = Response::new(body);
|
||||
res.headers_mut().insert(
|
||||
CONTENT_TYPE,
|
||||
HeaderValue::from_static("text/html;charset=utf-8"),
|
||||
);
|
||||
res
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="theme-color" content="white" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>{display_name}</title>
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
|
||||
<link rel="icon"
|
||||
href="/pkg/img/favicon.png?v={cache_buster_key}" />
|
||||
<link rel="apple-touch-icon"
|
||||
href="/pkg/img/logo-256.png?v={cache_buster_key}" />
|
||||
<link rel="apple-touch-icon" sizes="180x180"
|
||||
href="/pkg/img/logo-180.png?v={cache_buster_key}" />
|
||||
<link rel="apple-touch-icon" sizes="192x192"
|
||||
href="/pkg/img/logo-192.png?v={cache_buster_key}" />
|
||||
<link rel="apple-touch-icon" sizes="512x512"
|
||||
href="/pkg/img/logo-square.svg?v={cache_buster_key}" />
|
||||
<link rel="stylesheet" href="/pkg/external/bootstrap.min.css"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" />
|
||||
<link rel="stylesheet"
|
||||
href="/pkg/style.css?v={cache_buster_key}" />
|
||||
|
||||
{jstags}
|
||||
|
||||
</head>
|
||||
<body class="flex-column d-flex h-100">
|
||||
<main class="flex-shrink-0 form-signin m-auto">
|
||||
<center>
|
||||
<img
|
||||
src="/pkg/img/logo-square.svg?v={cache_buster_key}"
|
||||
alt="Kanidm"
|
||||
class="kanidm_logo" />
|
||||
<h3>Kanidm is loading, please wait... </h3>
|
||||
</center>
|
||||
</main>
|
||||
<footer class="footer mt-auto py-3 bg-light text-end">
|
||||
<div class="container">
|
||||
<span class="text-muted">Powered by <a
|
||||
href="https://kanidm.com">Kanidm</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -14,9 +14,14 @@
|
|||
(% block body %)
|
||||
<main class="flex-shrink-0 container form-signin m-auto" id="cred-reset-form">
|
||||
<center>
|
||||
(% if domain_info.image().is_some() %)
|
||||
<img src="/ui/images/domain"
|
||||
alt="(( domain_info.display_name() ))" class="kanidm_logo" />
|
||||
(% else %)
|
||||
<img
|
||||
src="/pkg/img/logo-square.svg?v=((crate::https::cache_buster::get_cache_buster_key()))"
|
||||
alt="Kanidm" class="kanidm_logo" />
|
||||
alt="(( domain_info.display_name() ))" class="kanidm_logo" />
|
||||
(% endif %)
|
||||
<h2>Credential Reset</h2>
|
||||
<h3>(( domain_info.display_name() ))</h3>
|
||||
</center>
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
<main id="main" class="form-signin m-auto align-items-center d-flex flex-column">
|
||||
(% if display_ctx.domain_info.image().is_some() %)
|
||||
<img src="/ui/images/domain"
|
||||
alt="Kanidm" class="kanidm_logo" />
|
||||
alt="(( display_ctx.domain_info.display_name() ))" class="kanidm_logo" />
|
||||
(% else %)
|
||||
<img
|
||||
src="/pkg/img/logo-square.svg?v=((crate::https::cache_buster::get_cache_buster_key()))"
|
||||
alt="Kanidm" class="kanidm_logo" />
|
||||
alt="(( display_ctx.domain_info.display_name() ))" class="kanidm_logo" />
|
||||
(% endif %)
|
||||
<h3>Kanidm</h3>
|
||||
(% if let Some(reauth) = display_ctx.reauth %)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<nav class="(( crate::https::ui::CSS_NAVBAR_NAV ))">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
|
||||
<div class="container-lg">
|
||||
<a class="(( crate::https::ui::CSS_NAVBAR_BRAND ))" href="/ui/apps">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/ui/apps">
|
||||
(% if navbar_ctx.domain_info.image().is_some() %)
|
||||
<img src="/ui/images/domain"
|
||||
alt="Kanidm" width="auto" height="40" class="navbar-toggler-img" />
|
||||
alt="(( navbar_ctx.domain_info.display_name() ))" width="auto" height="40" class="navbar-toggler-img" />
|
||||
(% else %)
|
||||
<img
|
||||
src="/pkg/img/logo.svg?v=((crate::https::cache_buster::get_cache_buster_key()))"
|
||||
alt="Kanidm" width="auto" height="40" class="navbar-toggler-img" />
|
||||
alt="(( navbar_ctx.domain_info.display_name() ))" width="auto" height="40" class="navbar-toggler-img" />
|
||||
(% endif %)
|
||||
<div class="ps-2">Kanidm</div>
|
||||
<div class="ps-2">(( navbar_ctx.domain_info.display_name() ))</div>
|
||||
</a>
|
||||
|
||||
<!-- this shows a button on mobile devices to open the menu-->
|
||||
|
@ -21,7 +21,7 @@
|
|||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="(( crate::https::ui::CSS_NAVBAR_LINKS_UL ))">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||
<li>
|
||||
<a class="nav-link" href=((Urls::Apps))>
|
||||
<span data-feather="file"></span>Apps</a>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<span data-feather="file"></span>Profile</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="(( crate::https::ui::CSS_NAVBAR_LINKS_UL )) ms-md-auto">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-md-0 ms-md-auto">
|
||||
<li>
|
||||
<a class="nav-link" href="#" data-bs-toggle="modal"
|
||||
data-bs-target="#signoutModal">Sign out</a>
|
||||
|
|
|
@ -34,10 +34,8 @@ futures = { workspace = true }
|
|||
dhat = { workspace = true, optional = true }
|
||||
clap = { workspace = true, features = ["env"] }
|
||||
reqwest = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
serde_json.workspace = true
|
||||
|
||||
|
|
|
@ -17,14 +17,6 @@ path = "src/lib.rs"
|
|||
test = true
|
||||
doctest = false
|
||||
|
||||
[[bench]]
|
||||
name = "scaling_10k"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "image_benches"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
default = []
|
||||
dhat-heap = ["dep:dhat"]
|
||||
|
@ -48,8 +40,7 @@ kanidm_proto = { workspace = true }
|
|||
kanidm_lib_crypto = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
ldap3_proto = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
libsqlite3-sys = { workspace = true }
|
||||
# libsqlite3-sys = { workspace = true }
|
||||
num_enum = { workspace = true }
|
||||
# We need to explicitly ask for openssl-sys so that we get the version propagated
|
||||
# into the build.rs for legacy feature checks.
|
||||
|
@ -69,19 +60,15 @@ serde = { workspace = true, features = ["derive"] }
|
|||
serde_cbor = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
sketching = { workspace = true }
|
||||
smartstring = { workspace = true, features = ["serde"] }
|
||||
smolset = { workspace = true }
|
||||
sshkey-attest = { workspace = true }
|
||||
time = { workspace = true, features = ["serde", "std"] }
|
||||
tokio = { workspace = true, features = ["net", "sync", "time", "rt"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
toml = { workspace = true }
|
||||
nonempty = { workspace = true, features = ["serialize"] }
|
||||
|
||||
tracing = { workspace = true, features = ["attributes"] }
|
||||
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
urlencoding = { workspace = true }
|
||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
||||
webauthn-rs = { workspace = true, features = [
|
||||
"resident-key-support",
|
||||
|
@ -110,7 +97,6 @@ compact_jwt = { workspace = true, features = [
|
|||
"hsm-crypto",
|
||||
"unsafe_release_without_verify",
|
||||
] }
|
||||
criterion = { workspace = true, features = ["html_reports"] }
|
||||
futures = { workspace = true }
|
||||
kanidmd_lib_macros = { workspace = true }
|
||||
# This is needed so that we can use a test feature across the crate boundary to proto
|
||||
|
|
|
@ -1,134 +1,135 @@
|
|||
/// This file contains benchmarks for the image module so we can work out the best order to run things in
|
||||
use std::time::Duration;
|
||||
// /// This file contains benchmarks for the image module so we can work out the best order to run things in
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use kanidmd_lib::valueset::image::jpg;
|
||||
use kanidmd_lib::valueset::image::png;
|
||||
// use std::time::Duration;
|
||||
|
||||
pub fn bench_png_lodepng_validate(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("png_lodepng_validate");
|
||||
group.bench_function("png_lodepng_validate_oversize", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| png::png_lodepng_validate(&contents, black_box("oversize_dimensions.png")))
|
||||
});
|
||||
group.bench_function("png_lodepng_validate_ok", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| png::png_lodepng_validate(&contents, black_box("oversize_dimensions.png")))
|
||||
});
|
||||
group.finish();
|
||||
}
|
||||
// use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
// use kanidmd_lib::valueset::image::jpg;
|
||||
// use kanidmd_lib::valueset::image::png;
|
||||
|
||||
pub fn bench_png_has_trailer(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("png_has_trailer");
|
||||
group.bench_function("png_has_trailer_oversize", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| png::png_has_trailer(&contents));
|
||||
});
|
||||
group.bench_function("png_has_trailer_ok", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/ok.png",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| png::png_has_trailer(&contents));
|
||||
});
|
||||
group.finish();
|
||||
}
|
||||
// pub fn bench_png_lodepng_validate(c: &mut Criterion) {
|
||||
// let mut group = c.benchmark_group("png_lodepng_validate");
|
||||
// group.bench_function("png_lodepng_validate_oversize", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| png::png_lodepng_validate(&contents, black_box("oversize_dimensions.png")))
|
||||
// });
|
||||
// group.bench_function("png_lodepng_validate_ok", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| png::png_lodepng_validate(&contents, black_box("oversize_dimensions.png")))
|
||||
// });
|
||||
// group.finish();
|
||||
// }
|
||||
|
||||
pub fn bench_jpg(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("jpg");
|
||||
group.bench_function("check_jpg_header", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| jpg::check_jpg_header(&contents));
|
||||
});
|
||||
group.bench_function("has_trailer", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(filename).unwrap());
|
||||
b.iter(|| jpg::has_trailer(&contents));
|
||||
});
|
||||
group.bench_function("use_decoder", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
b.iter(|| jpg::validate_decoding(&filename, &contents, image::io::Limits::default()));
|
||||
});
|
||||
group.finish();
|
||||
}
|
||||
// pub fn bench_png_has_trailer(c: &mut Criterion) {
|
||||
// let mut group = c.benchmark_group("png_has_trailer");
|
||||
// group.bench_function("png_has_trailer_oversize", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.png",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| png::png_has_trailer(&contents));
|
||||
// });
|
||||
// group.bench_function("png_has_trailer_ok", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/ok.png",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| png::png_has_trailer(&contents));
|
||||
// });
|
||||
// group.finish();
|
||||
// }
|
||||
|
||||
pub fn compare_jpg(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("compare_jpg");
|
||||
group.bench_function("header, trailer, decoder", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
b.iter(|| {
|
||||
assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
assert!(jpg::has_trailer(&contents).is_ok());
|
||||
assert!(
|
||||
jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
);
|
||||
});
|
||||
});
|
||||
group.bench_function("trailer, header, decoder", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
b.iter(|| {
|
||||
assert!(jpg::has_trailer(&contents).is_ok());
|
||||
assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
assert!(
|
||||
jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
);
|
||||
});
|
||||
});
|
||||
group.bench_function("decoder, trailer, header", |b| {
|
||||
let filename = black_box(format!(
|
||||
"{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
));
|
||||
let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
b.iter(|| {
|
||||
assert!(
|
||||
jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
);
|
||||
assert!(jpg::has_trailer(&contents).is_ok());
|
||||
assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
});
|
||||
});
|
||||
// pub fn bench_jpg(c: &mut Criterion) {
|
||||
// let mut group = c.benchmark_group("jpg");
|
||||
// group.bench_function("check_jpg_header", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| jpg::check_jpg_header(&contents));
|
||||
// });
|
||||
// group.bench_function("has_trailer", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(filename).unwrap());
|
||||
// b.iter(|| jpg::has_trailer(&contents));
|
||||
// });
|
||||
// group.bench_function("use_decoder", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
// b.iter(|| jpg::validate_decoding(&filename, &contents, image::io::Limits::default()));
|
||||
// });
|
||||
// group.finish();
|
||||
// }
|
||||
|
||||
group.finish();
|
||||
}
|
||||
// pub fn compare_jpg(c: &mut Criterion) {
|
||||
// let mut group = c.benchmark_group("compare_jpg");
|
||||
// group.bench_function("header, trailer, decoder", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
// b.iter(|| {
|
||||
// assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
// assert!(jpg::has_trailer(&contents).is_ok());
|
||||
// assert!(
|
||||
// jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
// group.bench_function("trailer, header, decoder", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
// b.iter(|| {
|
||||
// assert!(jpg::has_trailer(&contents).is_ok());
|
||||
// assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
// assert!(
|
||||
// jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
// group.bench_function("decoder, trailer, header", |b| {
|
||||
// let filename = black_box(format!(
|
||||
// "{}/src/valueset/image/test_images/oversize_dimensions.jpg",
|
||||
// env!("CARGO_MANIFEST_DIR")
|
||||
// ));
|
||||
// let contents = black_box(std::fs::read(&filename).unwrap());
|
||||
// b.iter(|| {
|
||||
// assert!(
|
||||
// jpg::validate_decoding(&filename, &contents, image::io::Limits::default()).is_ok()
|
||||
// );
|
||||
// assert!(jpg::has_trailer(&contents).is_ok());
|
||||
// assert!(jpg::check_jpg_header(&contents).is_ok());
|
||||
// });
|
||||
// });
|
||||
|
||||
criterion_group!(
|
||||
name = png_tests;
|
||||
config = Criterion::default()
|
||||
.measurement_time(Duration::from_secs(15))
|
||||
.with_plots();
|
||||
targets = bench_png_lodepng_validate, bench_png_has_trailer, bench_jpg, compare_jpg
|
||||
);
|
||||
criterion_main!(png_tests);
|
||||
// group.finish();
|
||||
// }
|
||||
|
||||
// criterion_group!(
|
||||
// name = png_tests;
|
||||
// config = Criterion::default()
|
||||
// .measurement_time(Duration::from_secs(15))
|
||||
// .with_plots();
|
||||
// targets = bench_png_lodepng_validate, bench_png_has_trailer, bench_jpg, compare_jpg
|
||||
// );
|
||||
// criterion_main!(png_tests);
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
use std::time::{Duration, Instant, SystemTime};
|
||||
|
||||
use criterion::{
|
||||
criterion_group, criterion_main, BenchmarkId, Criterion, SamplingMode, Throughput,
|
||||
};
|
||||
|
||||
use kanidmd_lib::entry::{Entry, EntryInit, EntryNew};
|
||||
use kanidmd_lib::entry_init;
|
||||
use kanidmd_lib::prelude::{Attribute, EntryClass};
|
||||
use kanidmd_lib::testkit::{setup_idm_test, TestConfiguration};
|
||||
use kanidmd_lib::value::Value;
|
||||
|
||||
pub fn duration_from_epoch_now() -> Duration {
|
||||
#[allow(clippy::expect_used)]
|
||||
SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("invalid duration from epoch now")
|
||||
}
|
||||
|
||||
pub fn scaling_user_create_single(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("user_create_single");
|
||||
group.sample_size(10);
|
||||
group.sampling_mode(SamplingMode::Flat);
|
||||
group.warm_up_time(Duration::from_secs(5));
|
||||
group.measurement_time(Duration::from_secs(120));
|
||||
|
||||
for size in &[100, 250, 500, 1000, 1500, 2000, 5000, 10000] {
|
||||
group.throughput(Throughput::Elements(*size));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
|
||||
b.iter_custom(|iters| {
|
||||
let mut elapsed = Duration::from_secs(0);
|
||||
println!("iters, size -> {iters:?}, {size:?}");
|
||||
|
||||
for _i in 0..iters {
|
||||
let mut rt = tokio::runtime::Builder::new_current_thread();
|
||||
elapsed = rt
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed building the Runtime")
|
||||
.block_on(async {
|
||||
let (idms, _idms_delayed, _idms_audit) =
|
||||
setup_idm_test(TestConfiguration::default()).await;
|
||||
|
||||
let ct = duration_from_epoch_now();
|
||||
let start = Instant::now();
|
||||
for counter in 0..size {
|
||||
let mut idms_prox_write =
|
||||
idms.proxy_write(ct).await.expect("Failed to get write txn");
|
||||
let name = format!("testperson_{counter}");
|
||||
let e1 = entry_init!(
|
||||
(Attribute::Class, EntryClass::Object.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Name, Value::new_iname(&name)),
|
||||
(Attribute::Description, Value::new_utf8s("criterion")),
|
||||
(Attribute::DisplayName, Value::new_utf8s(&name))
|
||||
);
|
||||
|
||||
let cr = idms_prox_write.qs_write.internal_create(vec![e1]);
|
||||
assert!(cr.is_ok());
|
||||
|
||||
idms_prox_write.commit().expect("Must not fail");
|
||||
}
|
||||
elapsed.checked_add(start.elapsed()).unwrap()
|
||||
});
|
||||
}
|
||||
elapsed
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
pub fn scaling_user_create_batched(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("user_create_batched");
|
||||
group.sample_size(10);
|
||||
group.sampling_mode(SamplingMode::Flat);
|
||||
group.warm_up_time(Duration::from_secs(5));
|
||||
group.measurement_time(Duration::from_secs(120));
|
||||
|
||||
for size in &[100, 250, 500, 1000, 1500, 2000, 5000, 10000] {
|
||||
group.throughput(Throughput::Elements(*size));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
|
||||
b.iter_custom(|iters| {
|
||||
let mut elapsed = Duration::from_secs(0);
|
||||
println!("iters, size -> {iters:?}, {size:?}");
|
||||
|
||||
let data: Vec<_> = (0..size)
|
||||
.map(|i| {
|
||||
let name = format!("testperson_{i}");
|
||||
entry_init!(
|
||||
(Attribute::Class, EntryClass::Object.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Name, Value::new_iname(&name)),
|
||||
(Attribute::Description, Value::new_utf8s("criterion")),
|
||||
(Attribute::DisplayName, Value::new_utf8s(&name))
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for _i in 0..iters {
|
||||
let mut rt = tokio::runtime::Builder::new_current_thread();
|
||||
elapsed = rt
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed building the Runtime")
|
||||
.block_on(async {
|
||||
let (idms, _idms_delayed, _idms_audit) =
|
||||
setup_idm_test(TestConfiguration::default()).await;
|
||||
|
||||
let ct = duration_from_epoch_now();
|
||||
let start = Instant::now();
|
||||
|
||||
let mut idms_prox_write =
|
||||
idms.proxy_write(ct).await.expect("Failed to get write txn");
|
||||
let cr = idms_prox_write.qs_write.internal_create(data.clone());
|
||||
assert!(cr.is_ok());
|
||||
|
||||
idms_prox_write.commit().expect("Must not fail");
|
||||
elapsed.checked_add(start.elapsed()).unwrap()
|
||||
});
|
||||
}
|
||||
elapsed
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
name = scaling_basic;
|
||||
config = Criterion::default()
|
||||
.measurement_time(Duration::from_secs(15))
|
||||
.with_plots();
|
||||
targets = scaling_user_create_single, scaling_user_create_batched
|
||||
);
|
||||
criterion_main!(scaling_basic);
|
|
@ -30,9 +30,7 @@ kanidm_client = { workspace = true }
|
|||
kanidm_proto = { workspace = true }
|
||||
kanidmd_core = { workspace = true }
|
||||
kanidmd_lib = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
openssl = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
reqwest = { workspace = true, default-features = false, features = ["cookies"] }
|
||||
serde = { workspace = true }
|
||||
sketching = { workspace = true }
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
[package]
|
||||
name = "kanidmd_web_ui_admin"
|
||||
description = "Kanidm Server Web UI - Admin Interface"
|
||||
documentation = "https://docs.rs/kanidm/latest/kanidm/"
|
||||
|
||||
version = { workspace = true }
|
||||
authors = [
|
||||
"William Brown <william@blackhats.net.au>",
|
||||
"James Hodgkinson <james@terminaloutcomes.com>",
|
||||
]
|
||||
rust-version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
kanidm_proto = { workspace = true, features = ["wasm"] }
|
||||
kanidmd_web_ui_shared = { workspace = true }
|
||||
gloo = { workspace = true }
|
||||
js-sys = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde-wasm-bindgen = { workspace = true }
|
||||
time = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
wasm-bindgen = { workspace = true }
|
||||
wasm-bindgen-futures = { workspace = true }
|
||||
yew = { workspace = true, features = ["csr"] }
|
||||
yew-router = { workspace = true }
|
||||
gloo-utils = { workspace = true }
|
||||
enum-iterator = { workspace = true}
|
||||
|
||||
[dependencies.web-sys]
|
||||
workspace = true
|
||||
features = [
|
||||
# "AuthenticationExtensionsClientOutputs",
|
||||
# "AuthenticatorResponse",
|
||||
# "CredentialCreationOptions",
|
||||
# "CredentialRequestOptions",
|
||||
# "CredentialsContainer",
|
||||
"DomTokenList",
|
||||
"Element",
|
||||
"Event",
|
||||
"FocusEvent",
|
||||
"FormData",
|
||||
"Headers",
|
||||
"HtmlButtonElement",
|
||||
"HtmlDocument",
|
||||
"HtmlFormElement",
|
||||
"HtmlSelectElement",
|
||||
"HtmlInputElement",
|
||||
"Navigator",
|
||||
# "PublicKeyCredential",
|
||||
# "PublicKeyCredentialCreationOptions",
|
||||
# "PublicKeyCredentialRpEntity",
|
||||
# "PublicKeyCredentialUserEntity",
|
||||
"Request",
|
||||
# "RequestCredentials",
|
||||
# "RequestInit",
|
||||
# "RequestMode",
|
||||
# "RequestRedirect",
|
||||
"Response",
|
||||
"Window",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = { workspace = true }
|
|
@ -1,584 +0,0 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use gloo::console;
|
||||
use wasm_bindgen::JsValue;
|
||||
use yew::{html, Component, Context, Html, Properties};
|
||||
use yew_router::prelude::Link;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::components::admin_menu::{Entity, EntityType, GetError};
|
||||
use crate::router::AdminRoute;
|
||||
use kanidmd_web_ui_shared::constants::{CSS_CELL, CSS_DT, CSS_TABLE};
|
||||
|
||||
impl From<GetError> for AdminListAccountsMsg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminListAccountsMsg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdminListAccounts {
|
||||
state: ViewState,
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminListAccountsMsg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded {
|
||||
response: BTreeMap<String, Entity>,
|
||||
},
|
||||
Failed {
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: BTreeMap<String, Entity> },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
enum ViewAccountState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: Entity },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Properties, Eq)]
|
||||
pub struct AdminListAccountsProps {
|
||||
// for filtering and pagination
|
||||
// #[allow(dead_code)]
|
||||
// search: Option<String>,
|
||||
// #[allow(dead_code)]
|
||||
// page: Option<u32>,
|
||||
}
|
||||
|
||||
/// Pulls all accounts (service or person-class) from the backend and returns a HashMap
|
||||
/// with the "name" field being the keys, for easy human-facing sortability.
|
||||
pub async fn get_accounts() -> Result<AdminListAccountsMsg, GetError> {
|
||||
// TODO: the actual pulling and turning into a BTreeMap in this and get_groups could *probably* be rolled up into one function? The result object differs but all the widgets are the same.
|
||||
let mut all_accounts = BTreeMap::new();
|
||||
|
||||
// we iterate over these endpoints
|
||||
let endpoints = [
|
||||
("/v1/service_account", EntityType::ServiceAccount),
|
||||
("/v1/person", EntityType::Person),
|
||||
];
|
||||
|
||||
for (endpoint, object_type) in endpoints {
|
||||
let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None::<JsValue>).await
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
// TODO: this kind of thing comes back when you're logged out: SerdeError(Error("invalid type: string \"sessionexpired\", expected a sequence", line: 1, column: 16))', server/web_ui/src/components/admin_accounts.rs:107:27
|
||||
let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("Failed to grab the account data into JSON: {:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for entity in data.iter() {
|
||||
let mut new_entity = entity.to_owned();
|
||||
new_entity.object_type = object_type.clone();
|
||||
|
||||
// first we try the short name and, if that isn't there then just use the SPN...
|
||||
#[allow(clippy::expect_used)]
|
||||
let entity_id = match entity.attrs.name.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => entity
|
||||
.attrs
|
||||
.spn
|
||||
.first()
|
||||
.expect("Failed to grab the SPN for an account.")
|
||||
.to_string(),
|
||||
};
|
||||
all_accounts.insert(entity_id.to_string(), new_entity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AdminListAccountsMsg::Responded {
|
||||
response: all_accounts,
|
||||
})
|
||||
}
|
||||
|
||||
impl Component for AdminListAccounts {
|
||||
type Message = AdminListAccountsMsg;
|
||||
type Properties = AdminListAccountsProps;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
// TODO: work out the querystring thing so we can just show x number of elements
|
||||
// console::log!("query: {:?}", location().query);
|
||||
|
||||
// start pulling the account data on startup
|
||||
ctx.link().send_future(async move {
|
||||
match get_accounts().await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminListAccounts {
|
||||
state: ViewState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminListAccountsMsg::Responded { response } => {
|
||||
// TODO: do we paginate here?
|
||||
/*
|
||||
// Seems broken
|
||||
#[cfg(debug_assertions)]
|
||||
for key in response.keys() {
|
||||
#[allow(clippy::unwrap_used)]
|
||||
console::log!(
|
||||
"response: {:?}",
|
||||
serde_json::to_string(response.get(key).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
*/
|
||||
self.state = ViewState::Responded { response };
|
||||
return true;
|
||||
}
|
||||
AdminListAccountsMsg::Failed { emsg, kopid } => {
|
||||
console::log!("emsg: {:?}", emsg);
|
||||
console::log!("kopid: {:?}", kopid);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
{do_page_header("Account Administration")}
|
||||
{ alpha_warning_banner() }
|
||||
<div id={"accountlist"}>
|
||||
{match &self.state {
|
||||
ViewState::Loading => {
|
||||
html! {"Waiting on the accounts list to load..."}
|
||||
}
|
||||
|
||||
ViewState::Responded { response } => {
|
||||
let scope_col = "col";
|
||||
|
||||
html!(
|
||||
<table class={CSS_TABLE}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope={scope_col}></th>
|
||||
<th scope={scope_col}>{"Display Name"}</th>
|
||||
<th scope={scope_col}>{"Username"}</th>
|
||||
<th scope={scope_col}>{"Description"}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{
|
||||
response.keys().map(|name| {
|
||||
#[allow(clippy::expect_used)]
|
||||
let account: &Entity = response.get(name).expect("Couldn't get account key when it was just in the iter...");
|
||||
|
||||
let display_name: String = match account.attrs.displayname.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
|
||||
let description: String = match account.attrs.description.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
let account_type: Html = match account.object_type {
|
||||
EntityType::ServiceAccount => html!{<img src={"/pkg/img/icon-robot.svg"} alt={"Service Account"} class={"p-0"} />},
|
||||
EntityType::Person => html!{<img src={"/pkg/img/icon-person.svg"} alt={"Person"} class={"p-0"} />},
|
||||
_ => html!("x"),
|
||||
};
|
||||
|
||||
|
||||
let uuid: String = match account.attrs.uuid.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => {
|
||||
console::error!("Account without a UUID?", format!("{:?}", account).to_string());
|
||||
String::from("Unknown UUID!")
|
||||
}
|
||||
};
|
||||
|
||||
let object_link = match account.object_type {
|
||||
EntityType::Person => AdminRoute::ViewPerson{id_or_name:uuid.clone()},
|
||||
EntityType::ServiceAccount => AdminRoute::ViewServiceAccount{id_or_name:uuid.clone()},
|
||||
// because matching is hard
|
||||
_ => AdminRoute::ViewPerson{id_or_name:uuid.clone()},
|
||||
};
|
||||
|
||||
html!{
|
||||
<tr key={uuid}>
|
||||
<td class={CSS_CELL}>{account_type}</td>
|
||||
<th scope={scope_col} class={CSS_CELL}>
|
||||
<Link<AdminRoute> to={object_link} >
|
||||
{display_name}
|
||||
</Link<AdminRoute>>
|
||||
</th>
|
||||
<td class={CSS_CELL}>{name}</td>
|
||||
<td class={CSS_CELL}>{description}</td>
|
||||
</tr>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</table>
|
||||
)
|
||||
}
|
||||
ViewState::Failed { emsg, kopid } => {
|
||||
console::error!("Failed to pull details", format!("{:?}", kopid));
|
||||
html!(
|
||||
<>
|
||||
{do_alert_error("Failed to Query Accounts", Some(emsg), false)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
ViewState::NotAuthorized {} => {
|
||||
do_alert_error("You're not authorized to see this page!", None, false)
|
||||
}
|
||||
}}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl AdminListAccounts {
|
||||
// /// output the information based on what's in the current state
|
||||
// fn view_state(&self, _ctx: &Context<Self>) -> Html {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<GetError> for AdminViewPersonMsg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminViewPersonMsg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdminViewPerson {
|
||||
#[allow(dead_code)]
|
||||
state: ViewAccountState,
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Eq, Clone)]
|
||||
/// Properties for accounts, either Person or Service Account
|
||||
pub struct AdminViewAccountProps {
|
||||
pub id_or_name: String,
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminViewPersonMsg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded { response: Entity },
|
||||
#[allow(dead_code)]
|
||||
Failed { emsg: String, kopid: Option<String> },
|
||||
}
|
||||
|
||||
impl Component for AdminViewPerson {
|
||||
type Message = AdminViewPersonMsg;
|
||||
type Properties = AdminViewAccountProps;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let uuid = ctx.props().id_or_name.clone();
|
||||
ctx.link().send_future(async move {
|
||||
match get_person(&uuid).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminViewPerson {
|
||||
state: ViewAccountState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminViewPersonMsg::Responded { response } => {
|
||||
self.state = ViewAccountState::Responded { response }
|
||||
}
|
||||
AdminViewPersonMsg::Failed { emsg, kopid } => {
|
||||
self.state = ViewAccountState::Failed { emsg, kopid }
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
ViewAccountState::Loading => html! {{"Loading..."}},
|
||||
ViewAccountState::Failed { emsg, kopid } => do_alert_error(
|
||||
emsg.clone().as_str(),
|
||||
Some(&format!("Operation ID: {:?}", kopid)),
|
||||
false,
|
||||
),
|
||||
// TODO: the not authorized page needs to be better
|
||||
ViewAccountState::NotAuthorized {} => {
|
||||
html! {{"You are not authorized to view this page!"}}
|
||||
}
|
||||
ViewAccountState::Responded { response } => {
|
||||
// TODO: This is pretty lacking in detail, even logged in as the idm_admin user, so will have to work out how to pull all the details
|
||||
let username = match response.attrs.name.first() {
|
||||
Some(value) => value.to_owned(),
|
||||
None => String::from("Unable to query username"),
|
||||
};
|
||||
let display_name = match response.attrs.displayname.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from("Display Name Unset"),
|
||||
};
|
||||
|
||||
// let mail_primary = match userinfo.uat.mail_primary.as_ref() {
|
||||
// Some(email_address) => {
|
||||
// html! {
|
||||
// <a href={ format!("mailto:{}", &email_address)}>
|
||||
// {email_address}
|
||||
// </a>
|
||||
// }
|
||||
// }
|
||||
// None => html! { {"<primary email is unset>"}},
|
||||
// };
|
||||
html! {
|
||||
<>
|
||||
{do_page_header(display_name.as_str())}
|
||||
{alpha_warning_banner()}
|
||||
|
||||
// <dt class={CSS_DT}>{ "Display Name" }</dt>
|
||||
// <dl class="row">
|
||||
// <dd class="col">{ }</dd>
|
||||
|
||||
// <dt class={CSS_DT}>{ "Primary Email" }</dt>
|
||||
// <dd class="col">{mail_primary}</dd>
|
||||
|
||||
// <dt class={CSS_DT}>{ "Group Memberships" }</dt>
|
||||
// <dd class="col">
|
||||
// <ul class="list-group">
|
||||
// {
|
||||
// match user_groups {
|
||||
// Some(grouplist) => html!{
|
||||
// {
|
||||
// for grouplist.iter()
|
||||
// .map(|group|
|
||||
// {
|
||||
// html!{ <li>{
|
||||
// #[allow(clippy::unwrap_used)]
|
||||
// group.split('@').next().unwrap().to_string()
|
||||
// }</li> }
|
||||
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// None => html!{
|
||||
// <li>{"Not a member of any groups"}</li>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// </ul>
|
||||
// </dd>
|
||||
|
||||
|
||||
// <dt class={CSS_DT}>
|
||||
// { "User's SPN" }
|
||||
// </dt>
|
||||
// <dd class="col">
|
||||
// { username.to_string() }{"@"}{ domain }
|
||||
// </dd>
|
||||
|
||||
<dt class={CSS_DT}>{ "Username" }</dt>
|
||||
<dd class="col">{ username }</dd>
|
||||
|
||||
<dt class={CSS_DT}>{ "User's UUID" }</dt>
|
||||
<dd class="col">{ response.attrs.uuid.clone().first() }</dd>
|
||||
|
||||
// </dl>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GetError> for AdminViewServiceAccountMsg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminViewServiceAccountMsg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdminViewServiceAccount {
|
||||
#[allow(dead_code)]
|
||||
state: ViewAccountState,
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminViewServiceAccountMsg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded { response: Entity },
|
||||
#[allow(dead_code)]
|
||||
Failed { emsg: String, kopid: Option<String> },
|
||||
}
|
||||
|
||||
impl Component for AdminViewServiceAccount {
|
||||
type Message = AdminViewServiceAccountMsg;
|
||||
type Properties = AdminViewAccountProps;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let id_or_name = ctx.props().id_or_name.clone();
|
||||
ctx.link().send_future(async move {
|
||||
match get_service_account(&id_or_name).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminViewServiceAccount {
|
||||
state: ViewAccountState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
ViewAccountState::Loading => html! {{"Loading..."}},
|
||||
ViewAccountState::Responded { response } => {
|
||||
let account = &response.attrs;
|
||||
let username = match account.name.first() {
|
||||
Some(value) => value.as_str(),
|
||||
None => "Unable to pull username",
|
||||
};
|
||||
let displayname = match account.displayname.first() {
|
||||
Some(value) => value.as_str(),
|
||||
None => "Unable to pull displayname",
|
||||
};
|
||||
|
||||
let description = match account.description.first() {
|
||||
Some(value) => html! {<p>{"Description: "}{value.as_str()}</p>},
|
||||
None => html! {},
|
||||
};
|
||||
|
||||
html! {
|
||||
<>
|
||||
|
||||
{do_page_header(&format!("Service Account: {}", username))}
|
||||
{alpha_warning_banner()}
|
||||
<p>{"Display Name: "}{displayname}</p>
|
||||
{description}
|
||||
</>
|
||||
}
|
||||
}
|
||||
ViewAccountState::Failed { emsg, kopid } => html! {
|
||||
do_alert_error(emsg.as_str(), Some(&format!("Operation ID: {:?}", kopid)), false)
|
||||
},
|
||||
// TODO: this error needs fixing
|
||||
ViewAccountState::NotAuthorized {} => {
|
||||
html! {{"You're not authorized to view this page!"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminViewServiceAccountMsg::Responded { response } => {
|
||||
self.state = ViewAccountState::Responded { response }
|
||||
}
|
||||
AdminViewServiceAccountMsg::Failed { emsg, kopid } => {
|
||||
self.state = ViewAccountState::Failed { emsg, kopid }
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// pull the details for a single person by UUID
|
||||
pub async fn get_person(uuid: &str) -> Result<AdminViewPersonMsg, GetError> {
|
||||
let (_, _, value, _) = match do_request(
|
||||
format!("/v1/person/{}", uuid).as_str(),
|
||||
RequestMethod::GET,
|
||||
None::<JsValue>,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Entity = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(AdminViewPersonMsg::Responded { response: data })
|
||||
}
|
||||
|
||||
/// pull the details for a single service_account by UUID
|
||||
pub async fn get_service_account(uuid: &str) -> Result<AdminViewServiceAccountMsg, GetError> {
|
||||
let (_, _, value, _) = match do_request(
|
||||
format!("/v1/service_account/{}", uuid).as_str(),
|
||||
RequestMethod::GET,
|
||||
None::<JsValue>,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!(
|
||||
"Failed to grab the service_account data into JSON: {:?}",
|
||||
error
|
||||
),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Entity = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(AdminViewServiceAccountMsg::Responded { response: data })
|
||||
}
|
|
@ -1,436 +0,0 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use gloo::console::{self};
|
||||
use kanidmd_web_ui_shared::utils::{do_alert_error, do_page_header};
|
||||
use wasm_bindgen::JsValue;
|
||||
use yew::{html, Component, Context, Html, Properties};
|
||||
use yew_router::prelude::Link;
|
||||
|
||||
use crate::components::admin_menu::{Entity, EntityType, GetError};
|
||||
use crate::router::AdminRoute;
|
||||
use kanidmd_web_ui_shared::constants::{CSS_CELL, CSS_TABLE};
|
||||
use kanidmd_web_ui_shared::{alpha_warning_banner, do_request, RequestMethod};
|
||||
#[cfg(debug_assertions)]
|
||||
use serde::Serialize;
|
||||
|
||||
impl From<GetError> for AdminListGroupsMsg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminListGroupsMsg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdminListGroups {
|
||||
state: GroupsViewState,
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminListGroupsMsg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded {
|
||||
response: BTreeMap<String, Entity>,
|
||||
},
|
||||
Failed {
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
enum GroupsViewState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: BTreeMap<String, Entity> },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Properties, Eq)]
|
||||
pub struct AdminListGroupsProps {
|
||||
// for filtering and pagination
|
||||
// #[allow(dead_code)]
|
||||
// search: Option<String>,
|
||||
// #[allow(dead_code)]
|
||||
// page: Option<u32>,
|
||||
}
|
||||
|
||||
/// Pulls all accounts (service or person-class) from the backend and returns a HashMap
|
||||
/// with the "name" field being the keys, for easy human-facing sortability.
|
||||
pub async fn get_groups() -> Result<AdminListGroupsMsg, GetError> {
|
||||
let mut all_groups = BTreeMap::new();
|
||||
|
||||
// we iterate over these endpoints
|
||||
let endpoints = [("/v1/group", EntityType::Group)];
|
||||
|
||||
for (endpoint, object_type) in endpoints {
|
||||
let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None::<JsValue>).await
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("Failed to grab the group data into JSON: {:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for entity in data.iter() {
|
||||
let mut new_entity = entity.to_owned();
|
||||
new_entity.object_type = object_type.clone();
|
||||
|
||||
// first we try the short name and, if that isn't there then just use the SPN...
|
||||
#[allow(clippy::expect_used)]
|
||||
let entity_id = match entity.attrs.name.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => entity
|
||||
.attrs
|
||||
.spn
|
||||
.first()
|
||||
.expect("Failed to grab the SPN for a group.")
|
||||
.to_string(),
|
||||
};
|
||||
all_groups.insert(entity_id.to_string(), new_entity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AdminListGroupsMsg::Responded {
|
||||
response: all_groups,
|
||||
})
|
||||
}
|
||||
|
||||
impl Component for AdminListGroups {
|
||||
type Message = AdminListGroupsMsg;
|
||||
type Properties = AdminListGroupsProps;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
// TODO: work out the querystring thing so we can just show x number of elements
|
||||
// console::log!("query: {:?}", location().query);
|
||||
|
||||
// start pulling the account data on startup
|
||||
ctx.link().send_future(async move {
|
||||
match get_groups().await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminListGroups {
|
||||
state: GroupsViewState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminListGroupsMsg::Responded { response } => {
|
||||
// TODO: do we paginate here?
|
||||
#[cfg(debug_assertions)]
|
||||
for key in response.keys() {
|
||||
let j = response
|
||||
.get(key)
|
||||
.and_then(|k| {
|
||||
k.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
|
||||
.ok()
|
||||
})
|
||||
.and_then(|jsv| js_sys::JSON::stringify(&jsv).ok().map(|s| s.into()))
|
||||
.unwrap_or_else(|| "Failed to dump response key".to_string());
|
||||
console::log!("response: {}", j);
|
||||
}
|
||||
self.state = GroupsViewState::Responded { response };
|
||||
return true;
|
||||
}
|
||||
AdminListGroupsMsg::Failed { emsg, kopid } => {
|
||||
// TODO: make this push a view state
|
||||
console::log!("emsg: {:?}", emsg);
|
||||
console::log!("kopid: {:?}", kopid);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
{do_page_header("Group Administration")}
|
||||
|
||||
{ alpha_warning_banner() }
|
||||
<div id={"grouplist"}>
|
||||
{self.view_state(ctx)}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AdminListGroups {
|
||||
/// output the information based on what's in the current state
|
||||
fn view_state(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
GroupsViewState::Loading => {
|
||||
html! {"Waiting on the groups list to load..."}
|
||||
}
|
||||
|
||||
GroupsViewState::Responded { response } => {
|
||||
let scope_col = "col";
|
||||
|
||||
html!(
|
||||
<table class={CSS_TABLE}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope={scope_col}>{"Name"}</th>
|
||||
<th scope={scope_col}>{"Description"}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{
|
||||
response.keys().map(|name| {
|
||||
#[allow(clippy::expect_used)]
|
||||
let group: &Entity = response.get(name).expect("Couldn't get group key when it was just in the iter...");
|
||||
|
||||
let description: String = match group.attrs.description.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
let uuid: String = match group.attrs.uuid.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => {
|
||||
console::error!("Group without a UUID?", format!("{:?}", group).to_string());
|
||||
String::from("GROUP WITHOUT A UUID!")
|
||||
}
|
||||
};
|
||||
|
||||
html!{
|
||||
<tr key={uuid.clone()}>
|
||||
<td class={CSS_CELL} scope={scope_col}>
|
||||
<Link<AdminRoute> to={AdminRoute::ViewGroup{id_or_name:{uuid.clone()}}} >{name}</Link<AdminRoute>></td>
|
||||
<td class={CSS_CELL}>{description}</td>
|
||||
</tr>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
GroupsViewState::Failed { emsg, kopid } => {
|
||||
console::error!("Failed to pull details", format!("{:?}", kopid));
|
||||
html!(
|
||||
<>
|
||||
{do_alert_error("Failed to Query Groups", Some(emsg), false)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
GroupsViewState::NotAuthorized {} => {
|
||||
do_alert_error("You're not authorized to see this page!", None, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Eq, Clone)]
|
||||
pub struct AdminViewGroupProps {
|
||||
pub id_or_name: String,
|
||||
}
|
||||
|
||||
// callback messaging for group detail view
|
||||
pub enum AdminViewGroupMsg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded { response: Entity },
|
||||
#[allow(dead_code)]
|
||||
Failed { emsg: String, kopid: Option<String> },
|
||||
#[allow(dead_code)]
|
||||
NotAuthorized {},
|
||||
}
|
||||
|
||||
impl From<GetError> for AdminViewGroupMsg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminViewGroupMsg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum GroupViewState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: Entity },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
pub struct AdminViewGroup {
|
||||
state: GroupViewState,
|
||||
}
|
||||
|
||||
impl Component for AdminViewGroup {
|
||||
type Message = AdminViewGroupMsg;
|
||||
type Properties = AdminViewGroupProps;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let id_or_name = ctx.props().id_or_name.clone();
|
||||
ctx.link().send_future(async move {
|
||||
match get_group(&id_or_name).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
|
||||
AdminViewGroup {
|
||||
state: GroupViewState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
GroupViewState::Loading => html! {"Loading..."},
|
||||
GroupViewState::Responded { response } => {
|
||||
let group_name = match response.attrs.name.first() {
|
||||
Some(value) => value.as_str(),
|
||||
None => {
|
||||
// TODO: this should throw an error
|
||||
"No Group Name?"
|
||||
}
|
||||
};
|
||||
let page_title = format!("Group: {}", group_name);
|
||||
|
||||
let group_uuid = match response.attrs.uuid.first() {
|
||||
Some(value) => value.clone(),
|
||||
None => String::from("Error querying UUID!"),
|
||||
};
|
||||
html! {
|
||||
<>
|
||||
{do_page_header(&page_title)}
|
||||
<p>{"UUID: "}{group_uuid}</p>
|
||||
|
||||
// membership
|
||||
// TODO: need to pull the member details so we can identify what they are
|
||||
{
|
||||
if !response.attrs.member.is_empty() {
|
||||
html!{
|
||||
<>
|
||||
<h3>{"Members"}</h3>
|
||||
<ul>
|
||||
{
|
||||
response.attrs.member.iter().map(|group| {
|
||||
html!{
|
||||
<li>{group}</li>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</ul>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
html!{<></>}
|
||||
}
|
||||
}
|
||||
|
||||
// this group is a member of the below
|
||||
// TODO: need to pull the names so we can identify what they are
|
||||
{
|
||||
if !response.attrs.memberof.is_empty() {
|
||||
html!{
|
||||
<>
|
||||
<h3>{"Group is a member of the following"}</h3>
|
||||
<ul>
|
||||
{
|
||||
response.attrs.memberof.iter().map(|group| {
|
||||
html!{
|
||||
<li>
|
||||
|
||||
{group}
|
||||
</li>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</ul>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
html!{<></>}
|
||||
}
|
||||
}
|
||||
</>
|
||||
}
|
||||
}
|
||||
GroupViewState::Failed { emsg, kopid } => do_alert_error(
|
||||
emsg,
|
||||
Some(
|
||||
kopid
|
||||
.as_ref()
|
||||
.unwrap_or(&String::from("unknown operation ID")),
|
||||
),
|
||||
false,
|
||||
),
|
||||
GroupViewState::NotAuthorized {} => {
|
||||
do_alert_error("You are not authorized to view this page!", None, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminViewGroupMsg::Responded { response } => {
|
||||
self.state = GroupViewState::Responded { response };
|
||||
true
|
||||
}
|
||||
AdminViewGroupMsg::Failed { emsg, kopid } => {
|
||||
self.state = GroupViewState::Failed { emsg, kopid };
|
||||
true
|
||||
}
|
||||
AdminViewGroupMsg::NotAuthorized {} => {
|
||||
self.state = GroupViewState::NotAuthorized {};
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// pull the details for a single group by UUID
|
||||
pub async fn get_group(groupid: &str) -> Result<AdminViewGroupMsg, GetError> {
|
||||
let endpoint = format!("/v1/group/{}", groupid);
|
||||
let (_, _, value, _) = match do_request(&endpoint, RequestMethod::GET, None::<JsValue>).await {
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Entity = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(AdminViewGroupMsg::Responded { response: data })
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
use kanidmd_web_ui_shared::alpha_warning_banner;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use yew::{html, Component, Context, Html, Properties};
|
||||
use yew_router::prelude::Link;
|
||||
|
||||
use kanidmd_web_ui_shared::constants::{
|
||||
CSS_CARD, CSS_CARD_BODY, CSS_LINK_DARK_STRETCHED, CSS_PAGE_HEADER,
|
||||
};
|
||||
// use crate::error::FetchError;
|
||||
use crate::router::AdminRoute;
|
||||
|
||||
#[derive(Eq, PartialEq, Properties)]
|
||||
pub struct Props;
|
||||
|
||||
// #[derive(PartialEq, Properties)]
|
||||
// pub struct ListProps {
|
||||
// #[allow(dead_code)]
|
||||
// search: Option<String>,
|
||||
// #[allow(dead_code)]
|
||||
// page: Option<u32>,
|
||||
// }
|
||||
pub struct AdminMenu;
|
||||
|
||||
impl Component for AdminMenu {
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
AdminMenu
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<div class={CSS_PAGE_HEADER}>
|
||||
<h2>{ "System Administration" }</h2>
|
||||
</div>
|
||||
{ alpha_warning_banner() }
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
|
||||
<div class="col">
|
||||
<div class={CSS_CARD}>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListAccounts}>
|
||||
<img src={"/pkg/img/icon-accounts.svg"} />
|
||||
</Link<AdminRoute>>
|
||||
<div class={CSS_CARD_BODY}>
|
||||
<h3>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListAccounts}>
|
||||
{ "Accounts" }
|
||||
</Link<AdminRoute>>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// card for groups
|
||||
<div class="col">
|
||||
<div class={CSS_CARD}>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListGroups}>
|
||||
<img src={"/pkg/img/icon-groups.svg"} />
|
||||
</Link<AdminRoute>>
|
||||
<div class={CSS_CARD_BODY}>
|
||||
<h3>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListGroups}>
|
||||
{ "Groups" }
|
||||
</Link<AdminRoute>>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// card for oauth
|
||||
<div class="col">
|
||||
<div class={CSS_CARD}>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListOAuth2}>
|
||||
<img src={"/pkg/img/icon-oauth2.svg"} />
|
||||
</Link<AdminRoute>>
|
||||
<div class={CSS_CARD_BODY}>
|
||||
<h3>
|
||||
<Link<AdminRoute> classes={CSS_LINK_DARK_STRETCHED} to={AdminRoute::AdminListOAuth2}>
|
||||
{ "OAuth Configurations" }
|
||||
</Link<AdminRoute>>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: can this come from somewhere else more simply? Probably not, because reasons.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Attributes {
|
||||
pub class: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub description: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub displayname: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub name: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub spn: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub uuid: Vec<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub oauth2_rs_name: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub oauth2_rs_origin: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub member: Vec<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty", default)]
|
||||
pub memberof: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EntityType {
|
||||
Person,
|
||||
ServiceAccount,
|
||||
Group,
|
||||
OAuth2RP,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Default for EntityType {
|
||||
fn default() -> Self {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Entity {
|
||||
pub attrs: Attributes,
|
||||
#[serde(default)]
|
||||
pub object_type: EntityType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct GetError {
|
||||
pub err: String,
|
||||
}
|
|
@ -1,435 +0,0 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use gloo::console;
|
||||
use wasm_bindgen::JsValue;
|
||||
use yew::{html, Component, Context, Html, Properties};
|
||||
use yew_router::prelude::Link;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::components::admin_menu::{Entity, EntityType, GetError};
|
||||
use crate::router::AdminRoute;
|
||||
use kanidmd_web_ui_shared::constants::{CSS_CELL, CSS_TABLE};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use serde::Serialize;
|
||||
|
||||
impl From<GetError> for AdminListOAuth2Msg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminListOAuth2Msg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdminListOAuth2 {
|
||||
state: ListViewState,
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminListOAuth2Msg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded {
|
||||
response: BTreeMap<String, Entity>,
|
||||
},
|
||||
Failed {
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
enum ListViewState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: BTreeMap<String, Entity> },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Properties, Eq)]
|
||||
pub struct AdminListOAuth2Props {
|
||||
// for filtering and pagination
|
||||
// #[allow(dead_code)]
|
||||
// search: Option<String>,
|
||||
// #[allow(dead_code)]
|
||||
// page: Option<u32>,
|
||||
}
|
||||
|
||||
/// Pulls all OAuth2 RPs from the backend and returns a HashMap
|
||||
/// with the "name" field being the keys, for easy human-facing sortability.
|
||||
pub async fn get_entities() -> Result<AdminListOAuth2Msg, GetError> {
|
||||
// TODO: the actual pulling and turning into a BTreeMap across the admin systems could *probably* be rolled up into one function? The result object differs but all the query bits are the same.
|
||||
let mut oauth2_objects = BTreeMap::new();
|
||||
|
||||
// we iterate over these endpoints
|
||||
let endpoints = [("/v1/oauth2", EntityType::OAuth2RP)];
|
||||
|
||||
for (endpoint, object_type) in endpoints {
|
||||
let (_, _, value, _) = match do_request(endpoint, RequestMethod::GET, None::<JsValue>).await
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Vec<Entity> = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("Failed to grab the oauth2 data into JSON: {:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for entity in data.into_iter() {
|
||||
let mut new_entity = entity.to_owned();
|
||||
new_entity.object_type = object_type.clone();
|
||||
|
||||
// first we try the uuid and if that isn't there oh no.
|
||||
#[allow(clippy::expect_used)]
|
||||
let entity_id = entity
|
||||
.attrs
|
||||
.uuid
|
||||
.first()
|
||||
.map(|e| e.to_owned())
|
||||
.unwrap_or(String::from("Unknown entity name!"));
|
||||
oauth2_objects.insert(entity_id, new_entity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AdminListOAuth2Msg::Responded {
|
||||
response: oauth2_objects,
|
||||
})
|
||||
}
|
||||
|
||||
impl Component for AdminListOAuth2 {
|
||||
type Message = AdminListOAuth2Msg;
|
||||
type Properties = AdminListOAuth2Props;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
// TODO: work out the querystring thing so we can just show x number of elements
|
||||
|
||||
// start pulling the data on startup
|
||||
ctx.link().send_future(async move {
|
||||
match get_entities().await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminListOAuth2 {
|
||||
state: ListViewState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminListOAuth2Msg::Responded { response } => {
|
||||
// TODO: do we paginate here?
|
||||
#[cfg(debug_assertions)]
|
||||
for key in response.keys() {
|
||||
let j = response
|
||||
.get(key)
|
||||
.and_then(|k| {
|
||||
k.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
|
||||
.ok()
|
||||
})
|
||||
.and_then(|jsv| js_sys::JSON::stringify(&jsv).ok().map(|s| s.into()))
|
||||
.unwrap_or_else(|| "Failed to dump response key".to_string());
|
||||
console::log!("response: {}", j);
|
||||
}
|
||||
self.state = ListViewState::Responded { response };
|
||||
return true;
|
||||
}
|
||||
AdminListOAuth2Msg::Failed { emsg, kopid } => {
|
||||
console::log!("emsg: {:?}", emsg);
|
||||
console::log!("kopid: {:?}", kopid);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
ListViewState::Loading => {
|
||||
html! {"Waiting on the OAuth2 data to load..."}
|
||||
}
|
||||
|
||||
ListViewState::Responded { response } => {
|
||||
let scope_col = "col";
|
||||
html! {
|
||||
<>
|
||||
|
||||
{do_page_header("OAuth2")}
|
||||
|
||||
{ alpha_warning_banner() }
|
||||
<div id={"accountlist"}>
|
||||
<table class={CSS_TABLE}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope={scope_col}>{"Display Name"}</th>
|
||||
<th scope={scope_col}>{"Username"}</th>
|
||||
<th scope={scope_col}>{"Description"}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{
|
||||
response.keys().map(|uuid| {
|
||||
#[allow(clippy::expect_used)]
|
||||
let oauth2_object: &Entity = response.get(uuid).expect("Couldn't get oauth2 key when it was just in the iter...");
|
||||
|
||||
let display_name: String = match oauth2_object.attrs.displayname.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
|
||||
let description: String = match oauth2_object.attrs.description.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
|
||||
let uuid: String = match oauth2_object.attrs.uuid.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => {
|
||||
console::error!("Config without a UUID?", format!("{:?}", oauth2_object).to_string());
|
||||
String::from("Unknown UUID!")
|
||||
}
|
||||
};
|
||||
|
||||
let rs_link = match oauth2_object.attrs.oauth2_rs_name.first() {
|
||||
Some(id_or_name) => {
|
||||
html!{
|
||||
<Link<AdminRoute> to={AdminRoute::ViewOAuth2RP{id_or_name: id_or_name.clone()}}>
|
||||
{display_name}
|
||||
</Link<AdminRoute>>
|
||||
}
|
||||
},
|
||||
None => {
|
||||
html!{{display_name}}
|
||||
}
|
||||
};
|
||||
|
||||
html!{
|
||||
<tr key={uuid.clone()}>
|
||||
<th scope={scope_col} class={CSS_CELL}>
|
||||
{rs_link}
|
||||
</th>
|
||||
<td class={CSS_CELL}>{uuid}</td>
|
||||
<td class={CSS_CELL}>{description}</td>
|
||||
</tr>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
}
|
||||
ListViewState::Failed { emsg, kopid } => {
|
||||
console::error!("Failed to pull details", format!("{:?}", kopid));
|
||||
html!(
|
||||
<>
|
||||
{do_alert_error("Failed to Query OAuth2", Some(emsg), false)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
ListViewState::NotAuthorized {} => {
|
||||
do_alert_error("You're not authorized to see this page!", None, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GetError> for AdminViewOAuth2Msg {
|
||||
fn from(ge: GetError) -> Self {
|
||||
AdminViewOAuth2Msg::Failed {
|
||||
emsg: ge.err,
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// callback messaging for this confused pile of crab-bait
|
||||
pub enum AdminViewOAuth2Msg {
|
||||
/// When the server responds and we need to update the page
|
||||
Responded {
|
||||
response: Entity,
|
||||
},
|
||||
Failed {
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Properties)]
|
||||
pub struct AdminViewOAuth2Props {
|
||||
pub id_or_name: String,
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
/// waiting for the page to load
|
||||
Loading,
|
||||
/// server has responded
|
||||
Responded { response: Entity },
|
||||
/// failed to pull the details
|
||||
#[allow(dead_code)]
|
||||
Failed {
|
||||
// TODO: use this
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
/// Not authorized to pull the details
|
||||
NotAuthorized {}, // TODO: use this
|
||||
}
|
||||
|
||||
pub struct AdminViewOAuth2 {
|
||||
state: ViewState,
|
||||
}
|
||||
|
||||
impl Component for AdminViewOAuth2 {
|
||||
type Message = AdminViewOAuth2Msg;
|
||||
type Properties = AdminViewOAuth2Props;
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
let rs_name = ctx.props().id_or_name.clone();
|
||||
|
||||
// start pulling the data on startup
|
||||
ctx.link().send_future(async move {
|
||||
match get_oauth2_rp(&rs_name).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
AdminViewOAuth2 {
|
||||
state: ViewState::Loading,
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
ViewState::Loading => {
|
||||
html! {"Waiting on the OAuth2 data to load..."}
|
||||
}
|
||||
|
||||
ViewState::Responded { response } => {
|
||||
let oauth2_object: &Entity = response;
|
||||
|
||||
let display_name: String = match oauth2_object.attrs.displayname.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from("!error getting display name!"),
|
||||
};
|
||||
|
||||
let description: String = match oauth2_object.attrs.description.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from(""),
|
||||
};
|
||||
let oauth2_rs_name: String = match oauth2_object.attrs.oauth2_rs_name.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from("!error getting oauth2_rs_name!"),
|
||||
};
|
||||
let oauth2_rs_origin: String = match oauth2_object.attrs.oauth2_rs_origin.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => String::from("!error getting oauth2_rs_origin!"),
|
||||
};
|
||||
let uuid: String = match oauth2_object.attrs.uuid.first() {
|
||||
Some(value) => value.to_string(),
|
||||
None => {
|
||||
console::error!("Config without a UUID?", format!("{:?}", oauth2_object));
|
||||
String::from("Unknown UUID!")
|
||||
}
|
||||
};
|
||||
html! {
|
||||
<>
|
||||
|
||||
{do_page_header(display_name.as_str())}
|
||||
{alpha_warning_banner()}
|
||||
|
||||
<p>{"UUID: "}{uuid}</p>
|
||||
<p>{description}</p>
|
||||
<p>{"RS Name: "}{oauth2_rs_name}</p>
|
||||
<p>{"Origin: "}{oauth2_rs_origin}</p>
|
||||
</>
|
||||
}
|
||||
}
|
||||
ViewState::Failed { emsg, kopid } => {
|
||||
console::error!("Failed to pull details", format!("{:?}", kopid));
|
||||
html!(
|
||||
<>
|
||||
{do_alert_error("Failed to Query OAuth2", Some(emsg), false)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
ViewState::NotAuthorized {} => {
|
||||
do_alert_error("You're not authorized to see this page!", None, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
AdminViewOAuth2Msg::Responded { response } => {
|
||||
// TODO: do we paginate here?
|
||||
/*
|
||||
// Seems broken
|
||||
#[cfg(debug_assertions)]
|
||||
for key in response.keys() {
|
||||
console::log!(
|
||||
"response: {:?}",
|
||||
serde_json::to_string(response.get(key).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
*/
|
||||
self.state = ViewState::Responded { response };
|
||||
}
|
||||
AdminViewOAuth2Msg::Failed { emsg, kopid } => {
|
||||
console::log!("emsg: {:?}", &emsg);
|
||||
console::log!("kopid: {:?}", kopid.to_owned());
|
||||
self.state = ViewState::Failed { emsg, kopid };
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_oauth2_rp(rs_name: &str) -> Result<AdminViewOAuth2Msg, GetError> {
|
||||
let endpoint = format!("/v1/oauth2/{}", rs_name);
|
||||
let (_, _, value, _) = match do_request(&endpoint, RequestMethod::GET, None::<JsValue>).await {
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
return Err(GetError {
|
||||
err: format!("{:?}", error),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let data: Entity = match serde_wasm_bindgen::from_value(value) {
|
||||
Ok(value) => {
|
||||
console::log!(format!("{:?}", value));
|
||||
value
|
||||
}
|
||||
Err(error) => {
|
||||
//TODO: turn this into an error, and handle when we aren't authorized. The server doesn't seem to be sending back anything nice for this, which is.. painful.
|
||||
console::log!(
|
||||
"Failed to grab the OAuth2 RP data into JSON:",
|
||||
format!("{:?}", error)
|
||||
);
|
||||
return Err(GetError {
|
||||
err: format!("Failed to grab the OAuth2 RP data into JSON: {:?}", error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Ok(AdminViewOAuth2Msg::Responded { response: data })
|
||||
}
|
|
@ -1,340 +0,0 @@
|
|||
use enum_iterator::{all, Sequence};
|
||||
#[cfg(debug_assertions)]
|
||||
use gloo::console;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use yew::prelude::*;
|
||||
|
||||
use kanidm_proto::internal::Filter::{Eq, Or};
|
||||
use kanidm_proto::internal::{SearchRequest, SearchResponse};
|
||||
use kanidm_proto::v1::Entry;
|
||||
use kanidmd_web_ui_shared::constants::CSS_PAGE_HEADER;
|
||||
use kanidmd_web_ui_shared::{do_request, error::FetchError, RequestMethod};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew_router::Routable;
|
||||
|
||||
use crate::router::AdminRoute;
|
||||
use kanidmd_web_ui_shared::ui::{error_page, loading_spinner};
|
||||
use kanidmd_web_ui_shared::utils::{init_graphviz, open_blank};
|
||||
|
||||
pub enum Msg {
|
||||
NewFilters { filters: Vec<ObjectType> },
|
||||
NewObjects { entries: Vec<Entry> },
|
||||
|
||||
Error { emsg: String, kopid: Option<String> },
|
||||
}
|
||||
|
||||
impl From<FetchError> for Msg {
|
||||
fn from(fe: FetchError) -> Self {
|
||||
Msg::Error {
|
||||
emsg: fe.as_string(),
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Sequence)]
|
||||
pub enum ObjectType {
|
||||
Group,
|
||||
BuiltinGroup,
|
||||
ServiceAccount,
|
||||
Person,
|
||||
}
|
||||
|
||||
impl Display for ObjectType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let str = match self {
|
||||
ObjectType::Group => "Group",
|
||||
ObjectType::BuiltinGroup => "Built In Group",
|
||||
ObjectType::ServiceAccount => "Service Account",
|
||||
ObjectType::Person => "Person",
|
||||
};
|
||||
|
||||
write!(f, "{str}")
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for ObjectType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
all::<ObjectType>()
|
||||
.find(|x| format!("{x}") == value)
|
||||
.ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum State {
|
||||
Waiting,
|
||||
Ready { entries: Vec<Entry> },
|
||||
Error { emsg: String, kopid: Option<String> },
|
||||
}
|
||||
|
||||
pub struct AdminObjectGraph {
|
||||
state: State,
|
||||
filters: Vec<ObjectType>,
|
||||
}
|
||||
|
||||
impl Component for AdminObjectGraph {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("views::objectgraph::create");
|
||||
|
||||
ctx.link()
|
||||
.send_future(async { Self::fetch_objects().await.unwrap_or_else(|v| v.into()) });
|
||||
|
||||
let state = State::Waiting;
|
||||
|
||||
AdminObjectGraph {
|
||||
state,
|
||||
filters: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("views::objectgraph::update");
|
||||
match msg {
|
||||
Msg::NewObjects { entries } => {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("Received new objects");
|
||||
self.state = State::Ready { entries }
|
||||
}
|
||||
Msg::NewFilters { filters } => {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("Received new filters");
|
||||
self.filters = filters;
|
||||
}
|
||||
Msg::Error { emsg, kopid } => self.state = State::Error { emsg, kopid },
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn changed(&mut self, _ctx: &Context<Self>, _props: &Self::Properties) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("views::objectgraph::changed");
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
match &self.state {
|
||||
State::Waiting => self.view_waiting(),
|
||||
State::Ready { entries } => self.view_ready(ctx, &self.filters, entries),
|
||||
State::Error { emsg, kopid } => self.view_error(ctx, emsg, kopid.as_deref()),
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("views::objectgraph::rendered");
|
||||
}
|
||||
}
|
||||
|
||||
impl AdminObjectGraph {
|
||||
fn view_waiting(&self) -> Html {
|
||||
loading_spinner()
|
||||
}
|
||||
|
||||
fn view_ready(&self, ctx: &Context<Self>, filters: &[ObjectType], entries: &[Entry]) -> Html {
|
||||
let typed_entries = entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let classes = entry.attrs.get("class")?;
|
||||
let uuid = entry.attrs.get("uuid")?.first()?;
|
||||
|
||||
// Logic to decide the type of each entry
|
||||
let obj_type = if classes.contains(&"group".to_string()) {
|
||||
if uuid.starts_with("00000000-0000-0000-0000-") {
|
||||
ObjectType::BuiltinGroup
|
||||
} else {
|
||||
ObjectType::Group
|
||||
}
|
||||
} else if classes.contains(&"account".to_string()) {
|
||||
if classes.contains(&"person".to_string()) {
|
||||
ObjectType::Person
|
||||
} else if classes.contains(&"service-account".to_string()) {
|
||||
ObjectType::ServiceAccount
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// Filter out the things we want to keep, if the filter is empty we assume we want all.
|
||||
if !filters.contains(&obj_type) && !filters.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let spn = entry.attrs.get("spn")?.first()?;
|
||||
Some((spn.clone(), uuid.clone(), obj_type))
|
||||
})
|
||||
.collect::<Vec<(String, String, ObjectType)>>();
|
||||
|
||||
// Vec<obj, uuid, obj's members>
|
||||
let members_of = entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let spn = entry.attrs.get("spn")?.first()?.clone();
|
||||
let uuid = entry.attrs.get("uuid")?.first()?.clone();
|
||||
let keep = typed_entries
|
||||
.iter()
|
||||
.any(|(_, filtered_uuid, _)| &uuid == filtered_uuid);
|
||||
if keep {
|
||||
Some((spn, uuid, entry.attrs.get("member")?.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Constructing graph source
|
||||
let mut sb = String::new();
|
||||
sb.push_str("digraph {\n rankdir=\"RL\"\n");
|
||||
for (spn, _, members) in members_of {
|
||||
members
|
||||
.iter()
|
||||
.filter(|member| typed_entries.iter().any(|(spn, _, _)| spn == *member))
|
||||
.for_each(|member| {
|
||||
sb.push_str(format!(r#" "{spn}" -> "{member}"{}"#, "\n").as_str());
|
||||
});
|
||||
}
|
||||
|
||||
for (spn, uuid, obj_type) in typed_entries {
|
||||
let (color, shape, route) = match obj_type {
|
||||
ObjectType::Group => ("#b86367", "box", AdminRoute::ViewGroup { id_or_name: uuid }),
|
||||
ObjectType::BuiltinGroup => (
|
||||
"#8bc1d6",
|
||||
"component",
|
||||
AdminRoute::ViewGroup { id_or_name: uuid },
|
||||
),
|
||||
ObjectType::ServiceAccount => (
|
||||
"#77c98d",
|
||||
"parallelogram",
|
||||
AdminRoute::ViewServiceAccount { id_or_name: uuid },
|
||||
),
|
||||
ObjectType::Person => (
|
||||
"#af8bd6",
|
||||
"ellipse",
|
||||
AdminRoute::ViewPerson { id_or_name: uuid },
|
||||
),
|
||||
};
|
||||
let url = route.to_path();
|
||||
sb.push_str(
|
||||
format!(
|
||||
r#" "{spn}" [color = "{color}", shape = {shape}, URL = "{url}"]{}"#,
|
||||
"\n"
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
sb.push('}');
|
||||
init_graphviz(sb.as_str());
|
||||
|
||||
let node_refs = all::<ObjectType>()
|
||||
.map(|object_type: ObjectType| (object_type, NodeRef::default()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let on_checkbox_click = {
|
||||
let scope = ctx.link().clone();
|
||||
let node_refs = node_refs.clone();
|
||||
move |_: Event| {
|
||||
let mut filters = vec![];
|
||||
|
||||
for (obj_type, node_ref) in &node_refs {
|
||||
if let Some(input_el) = node_ref.cast::<HtmlInputElement>() {
|
||||
let checked = input_el.checked();
|
||||
|
||||
if checked {
|
||||
filters.push(*obj_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.send_message(Msg::NewFilters { filters });
|
||||
}
|
||||
};
|
||||
|
||||
let view_graph_source = {
|
||||
move |_: MouseEvent| {
|
||||
open_blank(sb.as_str());
|
||||
}
|
||||
};
|
||||
|
||||
html! {
|
||||
<>
|
||||
<div class={CSS_PAGE_HEADER}>
|
||||
<h2>{ "ObjectGraph view" }</h2>
|
||||
</div>
|
||||
if entries.is_empty() {
|
||||
<div>
|
||||
<h5>{ "No graph objects for the applied filters." }</h5>
|
||||
</div>
|
||||
} else {
|
||||
<div class="column">
|
||||
<div class="hstack gap-3">
|
||||
{
|
||||
node_refs.iter().map(|(ot, node_ref)| {
|
||||
let ot_str = format!("{}", ot);
|
||||
let selected = filters.contains(ot);
|
||||
|
||||
html! {
|
||||
<>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input obj-graph-filter-cb" type="checkbox" ref={ node_ref } id={ot_str.clone()} onchange={on_checkbox_click.clone()} checked={selected}/>
|
||||
<label class="form-check-label" for={ot_str.clone()}>{ot_str.clone()}</label>
|
||||
</div>
|
||||
if *ot != ObjectType::last().unwrap() {
|
||||
<div class="vr"></div>
|
||||
}
|
||||
</>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</div>
|
||||
<button class="btn btn-primary mt-2" onclick={view_graph_source}>{ "View graph source" }</button>
|
||||
</div>
|
||||
<div id="graph-container" class="mt-3"></div>
|
||||
}
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
fn view_error(&self, _ctx: &Context<Self>, msg: &str, kopid: Option<&str>) -> Html {
|
||||
error_page(msg, kopid)
|
||||
}
|
||||
|
||||
async fn fetch_objects() -> Result<Msg, FetchError> {
|
||||
let req_body = SearchRequest {
|
||||
filter: Or(vec![
|
||||
Eq("class".to_string(), "person".to_string()),
|
||||
Eq("class".to_string(), "service_account".to_string()),
|
||||
Eq("class".to_string(), "group".to_string()),
|
||||
]),
|
||||
};
|
||||
|
||||
let req_jsvalue = req_body
|
||||
.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
|
||||
.expect("Failed to serialise request");
|
||||
let req_jsvalue = js_sys::JSON::stringify(&req_jsvalue).expect_throw("failed to stringify");
|
||||
|
||||
let (kopid, status, value, _) =
|
||||
do_request("/v1/raw/search", RequestMethod::POST, Some(req_jsvalue)).await?;
|
||||
|
||||
if status == 200 {
|
||||
let search_resp: SearchResponse = serde_wasm_bindgen::from_value(value)
|
||||
.expect_throw("Invalid response type - objectgraph::SearchRequest");
|
||||
|
||||
Ok(Msg::NewObjects {
|
||||
entries: search_resp.entries,
|
||||
})
|
||||
} else {
|
||||
let emsg = value.as_string().unwrap_or_default();
|
||||
Ok(Msg::Error { emsg, kopid })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
pub mod admin_accounts;
|
||||
pub mod admin_groups;
|
||||
pub mod admin_menu;
|
||||
pub mod admin_oauth2;
|
||||
pub mod admin_objectgraph;
|
||||
|
||||
mod prelude {
|
||||
|
||||
pub use kanidmd_web_ui_shared::alpha_warning_banner;
|
||||
pub use kanidmd_web_ui_shared::utils::{do_alert_error, do_page_header};
|
||||
pub use kanidmd_web_ui_shared::{do_request, RequestMethod};
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
mod components;
|
||||
mod router;
|
||||
|
||||
use gloo::console::{self, error};
|
||||
use kanidmd_web_ui_shared::add_body_form_classes;
|
||||
use kanidmd_web_ui_shared::constants::{
|
||||
CSS_NAVBAR_BRAND, CSS_NAVBAR_LINKS_UL, CSS_NAVBAR_NAV, CSS_NAV_LINK, ID_NAVBAR_COLLAPSE,
|
||||
IMG_LOGO_SQUARE, URL_USER_HOME,
|
||||
};
|
||||
use kanidmd_web_ui_shared::ui::{signout_link, signout_modal, ui_logout};
|
||||
use kanidmd_web_ui_shared::utils::do_footer;
|
||||
#[allow(unused_imports)] // because it's needed to compile wasm things
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
use yew::{html, Component, Context, Html};
|
||||
use yew_router::prelude::Link;
|
||||
use yew_router::{BrowserRouter, Switch};
|
||||
|
||||
use crate::router::AdminRoute;
|
||||
|
||||
pub struct AdminApp {}
|
||||
|
||||
/// This builds the navbar, it's not generic because the link on the logo is different
|
||||
fn make_navbar(links: Vec<Html>) -> Html {
|
||||
html! {
|
||||
<nav class={CSS_NAVBAR_NAV}>
|
||||
<div class="container-fluid">
|
||||
<a href={URL_USER_HOME} class={CSS_NAVBAR_BRAND}>
|
||||
{"Kanidm Administration"}
|
||||
</a>
|
||||
// this shows a button on mobile devices to open the menu
|
||||
<button class="navbar-toggler bg-white" type="button" data-bs-toggle="collapse" data-bs-target={["#", ID_NAVBAR_COLLAPSE].concat()} aria-controls={ID_NAVBAR_COLLAPSE} aria-expanded="false" aria-label="Toggle navigation">
|
||||
<img src={IMG_LOGO_SQUARE} alt="Toggle navigation" class="navbar-toggler-img" />
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id={ID_NAVBAR_COLLAPSE}>
|
||||
<ul class={CSS_NAVBAR_LINKS_UL}>
|
||||
{ links.into_iter().map(|link| {
|
||||
html!{ <li class="mb-1">
|
||||
{ link }
|
||||
</li>
|
||||
} }).collect::<Html>()
|
||||
}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AdminViewsMsg {
|
||||
Logout,
|
||||
LogoutComplete,
|
||||
}
|
||||
|
||||
impl Component for AdminApp {
|
||||
type Message = AdminViewsMsg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("manager::create");
|
||||
AdminApp {}
|
||||
}
|
||||
|
||||
fn changed(&mut self, _ctx: &Context<Self>, _props: &Self::Properties) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("manager::change");
|
||||
false
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("manager::update");
|
||||
match msg {
|
||||
AdminViewsMsg::Logout => {
|
||||
console::debug!("manager::update -> logout");
|
||||
|
||||
ctx.link().send_future(async {
|
||||
match Self::fetch_logout().await {
|
||||
Ok(v) => v,
|
||||
Err(v) => {
|
||||
error!("... failed to log out? {:?}", v);
|
||||
AdminViewsMsg::Logout
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
AdminViewsMsg::LogoutComplete => {
|
||||
let window = gloo_utils::window();
|
||||
window.location().set_href(URL_USER_HOME).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("manager::rendered");
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
add_body_form_classes!();
|
||||
|
||||
let links = vec![
|
||||
html! {<a href={URL_USER_HOME} class={CSS_NAV_LINK}>{"Home"}</a>},
|
||||
html! {<Link<AdminRoute> classes={CSS_NAV_LINK} to={AdminRoute::AdminMenu}>{"Admin"}</Link<AdminRoute>>},
|
||||
html! {<Link<AdminRoute> classes={CSS_NAV_LINK} to={AdminRoute::AdminListAccounts}>{"Accounts"}</Link<AdminRoute>>},
|
||||
html! {<Link<AdminRoute> classes={CSS_NAV_LINK} to={AdminRoute::AdminListGroups}>{"Groups"}</Link<AdminRoute>>},
|
||||
html! {<Link<AdminRoute> classes={CSS_NAV_LINK} to={AdminRoute::AdminObjectGraph}>{"ObjectGraph"}</Link<AdminRoute>>},
|
||||
html! {<Link<AdminRoute> classes={CSS_NAV_LINK} to={AdminRoute::AdminListOAuth2}>{"OAuth2"}</Link<AdminRoute>>},
|
||||
signout_link(),
|
||||
];
|
||||
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
|
||||
// sign out modal dialogue box
|
||||
{signout_modal(ctx, AdminViewsMsg::Logout)}
|
||||
{make_navbar(links)}
|
||||
|
||||
<main class="p-3 x-auto">
|
||||
<Switch<AdminRoute> render={ router::switch } />
|
||||
</main>
|
||||
{ do_footer() }
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AdminApp {
|
||||
async fn fetch_logout() -> Result<AdminViewsMsg, String> {
|
||||
match ui_logout().await {
|
||||
Ok(_) => Ok(AdminViewsMsg::LogoutComplete),
|
||||
Err((emsg, _kopid)) => {
|
||||
error!("failed to process logout request: {}", emsg);
|
||||
Ok(AdminViewsMsg::Logout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the entry point of the web front end. This triggers the manager app to load and begin
|
||||
/// its event loop.
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
|
||||
pub fn run_app() -> Result<(), JsValue> {
|
||||
yew::Renderer::<AdminApp>::new().render();
|
||||
Ok(())
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
#![allow(clippy::disallowed_types)] // because `Routable` uses a hashmap
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use yew::{html, Html};
|
||||
use yew_router::prelude::Redirect;
|
||||
use yew_router::Routable;
|
||||
|
||||
use crate::components;
|
||||
|
||||
#[derive(Routable, PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum AdminRoute {
|
||||
#[at("/ui/admin")]
|
||||
AdminMenu,
|
||||
#[at("/ui/admin/groups")]
|
||||
AdminListGroups,
|
||||
#[at("/ui/admin/accounts")]
|
||||
AdminListAccounts,
|
||||
#[at("/ui/admin/object-graph")]
|
||||
AdminObjectGraph,
|
||||
#[at("/ui/admin/oauth2")]
|
||||
AdminListOAuth2,
|
||||
|
||||
#[at("/ui/admin/group/:id_or_name")]
|
||||
ViewGroup { id_or_name: String },
|
||||
#[at("/ui/admin/person/:id_or_name")]
|
||||
ViewPerson { id_or_name: String },
|
||||
#[at("/ui/admin/service_account/:id_or_name")]
|
||||
ViewServiceAccount { id_or_name: String },
|
||||
#[at("/ui/admin/oauth2/:id_or_name")]
|
||||
ViewOAuth2RP { id_or_name: String },
|
||||
|
||||
#[not_found]
|
||||
#[at("/ui/admin/404")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
pub(crate) fn switch(route: AdminRoute) -> Html {
|
||||
match route {
|
||||
AdminRoute::AdminMenu => html! {
|
||||
<components::admin_menu::AdminMenu />
|
||||
},
|
||||
AdminRoute::AdminListAccounts => html!(
|
||||
<components::admin_accounts::AdminListAccounts />
|
||||
),
|
||||
AdminRoute::AdminListGroups => html!(
|
||||
<components::admin_groups::AdminListGroups />
|
||||
),
|
||||
AdminRoute::AdminObjectGraph => html!(
|
||||
<components::admin_objectgraph::AdminObjectGraph />
|
||||
),
|
||||
AdminRoute::AdminListOAuth2 => html!(
|
||||
<components::admin_oauth2::AdminListOAuth2 />
|
||||
),
|
||||
AdminRoute::ViewGroup { id_or_name } => {
|
||||
html!(<components::admin_groups::AdminViewGroup id_or_name={id_or_name} />)
|
||||
}
|
||||
AdminRoute::ViewPerson { id_or_name } => html!(
|
||||
<components::admin_accounts::AdminViewPerson id_or_name={id_or_name} />
|
||||
),
|
||||
AdminRoute::ViewServiceAccount { id_or_name } => html!(
|
||||
<components::admin_accounts::AdminViewServiceAccount id_or_name={id_or_name} />
|
||||
// html! {<></>}
|
||||
),
|
||||
AdminRoute::ViewOAuth2RP { id_or_name } => html! {
|
||||
<components::admin_oauth2::AdminViewOAuth2 id_or_name={id_or_name} />
|
||||
|
||||
},
|
||||
AdminRoute::NotFound => html! (
|
||||
<Redirect<AdminRoute> to={AdminRoute::NotFound}/>
|
||||
),
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// loads the module which loads the WASM. It's loaders all the way down.
|
||||
import init, { run_app } from '/pkg/kanidmd_web_ui_admin.js';
|
||||
async function main() {
|
||||
await init('/pkg/kanidmd_web_ui_admin_bg.wasm');
|
||||
run_app();
|
||||
}
|
||||
main()
|
|
@ -1,72 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# This builds the assets for the Web UI, defaulting to a release build.
|
||||
if [ ! -f build_wasm.sh ]; then
|
||||
echo "Please run from the crate directory. (server/web_ui)"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(which rsync)" ]; then
|
||||
echo "Cannot find rsync which is needed to move things around, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(which wasm-pack)" ]; then
|
||||
echo "Cannot find wasm-pack which is needed to build the UI, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(which wasm-bindgen)" ]; then
|
||||
echo "Cannot find wasm-bindgen which is needed to build the UI, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(which bc)" ]; then
|
||||
echo "Cannot find bc which is needed to build the UI, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${BUILD_FLAGS}" ]; then
|
||||
export BUILD_FLAGS="--release"
|
||||
fi
|
||||
|
||||
echo "Cleaning up pkg dir"
|
||||
find pkg/ -type f -delete
|
||||
find pkg/ -mindepth 1 -type d -delete
|
||||
|
||||
touch ./pkg/ANYTHING_HERE_WILL_BE_DELETED_IN_BUILDS
|
||||
if [ -f ./pkg/.gitignore ]; then
|
||||
rm ./pkg/.gitignore
|
||||
fi
|
||||
|
||||
# copy the shared static things
|
||||
rsync -av shared/static/* admin/static/* user/static/* login_flows/static/* pkg/
|
||||
|
||||
|
||||
cd admin
|
||||
echo "building admin"
|
||||
../individual_build.sh || exit 1
|
||||
cd ..
|
||||
echo "done building admin"
|
||||
|
||||
cd login_flows
|
||||
echo "building login_flows"
|
||||
../individual_build.sh || exit 1
|
||||
cd ..
|
||||
echo "done building login_flows"
|
||||
|
||||
cd user
|
||||
echo "building user"
|
||||
../individual_build.sh || exit 1
|
||||
cd ..
|
||||
echo "done building user"
|
||||
|
||||
|
||||
|
||||
if [ -z "${SKIP_BROTLI}" ]; then
|
||||
# updates the brotli-compressed files
|
||||
echo "brotli-compressing compressible files over 16KB in size..."
|
||||
find ./pkg -size +16k -type f \
|
||||
-not -name '*.br' \
|
||||
-not -name '*.png' \
|
||||
-exec ./find_best_brotli.sh "{}" \; || exit 1
|
||||
fi
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
SKIP_BROTLI=1 BUILD_FLAGS="--dev" ./build_wasm.sh
|
|
@ -1,64 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# check brotli's installed
|
||||
if ! command -v brotli &> /dev/null
|
||||
then
|
||||
echo "brotli tool could not be found, please make sure you have it in your path!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Exit if no argument is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "No filename provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
filename=$1
|
||||
echo "#####################################"
|
||||
echo "Compressing $1"
|
||||
|
||||
# Exit if the file doesn't exist
|
||||
if [ ! -f "${filename}" ]; then
|
||||
echo "File ${filename} not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
original_size_kb=$(du -k "${filename}" | cut -f1)
|
||||
|
||||
tmpfile=$(mktemp)
|
||||
|
||||
for num in {10..24}
|
||||
do
|
||||
{
|
||||
size=$(brotli --lgwin="${num}" -c "${filename}" | wc -c)
|
||||
echo "${num} ${size}" >> "${tmpfile}"
|
||||
} &
|
||||
done
|
||||
|
||||
# Wait for all background jobs to finish
|
||||
wait
|
||||
|
||||
# Process results
|
||||
{
|
||||
read -r min_num min_size
|
||||
while read -r num size; do
|
||||
if (( size < min_size )); then
|
||||
min_size=$size
|
||||
min_num=$num
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Original size was ${original_size_kb}KB"
|
||||
echo "Smallest compressed size was ${min_size} bytes for NUM=${min_num}"
|
||||
} < "${tmpfile}"
|
||||
|
||||
# Clean up
|
||||
rm "${tmpfile}"
|
||||
|
||||
# Use the smallest NUM value found in the test command
|
||||
brotli --force --lgwin="${min_num}" "${filename}" -o "${filename}.br"
|
||||
|
||||
# find the difference in the file sizes
|
||||
compressed_size_kb=$(du -k "${filename}.br" | cut -f1)
|
||||
size_difference=$(bc <<< "${original_size_kb} - ${compressed_size_kb}")
|
||||
echo "The compressed file is ${size_difference}KB smaller than the original file"
|
|
@ -1,45 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -f ../individual_build.sh ]; then
|
||||
echo "Please run from the package base directory!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${BUILD_FLAGS}" ]; then
|
||||
BUILD_FLAGS="--release"
|
||||
fi
|
||||
|
||||
if [ -z "$(which rsync)" ]; then
|
||||
echo "Cannot find rsync which is needed to move things around, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$(which wasm-pack)" ]; then
|
||||
echo "Cannot find wasm-pack which is needed to build the UI, quitting!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ./pkg
|
||||
|
||||
echo "Cleaning up WASM files before build..."
|
||||
find ./pkg/ -name 'kanidmd*' -exec rm "{}" \;
|
||||
|
||||
# we can disable this since we want it to expand
|
||||
# shellcheck disable=SC2086
|
||||
wasm-pack build ${BUILD_FLAGS} --no-typescript --target web --no-pack
|
||||
|
||||
echo "######################"
|
||||
echo "Moving files around..."
|
||||
echo "######################"
|
||||
touch ./pkg/ANYTHING_HERE_WILL_BE_DELETED_ADD_TO_SRC && \
|
||||
rm ./pkg/.gitignore
|
||||
|
||||
echo "######################"
|
||||
echo "Moving files up into the webui pkg dir..."
|
||||
echo "######################"
|
||||
rsync -av pkg/* ../pkg/
|
||||
|
||||
echo "######################"
|
||||
echo " Done!"
|
||||
echo "######################"
|
|
@ -1,42 +0,0 @@
|
|||
[package]
|
||||
name = "kanidmd_web_ui_login_flows"
|
||||
description = "Kanidm Server Web UI - Login Flows"
|
||||
documentation = "https://docs.rs/kanidm/latest/kanidm/"
|
||||
|
||||
version = { workspace = true }
|
||||
authors = [
|
||||
"William Brown <william@blackhats.net.au>",
|
||||
"James Hodgkinson <james@terminaloutcomes.com>",
|
||||
]
|
||||
rust-version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
gloo = { workspace = true }
|
||||
js-sys = { workspace = true }
|
||||
kanidm_proto = { workspace = true, features = ["wasm"] }
|
||||
kanidmd_web_ui_shared = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde-wasm-bindgen = { workspace = true }
|
||||
wasm-bindgen = { workspace = true }
|
||||
wasm-bindgen-futures = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
yew = { workspace = true, features = ["csr"] }
|
||||
yew-router = { workspace = true }
|
||||
time = { workspace = true }
|
||||
gloo-utils = { workspace = true }
|
||||
web-sys = { workspace = true, features = [
|
||||
"CredentialsContainer",
|
||||
"Location",
|
||||
"Navigator",
|
||||
"Window",
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = { workspace = true }
|
|
@ -1,73 +0,0 @@
|
|||
//! This handles the login/auth flows, and is designed to be smol and snappy
|
||||
//! so it loads fast and gets the user to where they need to go!
|
||||
//!
|
||||
//! - /ui/login
|
||||
//! - /ui/oauth2
|
||||
//! - /ui/reauth
|
||||
|
||||
mod components;
|
||||
mod oauth2;
|
||||
pub mod router;
|
||||
|
||||
use gloo::console;
|
||||
use kanidmd_web_ui_shared::constants::URL_LOGIN;
|
||||
use kanidmd_web_ui_shared::utils::window;
|
||||
use router::LoginRoute;
|
||||
#[allow(unused_imports)] // because it's needed to compile wasm things
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::{JsValue, UnwrapThrowExt};
|
||||
use yew::{html, Html};
|
||||
use yew_router::{BrowserRouter, Switch};
|
||||
|
||||
use crate::components::{LoginApp, LoginWorkflow};
|
||||
use crate::oauth2::Oauth2App;
|
||||
|
||||
// Needed for yew to pass by value
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
/// Handle routes for the login_flows app
|
||||
fn switch(route: LoginRoute) -> Html {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!(format!("UserUiApp::switch -> {:?}", route).as_str());
|
||||
match route {
|
||||
LoginRoute::Login => html! {<LoginApp workflow={LoginWorkflow::Login} />},
|
||||
LoginRoute::Reauth => html! {<LoginApp workflow={LoginWorkflow::Reauth} />},
|
||||
LoginRoute::Oauth2 => html! {<Oauth2App />},
|
||||
LoginRoute::NotFound => {
|
||||
console::error!("Unknown route {}, showing login flow");
|
||||
window()
|
||||
.location()
|
||||
.set_href(URL_LOGIN)
|
||||
.expect_throw("Failed to redirect user to the login page!");
|
||||
html! { <a href={URL_LOGIN}>{"Click here to return to the login page..."}</a> }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginFlowsApp {}
|
||||
|
||||
impl yew::Component for LoginFlowsApp {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_ctx: &yew::Context<Self>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn view(&self, _ctx: &yew::Context<Self>) -> Html {
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
<Switch<LoginRoute> render={switch} />
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the entry point of the web front end.
|
||||
///
|
||||
/// This triggers the manager app to load and begin its event loop.
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
|
||||
pub fn run_app() -> Result<(), JsValue> {
|
||||
yew::Renderer::<LoginFlowsApp>::new().render();
|
||||
Ok(())
|
||||
}
|
|
@ -1,536 +0,0 @@
|
|||
use gloo::console;
|
||||
use kanidm_proto::constants::uri::{OAUTH2_AUTHORISE, OAUTH2_AUTHORISE_PERMIT};
|
||||
use kanidm_proto::constants::{APPLICATION_JSON, KOPID};
|
||||
pub use kanidm_proto::oauth2::{AuthorisationRequest, AuthorisationResponse};
|
||||
use kanidmd_web_ui_shared::constants::{CONTENT_TYPE, CSS_ALERT_DANGER, URL_OAUTH2};
|
||||
use kanidmd_web_ui_shared::utils::{do_alert_error, do_footer, window};
|
||||
use kanidmd_web_ui_shared::{
|
||||
add_body_form_classes, fetch_session_valid, logo_img, remove_body_form_classes, SessionStatus,
|
||||
};
|
||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{Request, RequestInit, RequestMode, RequestRedirect, Response};
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
use super::router::LoginRoute;
|
||||
use kanidmd_web_ui_shared::models::{
|
||||
pop_oauth2_authorisation_request, push_login_hint, push_oauth2_authorisation_request,
|
||||
push_return_location,
|
||||
};
|
||||
use kanidmd_web_ui_shared::{do_request, error::FetchError, utils, RequestMethod};
|
||||
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
enum State {
|
||||
LoginRequired,
|
||||
// We are in the process of checking the auth token to be sure we can proceed.
|
||||
TokenCheck,
|
||||
// Token check done, lets do it.
|
||||
SubmitAuthReq,
|
||||
Consent {
|
||||
client_name: String,
|
||||
#[allow(dead_code)]
|
||||
scopes: BTreeSet<String>,
|
||||
pii_scopes: BTreeSet<String>,
|
||||
consent_token: String,
|
||||
},
|
||||
ConsentGranted(String),
|
||||
AccessDenied(Option<String>),
|
||||
ErrInvalidRequest,
|
||||
}
|
||||
|
||||
pub struct Oauth2App {
|
||||
state: State,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Oauth2Msg {
|
||||
LoginRequired,
|
||||
LoginProceed,
|
||||
#[allow(dead_code)]
|
||||
ConsentGranted(String),
|
||||
TokenValid,
|
||||
Consent {
|
||||
client_name: String,
|
||||
scopes: BTreeSet<String>,
|
||||
pii_scopes: BTreeSet<String>,
|
||||
consent_token: String,
|
||||
},
|
||||
Redirect(String),
|
||||
AccessDenied {
|
||||
kopid: Option<String>,
|
||||
},
|
||||
Error {
|
||||
emsg: String,
|
||||
kopid: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<FetchError> for Oauth2Msg {
|
||||
fn from(fe: FetchError) -> Self {
|
||||
Oauth2Msg::Error {
|
||||
emsg: fe.as_string(),
|
||||
kopid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SessionStatus> for Oauth2Msg {
|
||||
fn from(value: SessionStatus) -> Self {
|
||||
match value {
|
||||
SessionStatus::TokenValid => Oauth2Msg::TokenValid,
|
||||
SessionStatus::LoginRequired => Oauth2Msg::LoginRequired,
|
||||
SessionStatus::Error { emsg, kopid } => Oauth2Msg::Error { emsg, kopid },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Oauth2App {
|
||||
/// Validate that the current auth token's OK
|
||||
async fn fetch_session_valid() -> Result<Oauth2Msg, FetchError> {
|
||||
fetch_session_valid().await.map(|v| v.into())
|
||||
}
|
||||
|
||||
async fn fetch_authreq(authreq: AuthorisationRequest) -> Result<Oauth2Msg, FetchError> {
|
||||
let req_jsvalue_1 = authreq
|
||||
.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
|
||||
.expect("Failed to serialise request");
|
||||
let req_jsvalue =
|
||||
js_sys::JSON::stringify(&req_jsvalue_1).expect_throw("failed to stringify");
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!(&format!("fetch_authreq post {}", req_jsvalue));
|
||||
|
||||
let (kopid, status, value, headers) =
|
||||
do_request(OAUTH2_AUTHORISE, RequestMethod::POST, Some(req_jsvalue)).await?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!(&format!("fetch_authreq result {}", status));
|
||||
|
||||
if status == 200 {
|
||||
let state: AuthorisationResponse = serde_wasm_bindgen::from_value(value)
|
||||
.map_err(|e| {
|
||||
let e_msg = format!("serde error -> {:?}", e);
|
||||
console::error!(e_msg.as_str());
|
||||
})
|
||||
.expect_throw("Invalid response type");
|
||||
match state {
|
||||
AuthorisationResponse::ConsentRequested {
|
||||
client_name,
|
||||
scopes,
|
||||
pii_scopes,
|
||||
consent_token,
|
||||
} => Ok(Oauth2Msg::Consent {
|
||||
client_name,
|
||||
scopes,
|
||||
pii_scopes,
|
||||
consent_token,
|
||||
}),
|
||||
AuthorisationResponse::Permitted => {
|
||||
if let Some(loc) = headers.get("location").ok().flatten() {
|
||||
Ok(Oauth2Msg::Redirect(loc))
|
||||
} else {
|
||||
Ok(Oauth2Msg::Error {
|
||||
emsg: "no location header".to_string(),
|
||||
kopid,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if status == 403 {
|
||||
Ok(Oauth2Msg::AccessDenied { kopid })
|
||||
} else {
|
||||
let emsg = value.as_string().unwrap_or_default();
|
||||
Ok(Oauth2Msg::Error { emsg, kopid })
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_consent_token(consent_token: String) -> Result<Oauth2Msg, FetchError> {
|
||||
let req_jsvalue = consent_token
|
||||
.serialize(&serde_wasm_bindgen::Serializer::json_compatible())
|
||||
.expect("Failed to serialise request");
|
||||
let req_jsvalue = js_sys::JSON::stringify(&req_jsvalue).expect_throw("failed to stringify");
|
||||
|
||||
let opts = RequestInit::new();
|
||||
opts.set_method("POST");
|
||||
opts.set_mode(RequestMode::SameOrigin);
|
||||
opts.set_redirect(RequestRedirect::Manual); // can't replace with do_request because of this
|
||||
|
||||
opts.set_body(&req_jsvalue);
|
||||
|
||||
let request = Request::new_with_str_and_init(OAUTH2_AUTHORISE_PERMIT, &opts)?;
|
||||
|
||||
request
|
||||
.headers()
|
||||
.set(CONTENT_TYPE, APPLICATION_JSON)
|
||||
.expect_throw("failed to set header");
|
||||
|
||||
/*
|
||||
if let Some(bearer_token) = get_bearer_token() {
|
||||
request
|
||||
.headers()
|
||||
.set("authorization", &bearer_token)
|
||||
.expect_throw("failed to set authorisation header");
|
||||
}
|
||||
*/
|
||||
|
||||
let window = utils::window();
|
||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||
let resp: Response = resp_value.dyn_into().expect_throw("Invalid response type");
|
||||
let status = resp.status();
|
||||
let headers = resp.headers();
|
||||
|
||||
let kopid = headers.get(KOPID).ok().flatten();
|
||||
|
||||
if status == 200 {
|
||||
if let Some(loc) = headers.get("location").ok().flatten() {
|
||||
Ok(Oauth2Msg::Redirect(loc))
|
||||
} else {
|
||||
Ok(Oauth2Msg::Error {
|
||||
emsg: "no location header".to_string(),
|
||||
kopid,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
let emsg = "Redirect error".to_string();
|
||||
Ok(Oauth2Msg::Error { emsg, kopid })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Oauth2App {
|
||||
type Message = Oauth2Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("oauth2::create");
|
||||
|
||||
// Do we have a query here?
|
||||
// Did we get sent a valid Oauth2 request?
|
||||
let location = ctx
|
||||
.link()
|
||||
.location()
|
||||
.expect_throw("Can't access browser current location");
|
||||
|
||||
let query: Option<AuthorisationRequest> = location
|
||||
.query()
|
||||
.map_err(|e| {
|
||||
let e_msg = format!(
|
||||
"failed to decode authorisation request url parameters -> {:?}",
|
||||
e
|
||||
);
|
||||
console::error!(e_msg.as_str());
|
||||
})
|
||||
.ok()
|
||||
.or_else(|| {
|
||||
console::log!("using previously storage oauth2 authorisation request if possible");
|
||||
pop_oauth2_authorisation_request()
|
||||
});
|
||||
|
||||
add_body_form_classes!();
|
||||
|
||||
// If we have neither we need to say that we can not proceed at all.
|
||||
let query = match query {
|
||||
Some(q) => q,
|
||||
None => {
|
||||
return Oauth2App {
|
||||
state: State::ErrInvalidRequest,
|
||||
};
|
||||
}
|
||||
};
|
||||
console::debug!(format!("{query:?}",));
|
||||
|
||||
// In the query, if this is openid there MAY be a hint
|
||||
// as to the users name.
|
||||
// See: https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters
|
||||
// specifically, login_hint
|
||||
if let Some(login_hint) = query.oidc_ext.login_hint.clone() {
|
||||
push_login_hint(login_hint)
|
||||
}
|
||||
// Push the request down. This covers if we move to LoginRequired so we can restore where
|
||||
// we were / what we were doing.
|
||||
push_oauth2_authorisation_request(query);
|
||||
|
||||
// Start the fetch req.
|
||||
// Put the fetch handle into the consent type.
|
||||
ctx.link().send_future(async {
|
||||
match Self::fetch_session_valid().await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
|
||||
Oauth2App {
|
||||
state: State::TokenCheck,
|
||||
}
|
||||
}
|
||||
|
||||
fn changed(&mut self, _ctx: &Context<Self>, _props: &Self::Properties) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("oauth2::change");
|
||||
false
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!(&format!("oauth2::update {:?}", msg));
|
||||
|
||||
match msg {
|
||||
Oauth2Msg::LoginRequired => {
|
||||
self.state = State::LoginRequired;
|
||||
true
|
||||
}
|
||||
Oauth2Msg::LoginProceed => {
|
||||
let current_loc = window()
|
||||
.location()
|
||||
.as_string()
|
||||
.unwrap_or(URL_OAUTH2.to_string());
|
||||
push_return_location(¤t_loc);
|
||||
|
||||
ctx.link()
|
||||
.navigator()
|
||||
.expect_throw("failed to read history")
|
||||
.push(&LoginRoute::Login);
|
||||
// Don't need to redraw as we are yolo-ing out.
|
||||
false
|
||||
}
|
||||
Oauth2Msg::TokenValid => {
|
||||
// Okay we can proceed, pop the query.
|
||||
let ar = pop_oauth2_authorisation_request();
|
||||
|
||||
self.state = match (&self.state, ar) {
|
||||
(State::TokenCheck, Some(ar)) => {
|
||||
ctx.link().send_future(async {
|
||||
match Self::fetch_authreq(ar).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
State::SubmitAuthReq
|
||||
}
|
||||
_ => {
|
||||
console::error!("Invalid state transition");
|
||||
State::ErrInvalidRequest
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
Oauth2Msg::Consent {
|
||||
client_name,
|
||||
scopes,
|
||||
pii_scopes,
|
||||
consent_token,
|
||||
} => {
|
||||
self.state = match &self.state {
|
||||
State::SubmitAuthReq => State::Consent {
|
||||
client_name,
|
||||
scopes,
|
||||
pii_scopes,
|
||||
consent_token,
|
||||
},
|
||||
_ => {
|
||||
console::error!("Invalid state transition");
|
||||
State::ErrInvalidRequest
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
Oauth2Msg::ConsentGranted(_) => {
|
||||
self.state = match &self.state {
|
||||
State::Consent {
|
||||
consent_token,
|
||||
client_name,
|
||||
..
|
||||
} => {
|
||||
let cr_c = consent_token.clone();
|
||||
ctx.link().send_future(async {
|
||||
match Self::fetch_consent_token(cr_c).await {
|
||||
Ok(v) => v,
|
||||
Err(v) => v.into(),
|
||||
}
|
||||
});
|
||||
State::ConsentGranted(client_name.to_string())
|
||||
}
|
||||
_ => {
|
||||
console::error!("Invalid state transition");
|
||||
State::ErrInvalidRequest
|
||||
}
|
||||
};
|
||||
// We need to send off fetch task here.
|
||||
true
|
||||
}
|
||||
Oauth2Msg::AccessDenied { kopid } => {
|
||||
console::error!(format!("opid - {:?}", kopid).as_str());
|
||||
self.state = State::AccessDenied(kopid);
|
||||
true
|
||||
}
|
||||
Oauth2Msg::Error { emsg, kopid } => {
|
||||
self.state = State::ErrInvalidRequest;
|
||||
console::error!(format!("opid - {:?}, msg - {}", kopid, emsg).as_str());
|
||||
true
|
||||
}
|
||||
Oauth2Msg::Redirect(loc) => {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!(format!("Redirecting to {}", loc).as_str());
|
||||
// Send the location here, and then update will trigger the redir via
|
||||
// https://docs.rs/web-sys/0.3.51/web_sys/struct.Location.html#method.replace
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/Location/replace
|
||||
|
||||
let location = utils::window().location();
|
||||
|
||||
match location.replace(loc.as_str()) {
|
||||
// No need to redraw, we are leaving.
|
||||
Ok(_) => false,
|
||||
Err(e) => {
|
||||
// Something went bang, oops.
|
||||
console::error!(format!("{:?}", e).as_str());
|
||||
self.state = State::ErrInvalidRequest;
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("oauth2::rendered");
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
#[cfg(debug_assertions)]
|
||||
console::debug!("oauth2::view");
|
||||
|
||||
let body_content = match &self.state {
|
||||
State::LoginRequired => {
|
||||
// <body class="html-body form-body">
|
||||
|
||||
html! {
|
||||
<form
|
||||
onsubmit={ ctx.link().callback(|e: SubmitEvent| {
|
||||
console::debug!("oauth2::view -> LoginRequired - prevent_default()");
|
||||
e.prevent_default();
|
||||
Oauth2Msg::LoginProceed
|
||||
} ) }
|
||||
action="javascript:void(0);"
|
||||
>
|
||||
<h1 class="h3 mb-3 fw-normal">
|
||||
// TODO: include the domain display name here, and the RS display name?
|
||||
{"Sign in to proceed" }
|
||||
</h1>
|
||||
<button autofocus=true class="w-100 btn btn-lg btn-primary" type="submit">
|
||||
{ "Sign in" }
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
State::Consent {
|
||||
client_name,
|
||||
scopes: _,
|
||||
pii_scopes,
|
||||
consent_token: _,
|
||||
} => {
|
||||
let client_name = client_name.clone();
|
||||
|
||||
let pii_req = if pii_scopes.is_empty() {
|
||||
html! {
|
||||
<div>
|
||||
<p>{ "This site will not have access to your personal information." }</p>
|
||||
<p>{ "If this site requests personal information in the future we will check with you." }</p>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<div>
|
||||
<p>{ "This site has requested to see the following personal information." }</p>
|
||||
<ul>
|
||||
{
|
||||
pii_scopes.iter().map(|s| html! { <li>{ s }</li> } ).collect::<Html>()
|
||||
}
|
||||
</ul>
|
||||
<p>{ "If this site requests different personal information in the future we will check with you again." }</p>
|
||||
</div>
|
||||
}
|
||||
};
|
||||
|
||||
// <body class="html-body form-body">
|
||||
let app_name = client_name.clone();
|
||||
html! {
|
||||
<form
|
||||
onsubmit={ ctx.link().callback(move |e: SubmitEvent| {
|
||||
console::debug!("oauth2::view -> Consent - prevent_default()");
|
||||
e.prevent_default();
|
||||
Oauth2Msg::ConsentGranted(client_name.to_string())
|
||||
} ) }
|
||||
action="javascript:void(0);"
|
||||
>
|
||||
<h2 class="h3 mb-3 fw-normal">{"Consent to Proceed to " }{ app_name }</h2>
|
||||
{ pii_req }
|
||||
|
||||
<div class="text-center">
|
||||
<button autofocus=true class="w-100 btn btn-lg btn-primary" type="submit">{ "Proceed" }</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
State::ConsentGranted(app_name) => {
|
||||
html! {
|
||||
<div class="alert alert-success" role="alert">
|
||||
<h2 class="text-center">{ "Taking you to " }{app_name}{" ... " }</h2>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
State::SubmitAuthReq | State::TokenCheck => {
|
||||
html! {
|
||||
<div class="alert alert-light" role="alert">
|
||||
<h2 class="text-center">{ "Processing ... " }</h2>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
State::AccessDenied(kopid) => {
|
||||
html! {
|
||||
<div class={CSS_ALERT_DANGER} role="alert">
|
||||
<h1>{ "Access Denied" } </h1>
|
||||
<p>
|
||||
{ "You do not have access to the requested resources." }
|
||||
</p>
|
||||
<p>
|
||||
{ if let Some(opid) = kopid {
|
||||
format!("Operation ID: {}", opid)
|
||||
} else {
|
||||
"Operation ID: -".to_string()
|
||||
}
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
State::ErrInvalidRequest => do_alert_error(
|
||||
"Invalid request",
|
||||
Some("Please close this window and try again from the beginning."),
|
||||
false,
|
||||
),
|
||||
};
|
||||
html! {
|
||||
<>
|
||||
<main class="form-signin">
|
||||
<center>
|
||||
{logo_img()}
|
||||
</center>
|
||||
<div class="container">
|
||||
{ body_content }
|
||||
</div>
|
||||
</main>
|
||||
{ do_footer() }
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy(&mut self, _ctx: &Context<Self>) {
|
||||
console::debug!("oauth2::destroy");
|
||||
remove_body_form_classes!();
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#![allow(clippy::disallowed_types)] // because `Routable` uses a hashmap
|
||||
use serde::{Deserialize, Serialize};
|
||||
use yew_router::Routable;
|
||||
|
||||
#[derive(Routable, PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum LoginRoute {
|
||||
#[at("/ui/login")]
|
||||
Login,
|
||||
#[at("/ui/reauth")]
|
||||
Reauth,
|
||||
|
||||
#[at("/ui/oauth2")]
|
||||
Oauth2,
|
||||
|
||||
#[not_found]
|
||||
#[at("/ui/login/404")]
|
||||
NotFound,
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// loads the module which loads the WASM. It's loaders all the way down.
|
||||
import init, { run_app } from '/pkg/kanidmd_web_ui_login_flows.js';
|
||||
async function main() {
|
||||
await init('/pkg/kanidmd_web_ui_login_flows_bg.wasm');
|
||||
run_app();
|
||||
}
|
||||
main()
|
6
server/web_ui/pkg/external/bootstrap.min.css
vendored
BIN
server/web_ui/pkg/external/bootstrap.min.css.br
vendored
BIN
server/web_ui/pkg/external/bootstrap.min.css.map.br
vendored
16
server/web_ui/pkg/external/confetti.js
vendored
|
@ -1,16 +0,0 @@
|
|||
var maxParticleCount=150;var particleSpeed=2;var startConfetti;var stopConfetti;var toggleConfetti;var removeConfetti;(function(){startConfetti=startConfettiInner;stopConfetti=stopConfettiInner;toggleConfetti=toggleConfettiInner;removeConfetti=removeConfettiInner;var colors=["DodgerBlue","OliveDrab","Gold","Pink","SlateBlue","LightBlue","Violet","PaleGreen","SteelBlue","SandyBrown","Chocolate","Crimson"]
|
||||
var streamingConfetti=false;var animationTimer=null;var particles=[];var waveAngle=0;function resetParticle(particle,width,height){particle.color=colors[(Math.random()*colors.length)|0];particle.x=Math.random()*width;particle.y=Math.random()*height-height;particle.diameter=Math.random()*10+5;particle.tilt=Math.random()*10-10;particle.tiltAngleIncrement=Math.random()*0.07+0.05;particle.tiltAngle=0;return particle;}
|
||||
function startConfettiInner(){var width=window.innerWidth;var height=window.innerHeight;window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(callback){return window.setTimeout(callback,16.6666667);};})();var canvas=document.getElementById("confetti-canvas");if(canvas===null){canvas=document.createElement("canvas");canvas.setAttribute("id","confetti-canvas");canvas.setAttribute("style","display:block;z-index:999999;pointer-events:none");document.body.appendChild(canvas);canvas.width=width;canvas.height=height;window.addEventListener("resize",function(){canvas.width=window.innerWidth;canvas.height=window.innerHeight;},true);}
|
||||
var context=canvas.getContext("2d");while(particles.length<maxParticleCount)
|
||||
particles.push(resetParticle({},width,height));streamingConfetti=true;if(animationTimer===null){(function runAnimation(){context.clearRect(0,0,window.innerWidth,window.innerHeight);if(particles.length===0)
|
||||
animationTimer=null;else{updateParticles();drawParticles(context);animationTimer=requestAnimFrame(runAnimation);}})();}}
|
||||
function stopConfettiInner(){streamingConfetti=false;}
|
||||
function removeConfettiInner(){stopConfetti();particles=[];}
|
||||
function toggleConfettiInner(){if(streamingConfetti)
|
||||
stopConfettiInner();else
|
||||
startConfettiInner();}
|
||||
function drawParticles(context){var particle;var x;for(var i=0;i<particles.length;i++){particle=particles[i];context.beginPath();context.lineWidth=particle.diameter;context.strokeStyle=particle.color;x=particle.x+particle.tilt;context.moveTo(x+particle.diameter/2,particle.y);context.lineTo(x,particle.y+particle.tilt+particle.diameter/2);context.stroke();}}
|
||||
function updateParticles(){var width=window.innerWidth;var height=window.innerHeight;var particle;waveAngle+=0.01;for(var i=0;i<particles.length;i++){particle=particles[i];if(!streamingConfetti&&particle.y<-15)
|
||||
particle.y=height+100;else{particle.tiltAngle+=particle.tiltAngleIncrement;particle.x+=Math.sin(waveAngle);particle.y+=(Math.cos(waveAngle)+particle.diameter+particleSpeed)*0.5;particle.tilt=Math.sin(particle.tiltAngle)*15;}
|
||||
if(particle.x>width+20||particle.x<-20||particle.y>height){if(streamingConfetti&&particles.length<=maxParticleCount)
|
||||
resetParticle(particle,width,height);else{particles.splice(i,1);i--;}}}}})();
|
9
server/web_ui/pkg/external/viz.js
vendored
BIN
server/web_ui/pkg/external/viz.js.br
vendored
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,834 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="svg5800"
|
||||
version="1.1"
|
||||
viewBox="0 0 39.6875 39.6875"
|
||||
height="150"
|
||||
width="150"
|
||||
sodipodi:docname="icon-accounts.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||
inkscape:export-filename="../94e4957b/kani-yellow-sign.png"
|
||||
inkscape:export-xdpi="86.699997"
|
||||
inkscape:export-ydpi="86.699997"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1391"
|
||||
inkscape:window-height="819"
|
||||
id="namedview108"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.2181916"
|
||||
inkscape:cx="99.179892"
|
||||
inkscape:cy="83.175864"
|
||||
inkscape:window-x="49"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer3"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="0,-35.312501"
|
||||
orientation="0,1"
|
||||
id="guide932"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleHorizontal"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="75,39.687501"
|
||||
orientation="-1,0"
|
||||
id="guide934"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleVertical"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="4.7580686,-10.089218"
|
||||
orientation="0,-1"
|
||||
id="guide1652"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs5794">
|
||||
<radialGradient
|
||||
id="Gradient_4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="420.20801"
|
||||
cy="346.897"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8111" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8113" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="385.79401"
|
||||
cy="98.971001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8116" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8118" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_6"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="154.649"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8121" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8123" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="120.117"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8126" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8128" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_8"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="660.41699"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8131" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8133" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="625.88501"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8136" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8138" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="283.38901"
|
||||
cy="577.77899"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8141" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8143" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_11"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="213.711"
|
||||
cy="337.353"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8146" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8148" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="Gradient_12"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="395.94601"
|
||||
y1="909.60699"
|
||||
x2="398.86099"
|
||||
y2="889.30902">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8151" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8153" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="364.41199"
|
||||
y1="920.81097"
|
||||
x2="381.88199"
|
||||
y2="898.88202">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8156" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="400.103"
|
||||
y1="884.01398"
|
||||
x2="414.327"
|
||||
y2="886.43201">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8161" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8163" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="401.52899"
|
||||
y1="-883.02899"
|
||||
x2="418.35501"
|
||||
y2="-884.72101"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8166" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8168" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_1">
|
||||
<path
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c -2.74,0.34 -5.51,-0.08 -8.21,-0.56 v 0 c 1.75,0.6 3.93,1.12 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8171" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_16"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="406.53"
|
||||
y1="880.51599"
|
||||
x2="409.40302"
|
||||
y2="880.80499">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8174" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8176" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_17"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="452.20001"
|
||||
y1="905.45599"
|
||||
x2="444.604"
|
||||
y2="892.92102">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8179" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8181" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_18"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="462.254"
|
||||
y1="893.729"
|
||||
x2="456.45901"
|
||||
y2="887.92401">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8184" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8186" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_19"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="446.13501"
|
||||
y1="882.91602"
|
||||
x2="429.77499"
|
||||
y2="883.61603">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8189" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8191" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_20"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="443.24799"
|
||||
y1="-882.92798"
|
||||
x2="426.452"
|
||||
y2="-884.64899"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8194" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8196" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_2">
|
||||
<path
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -3.99,0.52 -9.46,1.2 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8199" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_21"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.23401"
|
||||
y1="880.48499"
|
||||
x2="435.36099"
|
||||
y2="880.78003">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8202" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8204" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="Gradient_22"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="421.086"
|
||||
cy="879.30603"
|
||||
r="5.8280001">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#E61F19"
|
||||
id="stop8207" />
|
||||
<stop
|
||||
offset="0.988"
|
||||
stop-color="#9E282C"
|
||||
id="stop8209" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#9E282C"
|
||||
id="stop8211" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_23"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="146.832"
|
||||
cy="-316.11899"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8214" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8216" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55.174999"
|
||||
cy="-176.464"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8219" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8221" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_25"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="565.53101"
|
||||
cy="-165.11301"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8224" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8226" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_26"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="333.47"
|
||||
cy="-63.138"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8229" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8231" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_27"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="536.58099"
|
||||
cy="578.03198"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8234" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8236" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_28"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="553.57397"
|
||||
cy="328.29001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8239" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8241" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_29"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="488.81201"
|
||||
cy="-304.62601"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8244" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8246" />
|
||||
</radialGradient>
|
||||
<symbol
|
||||
id="balloons"
|
||||
viewBox="0 0 825 962">
|
||||
<g
|
||||
style="fill:none;stroke:#eccb78;stroke-width:4.069;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="g8261">
|
||||
<path
|
||||
d="M 291.13,584.61 422.41,889.24 540.38,589.26"
|
||||
id="path8249" />
|
||||
<path
|
||||
d="m 426.95,357.75 -4.54,531.49"
|
||||
id="path8251" />
|
||||
<path
|
||||
d="M 158.17,411.35 421.71,889.24 667.1,402.98"
|
||||
id="path8253" />
|
||||
<path
|
||||
d="m 415.21,958.51 c 8.81,-23.5 6.08,-71.63 6.08,-71.63 -3.66,47 -29.02,70.1 -29.02,70.1"
|
||||
id="path8255" />
|
||||
<path
|
||||
d="m 456.29,956.29 c 0,0 -26.52,-21.77 -32.58,-68.52 0,0 -0.26,48.21 9.75,71.23"
|
||||
id="path8257" />
|
||||
<path
|
||||
d="m 404.06,957.77 c 0,0 13.62,-20.66 18.45,-69.2"
|
||||
id="path8259" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_4)"
|
||||
d="m 423.73,337.05 -21.46,35.03 c -1.86,3.04 0.32,6.93 3.89,6.93 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.83 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.28 -3.95,-2.28 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8263" />
|
||||
<path
|
||||
style="fill:url(#Gradient_5)"
|
||||
d="m 273.05,178.98 c 0,97.08 68.93,175.78 153.96,175.79 v 0 c 85.03,0 153.96,-78.7 153.97,-175.79 v 0 C 580.98,81.9 512.05,3.2 427.01,3.2 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8265" />
|
||||
<path
|
||||
style="fill:url(#Gradient_6)"
|
||||
d="m 158.17,425.62 -21.46,35.02 c -1.86,3.04 0.32,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 L 166,425.71 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8267" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_7)"
|
||||
d="m 7.37,267.55 c 0,97.08 68.93,175.78 153.97,175.78 v 0 c 85.03,0 153.96,-78.7 153.96,-175.78 v 0 C 315.3,170.47 246.37,91.77 161.34,91.77 v 0 C 76.31,91.77 7.38,170.47 7.37,267.55 Z"
|
||||
id="path8269" />
|
||||
<path
|
||||
style="fill:url(#Gradient_8)"
|
||||
d="m 663.94,425.62 -21.46,35.02 c -1.86,3.04 0.33,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8271" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_9)"
|
||||
d="m 513.14,267.55 c 0,97.08 68.93,175.78 153.96,175.78 v 0 c 85.03,0 153.96,-78.7 153.97,-175.78 v 0 C 821.07,170.47 752.14,91.77 667.1,91.77 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8273" />
|
||||
<path
|
||||
style="fill:url(#Gradient_10)"
|
||||
d="m 285.46,567.53 -16.21,37.74 c -1.41,3.27 1.31,6.82 4.83,6.3 v 0 l 41.28,-5.97 c 3.47,-0.5 5.1,-4.58 2.93,-7.33 v 0 l -25.06,-31.76 c -0.93,-1.17 -2.25,-1.74 -3.57,-1.74 v 0 c -1.72,0 -3.42,0.96 -4.2,2.76 z"
|
||||
id="path8275" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_11)"
|
||||
d="m 240.79,236.67 c -84.15,12.18 -141.11,99.94 -127.2,196.02 v 0 c 13.9,96.08 93.39,164.1 177.54,151.92 v 0 c 84.15,-12.18 141.1,-99.94 127.21,-196.02 v 0 C 405.52,300 336.93,235.26 260.34,235.26 v 0 c -6.47,0 -12.99,0.46 -19.55,1.41 z"
|
||||
id="path8277" />
|
||||
<path
|
||||
style="fill:url(#Gradient_27)"
|
||||
d="M 542.05,569.11 513.87,599 c -2.44,2.59 -1.1,6.85 2.38,7.59 v 0 l 40.83,8.54 c 3.43,0.72 6.36,-2.55 5.25,-5.88 v 0 l -12.64,-38.43 c -0.66,-2.01 -2.48,-3.13 -4.35,-3.14 v 0 c -1.18,0 -2.38,0.46 -3.29,1.43 z"
|
||||
id="path8279" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_28)"
|
||||
d="m 426.83,383.51 c -19.89,95.02 31.46,186.18 114.68,203.6 v 0 c 83.23,17.42 166.82,-45.49 186.71,-140.52 v 0 C 748.11,351.57 696.76,260.41 613.54,242.99 v 0 c -9.34,-1.96 -18.68,-2.9 -27.94,-2.89 v 0 c -73.25,0 -141.11,59.05 -158.77,143.41 z"
|
||||
id="path8281" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_23)"
|
||||
d="m 126.74,409.71 c 0,0 29.93,-94.86 60.85,-110.42 19.92,-10.03 -4.23,-30.39 -27.01,-14.05 -6.7,5.14 -12.35,11.69 -17.06,18.66 -14.36,21.28 -19.56,46.01 -20.09,71.27 v 0.02 c -0.07,11.6 1.32,23.12 3.31,34.52 z"
|
||||
id="path8283" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_24)"
|
||||
d="m 30.74,269.01 c 0,0 34.33,-93.36 65.93,-107.45 20.37,-9.09 -2.81,-30.55 -26.32,-15.3 0,0 -51.89,32.72 -39.61,122.75 z"
|
||||
id="path8285" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_25)"
|
||||
d="m 537.49,256.64 c 0,0 37.96,-91.94 70.09,-104.8 20.71,-8.29 -1.61,-30.64 -25.71,-16.31 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8287" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_26)"
|
||||
d="m 305.43,154.66 c 0,0 37.96,-91.94 70.09,-104.79 20.71,-8.28 -1.61,-30.64 -25.71,-16.32 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8289" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_29)"
|
||||
d="m 454.08,393.82 c 0,0 44.65,-88.88 77.64,-99.32 21.27,-6.73 0.66,-30.67 -24.42,-18.17 0,0 -55.25,26.66 -53.22,117.49 z"
|
||||
id="path8291" />
|
||||
<path
|
||||
style="fill:url(#Gradient_12)"
|
||||
d="m 375.83,907.75 9.08,1.65 c -1.21,2.8 0.79,11.89 0.79,11.89 v 0 c 8.26,-15.42 34.5,-34.41 33.81,-33.91 v 0 l 0.71,-5.79 c -24.03,1.57 -44.39,26.16 -44.39,26.16 z"
|
||||
id="path8293" />
|
||||
<path
|
||||
style="fill:url(#Gradient_13)"
|
||||
d="m 380.2,872.6 c 13.6,7.74 40.82,5.99 40.82,5.99 v 0 c -22.8,-5.81 -32.93,-7.21 -37.4,-7.21 v 0 c -4.17,0 -3.42,1.22 -3.42,1.22 z"
|
||||
id="path8295" />
|
||||
<path
|
||||
style="fill:url(#Gradient_14)"
|
||||
d="m 380.45,890.39 c 7.74,5.62 42.01,-3.08 42.01,-3.09 v 0 l -0.09,-10.01 c -42.04,-1.73 -42.31,-5.05 -42.31,-5.05 v 0 z"
|
||||
id="path8297" />
|
||||
<g
|
||||
clip-path="url(#Clip_1)"
|
||||
opacity="0.24"
|
||||
id="g8301">
|
||||
<path
|
||||
style="fill:url(#Gradient_15)"
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c 0,0 -3,0.5 -8.21,-0.56 2.01,0.59 4.41,1.58 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8299" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_16)"
|
||||
d="m 409.38,881 c -1.53,-0.45 -2.83,-0.68 -2.83,-0.68 v 0 c 1.01,0.28 1.95,0.5 2.83,0.68 z"
|
||||
id="path8303" />
|
||||
<path
|
||||
style="fill:url(#Gradient_17)"
|
||||
d="m 425.53,887.37 c 0,0 25.53,18.33 33.88,33.85 v 0 c 0,0 1.98,-9.1 0.76,-11.89 v 0 l 9.08,-1.67 c 0,0 -20.4,-24.55 -44.44,-26.08 v 0 z"
|
||||
id="path8305" />
|
||||
<path
|
||||
style="fill:url(#Gradient_18)"
|
||||
d="m 423.74,878.59 c 0,0 40.72,9.96 40.43,-5.69 v 0 c -0.01,-0.45 0.33,-1.72 -3.83,-1.73 v 0 c -4.58,0 -14.62,1.54 -36.6,7.42 z"
|
||||
id="path8307" />
|
||||
<path
|
||||
style="fill:url(#Gradient_19)"
|
||||
d="m 422.39,877.29 -0.07,10.01 c 0,0 34.28,8.63 42.01,3 v 0 l -0.11,-17.86 c 0,0 -0.29,1.43 -41.83,4.85 z"
|
||||
id="path8309" />
|
||||
<g
|
||||
clip-path="url(#Clip_2)"
|
||||
opacity="0.24"
|
||||
id="g8313">
|
||||
<path
|
||||
style="fill:url(#Gradient_20)"
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -9.75,1.64 -12.88,-1.55 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8311" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_21)"
|
||||
d="m 435.38,880.98 c 0.88,-0.18 1.83,-0.4 2.83,-0.69 v 0 c 0,0 -1.3,0.23 -2.83,0.69 z"
|
||||
id="path8315" />
|
||||
<path
|
||||
style="fill:url(#Gradient_22)"
|
||||
d="m 417.09,877.31 c 0,0 -1.77,8.19 0.74,11.61 v 0 l 9.25,-0.01 c 0,0 2.64,-7.59 0.88,-11.59 v 0 c 0,0 -4.62,-1 -7.84,-1 v 0 c -1.6,0 -2.86,0.25 -3.03,0.99 z"
|
||||
id="path8317" />
|
||||
</symbol>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5797">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Kani"
|
||||
style="display:inline"
|
||||
transform="translate(-40.228511,-7.4385631)">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 47.256748,30.044057 c -1.108637,2.679174 1.907156,5.148881 1.920091,5.188787 -0.550848,-1.615849 -1.133032,-2.920248 -0.0623,-4.049623"
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.32966;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.32966;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 72.279451,29.867841 c 1.108639,2.679173 -1.907154,5.148881 -1.920091,5.188782 0.550847,-1.615844 1.133031,-2.920243 0.0623,-4.049619"
|
||||
id="path5408"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 59.687987,15.86156 c -0.431403,-0.0051 -0.84422,0.775615 -1.612258,2.30322 -2.32472,-2.556767 -2.443632,-2.587721 -3.24461,0.873588 -0.03747,0.01568 -0.07486,0.03161 -0.112266,0.0477 -2.928143,-1.755243 -3.079434,-1.768972 -2.857219,1.661998 -0.07111,0.05273 -0.142154,0.10618 -0.212947,0.160477 -3.000566,-1.188615 -3.130304,-1.113719 -2.371021,2.179539 -0.03555,0.03847 -0.0712,0.07676 -0.106646,0.115675 -3.058205,-0.826252 -3.143772,-0.702098 -2.003221,2.524684 -0.04894,0.0702 -0.09751,0.141613 -0.146165,0.212776 -3.446985,-0.368477 -3.517796,-0.301154 -1.765405,2.91037 -0.0085,0.01589 -0.01734,0.03109 -0.02591,0.04702 -1.4122,0.675083 -1.879711,1.497912 -2.548875,2.602365 -0.05195,2.190449 2.292587,4.07824 5.663674,6.223636 -1.158177,-2.146516 -2.969363,-3.234648 -3.31684,-5.897064 0.508886,-0.957788 1.374276,-1.288645 2.117359,-1.71958 8.116214,4.736605 16.686002,4.791513 25.235776,-0.181428 0.745079,0.433512 1.615611,0.763192 2.126555,1.72486 -0.347475,2.662414 -2.158831,3.750377 -3.317007,5.896892 3.371082,-2.145394 5.715783,-4.033017 5.663843,-6.223466 -0.650598,-1.073811 -1.113187,-1.88104 -2.436098,-2.545467 1.652553,-3.038888 1.495242,-3.06749 -1.973239,-2.695722 -0.02938,-0.03798 -0.05866,-0.07643 -0.08808,-0.114138 1.198204,-3.382817 1.123036,-3.471219 -2.107139,-2.594874 0.81753,-3.529305 0.708286,-3.543698 -2.564551,-2.242913 0.246522,-3.72022 0.158214,-3.712493 -2.930134,-1.860122 -0.823543,-3.566516 -0.920717,-3.555903 -3.27698,-0.964219 -0.886279,-1.626423 -1.352579,-2.440599 -1.790618,-2.445808 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:0.32966;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="matrix(0.32966003,0,0,0.32966003,25.875957,-8.7851129)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 51.475333,28.920487 c -0.168261,0.0013 -0.280434,0.01794 -0.262006,0.02931 0,0 -3.011135,3.934858 0.102216,6.151064 a 3.2132327,2.7286249 37.793943 0 0 0.473761,3.106624 3.2132327,2.7286249 37.793943 0 0 3.48277,1.307827 l -1.174949,-2.836952 3.031834,0.242419 a 3.2132327,2.7286249 37.793943 0 0 -2.31634,-2.937459 3.2132327,2.7286249 37.793943 0 0 -2.310205,0.003 c -0.613929,-0.449677 -1.525896,-1.623909 -0.01345,-4.112595 0.500447,-0.823475 -0.508826,-0.95705 -1.013621,-0.953144 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.32966;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
id="path8665"
|
||||
d="m 83.960168,109.11313 c -0.27485,0.43011 -0.4985,0.69147 -0.49798,0.62578 0,0 -14.965898,1.38701 -15.636208,-10.186101 a 9.7471106,8.2770874 84.335985 0 1 -7.216103,-6.22894 9.7471106,8.2770874 84.335985 0 1 2.259156,-11.0566 l 5.392134,7.59511 4.268531,-8.17939 a 9.7471106,8.2770874 84.335985 0 1 3.80891,10.68931 9.7471106,8.2770874 84.335985 0 1 -3.73468,5.92977 c 0.16465,2.302521 1.70979,6.539611 10.54286,6.669381 2.92274,0.043 1.63761,2.85111 0.81319,4.14154 z"
|
||||
style="display:none;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-up" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="kani-claw-right-overlay"
|
||||
style="display:inline"
|
||||
transform="translate(-40.228511,-7.4385631)">
|
||||
<path
|
||||
d="m 74.643953,26.251952 c 1.156883,-1.026462 1.383369,-2.311371 1.047116,-3.752599 l -2.436647,1.263643 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:0.32966;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523"
|
||||
inkscape:label="under-kani-claw" />
|
||||
<path
|
||||
id="path5732-74"
|
||||
d="m 71.753651,21.394807 c -0.719107,0.469439 -1.267535,1.208385 -1.51602,2.042676 -0.326817,1.104585 -0.08447,2.222568 0.632582,2.918124 -1.17999,3.220643 -3.314446,2.161056 -3.359552,2.118688 -0.362682,-0.282284 -1.70696,1.196822 0.175601,1.723889 2.940634,0.823316 4.211648,-1.804817 4.666738,-3.187938 0.808096,0.06183 1.654903,-0.257623 2.324887,-0.877051 1.011643,-0.938034 1.432188,-2.380843 1.04105,-3.571645 l -2.74009,1.385776 0.0019,-0.425981 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.32966;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.32966;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 71.753651,21.394807 c -0.719107,0.46944 -1.267535,1.208385 -1.51602,2.042676 -0.326817,1.104585 -0.08447,2.222568 0.632582,2.918125 -1.17999,3.220639 -3.314446,2.161052 -3.359552,2.118684 -0.362682,-0.282284 -1.70696,1.196821 0.175604,1.723888 2.940631,0.823316 4.211645,-1.804816 4.666735,-3.187934 0.808099,0.06183 1.654907,-0.257623 2.324891,-0.877051 1.011642,-0.938034 1.432189,-2.380843 1.04105,-3.571645 l -2.740091,1.385776 0.0019,-0.425981 z"
|
||||
id="path5728" />
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 71.753651,21.394807 c -0.719107,0.46944 -1.267535,1.208385 -1.51602,2.042676 -0.326817,1.104585 -0.08447,2.222568 0.632582,2.918125 -1.17999,3.220639 -3.314446,2.161052 -3.359552,2.118684 -0.362682,-0.282284 -1.70696,1.196821 0.175604,1.723888 2.940631,0.823316 4.211645,-1.804816 4.666735,-3.187934 0.808099,0.06183 1.654907,-0.257623 2.324891,-0.877051 1.011642,-0.938034 1.432189,-2.380843 1.04105,-3.571645 l -2.740091,1.385776 0.0019,-0.425981 z"
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.32966;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g7998"
|
||||
inkscape:label="party-hat"
|
||||
transform="matrix(1.0107117,0,0,0.94642879,-34.697969,-6.0098395)"
|
||||
style="display:none">
|
||||
<path
|
||||
style="display:inline;fill:#1da1f2;fill-opacity:1;stroke:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path7024"
|
||||
inkscape:label="party-hat-background"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 90.866459,64.772976 -1.399384,3.650367 c 0,0 6.297977,-0.0079 9.604616,-2.229612 3.306639,-2.221751 6.641769,-4.763148 6.637539,-5.892882 -0.004,-1.129737 -1.2244,-3.398221 -1.2244,-3.398221 0,0 -1.76379,2.983434 -5.089689,4.759036 -3.325897,1.775606 -6.256176,3.317156 -8.528682,3.111312 z"
|
||||
id="path7711"
|
||||
inkscape:label="yellow-middle" />
|
||||
<path
|
||||
style="fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.283815,50.496253 c 0,0 2.017636,-0.742584 2.746046,-1.209859 0.68409,-0.438843 2.540819,-1.493505 2.505569,-1.916931 -0.0353,-0.423423 0.90713,1.638551 0.90713,1.638551 0,0 -0.43327,0.543192 -1.447199,1.610006 -1.01394,1.066813 -1.72817,1.358505 -2.26456,1.622681 -0.53638,0.264174 -2.0866,0.861497 -2.636383,0.793816 -0.549783,-0.06768 0.189397,-2.538264 0.189397,-2.538264 z"
|
||||
id="path7713"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="yellow-top" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 109.92717,71.488689 c 0,0 -2.20481,3.007619 -3.4367,4.221512 -1.06044,1.044951 -3.3987,2.32693 -5.45873,3.108264 -2.060039,0.78133 -7.390321,2.031263 -10.319319,2.035505 -2.53475,0.0037 -3.102127,-0.17882 -4.727213,-0.614261 -1.010264,-0.270699 -0.801047,2.045289 -0.801047,2.045289 l 4.858605,2.209687 10.217314,-0.32013 c 0,0 3.08806,-0.85865 3.26326,-0.9226 0.17519,-0.06395 5.61136,-3.775927 5.91906,-4.176562 0.30769,-0.400637 1.97931,-2.854544 1.85876,-3.106917 -0.12055,-0.25237 -1.37399,-4.479787 -1.37399,-4.479787 z"
|
||||
id="path7715"
|
||||
sodipodi:nodetypes="csssscccsssc"
|
||||
inkscape:label="yellow-bottom" />
|
||||
<path
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.208385,72.747325 c 0,0 6.251797,0.04012 9.907566,-1.876691 3.875559,-2.032049 5.147419,-2.116642 8.954089,-7.814465 -0.0353,-0.423423 1.59724,3.704345 1.59724,3.704345 0,0 -2.99139,5.115034 -6.19574,6.653752 -4.079519,1.958969 -6.324966,2.675602 -8.934752,3.106262 -1.713747,0.282798 -4.8213,0.352969 -6.27215,-0.01279 -0.537127,-0.135411 0.943747,-3.760409 0.943747,-3.760409 z"
|
||||
id="path7982"
|
||||
sodipodi:nodetypes="csccssscc"
|
||||
inkscape:label="white-middle" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 92.993027,57.289539 c 0,0 3.629855,-0.719631 5.482954,-2.090937 0.65332,-0.483462 3.662839,-3.285322 4.163269,-4.079419 -0.0353,-0.423423 0.98376,2.839616 0.98376,2.839616 0,0 -1.55545,1.919882 -2.68768,2.888013 -1.118619,0.956483 -3.276219,2.193755 -4.815637,2.748644 -1.634013,0.588985 -3.388075,0.798009 -3.937858,0.730328 -0.549783,-0.06768 0.811192,-3.036245 0.811192,-3.036245 z"
|
||||
id="path7979"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="white-top" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ff00ff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path508"
|
||||
inkscape:label="party-hat-outline"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:#8f57a8;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.307706,40.797374 8.863844,3.5236 c -4.511069,-1.476791 -5.455019,1.171445 -8.289058,2.243988 0,0 5.051628,-7.95802 4.765018,-7.734177 -1.618949,1.264417 -2.259979,9.16058 -2.259979,9.16058 l -0.26088,-9.396127 3.698779,7.921822 -7.078677,-2.809491 8.818747,-2.23602 z"
|
||||
id="path3171-3"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="display:inline;fill:#0056ed;fill-opacity:1;stroke:#ae00ff;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 96.516104,39.086314 5.923406,7.476417 c -3.172509,-3.530708 -5.311942,-1.706696 -8.303144,-2.191314 0,0 8.348654,-4.375959 7.988584,-4.324981 -2.03392,0.28796 -6.529397,6.811072 -6.529397,6.811072 l 4.462297,-8.273038 -0.747319,8.710783 -4.732664,-5.966807 8.758203,2.462516 z"
|
||||
id="path3171"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="fill:#744eaa;fill-opacity:1;stroke:#8f57a8;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.749242,80.805507 -1.299196,-0.793626 -0.72012,1.516668 -1.19957,0.02641 1.07959,1.592728 -0.479079,1.665647 1.727851,-0.04555 0.945116,1.102037 1.595689,-0.420439 1.013886,1.119783 1.616715,-0.611034 0.955484,0.869926 1.417278,-0.82042 1.399024,0.893951 1.62274,-0.936247 1.191522,0.880515 1.692439,-0.626057 1.62431,0.594614 1.273839,-0.730245 1.14228,0.675465 0.83977,-0.542118 1.7433,0.433922 1.37853,-0.883036 1.46376,0.789948 0.98369,-0.723702 1.56885,0.265388 0.83917,-1.064009 1.5817,0.538036 1.04635,-1.072595 1.45989,-0.386437 -0.0243,-1.46382 0.73064,-1.311775 -1.08662,-0.620199 -0.54503,-1.441178 -1.29888,0.821314 -1.72095,-0.803735 -0.89109,1.605976 -1.44802,-0.173747 -0.40144,0.954405 -1.25934,-0.74345 -1.14276,1.025692 -2.05145,-0.719347 c 0,0 -1.1538,1.054828 -1.21655,1.018337 -0.0627,-0.03649 -0.72908,-0.632037 -0.72908,-0.632037 l -2.781839,0.990357 -1.01136,-0.982973 -0.76464,0.897745 -1.265471,-0.508519 -1.392952,0.640072 -1.261957,-0.842494 -1.207529,1.021591 -2.137111,-1.168069 -0.83207,0.565255 -0.716719,-0.940683 -1.262123,0.222665 -0.854411,-1.073467 z"
|
||||
id="path3419"
|
||||
inkscape:label="purple-frizzy-bit" />
|
||||
</g>
|
||||
<g
|
||||
id="g571"
|
||||
transform="matrix(-0.37792196,-0.19227008,-0.19227008,0.37792196,160.95541,83.78303)"
|
||||
inkscape:export-filename="../fe6a9b8b/kani-stabby.png"
|
||||
inkscape:export-xdpi="370.63721"
|
||||
inkscape:export-ydpi="370.63721"
|
||||
style="display:none"
|
||||
inkscape:label="knife-left">
|
||||
<path
|
||||
d="M 327.32922,104.16963 313.23927,90.079688 246.31471,157.00414 c 0,0 -6.09712,4.9021 -4.45506,8.97393 1.6429,4.07209 4.34482,5.77218 11.55969,6.84567 6.14218,0.99798 6.56385,-1.72199 9.06459,-9.07879 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 5.35834,-9.35496 4.43089,-10.42811 12.07206,-10.21327 4.21357,0.0716 4.88879,-0.46249 6.31789,-1.74872 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439"
|
||||
style="fill:#c52a34;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path561" />
|
||||
<path
|
||||
d="M 333.98084,110.82126 313.52961,90.369671 c 0,0 66.27001,-67.178418 73.76936,-74.221626 7.49688,-7.0446203 13.081,-13.0810013 23.41845,-16.14946258 -0.68086,6.58883098 -6.21418,20.98428158 -13.48493,31.66357158 -7.2711,10.681759 -36.32483,51.549656 -63.25165,79.159106"
|
||||
style="fill:#b9b8b7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path563" />
|
||||
<path
|
||||
d="m 404.21431,2.595027 c -6.52039,3.3330447 -11.1573,8.142464 -16.91534,13.553018 -7.49935,7.043208 -73.76936,74.221626 -73.76936,74.221626 l 15.67956,15.678859 c 26.92717,-27.608745 55.97949,-68.476642 63.25094,-79.158049 5.17807,-7.605536 9.46362,-17.0825591 11.7542,-24.295454"
|
||||
style="fill:#999a99;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path565" />
|
||||
<path
|
||||
d="m 255.68936,173.17156 c -0.61955,0 -1.31989,-0.0656 -2.11762,-0.19541 -4.67209,-0.69397 -7.69193,-1.90252 -9.11972,-3.20187 l 0.0139,-0.014 c 1.82658,1.5197 4.5489,2.40839 8.9534,3.06351 0.81082,0.13188 1.52216,0.19899 2.15166,0.19899 4.13826,0 4.74239,-2.8925 6.91293,-9.27778 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 4.98299,-8.6995 4.53108,-10.23726 10.58792,-10.23726 0.4565,0 0.94862,0.009 1.48414,0.024 0.24729,0.004 0.48295,0.006 0.70661,0.006 3.58916,0 4.26614,-0.54433 5.61128,-1.75507 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439 v 0 c 0,0 -5.6,5.75451 -7.02875,7.03933 -1.34549,1.21109 -2.01824,1.7593 -5.61058,1.7593 -0.2226,0 -0.45649,-0.002 -0.70238,-0.006 -0.53269,-0.0152 -1.0227,-0.0236 -1.47708,-0.0236 -6.06319,0 -5.60035,1.54375 -10.5851,10.24714 -5.35693,9.35778 -17.62054,20.09429 -26.55122,29.02274 -8.92845,8.92803 -10.31434,4.2562 -12.81342,11.61408 -2.17593,6.40046 -2.71998,9.34932 -6.87133,9.34932 m 71.63986,-69.00193 -8.63636,-8.63635 v 0 l 8.63636,8.63635"
|
||||
style="fill:#cdccca;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path567" />
|
||||
<path
|
||||
d="m 255.571,173.02273 c -0.6295,0 -1.34084,-0.0671 -2.15166,-0.19899 -4.4045,-0.65512 -7.12682,-1.54381 -8.9534,-3.06351 l 74.22692,-74.22695 8.63636,8.63635 c 0,0 -5.60459,5.74958 -7.03334,7.03439 -1.34514,1.21074 -2.02212,1.75507 -5.61128,1.75507 -0.22366,0 -0.45932,-0.002 -0.70661,-0.006 -0.53552,-0.0152 -1.02764,-0.024 -1.48414,-0.024 -6.05684,0 -5.60493,1.53776 -10.58792,10.23726 -5.35587,9.35814 -17.63924,20.0762 -26.56932,29.0037 -8.92912,8.92874 -10.3536,4.21845 -12.85268,11.57524 -2.17054,6.38528 -2.77467,9.27778 -6.91293,9.27778"
|
||||
style="fill:#9b232b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path569" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 39 KiB |
|
@ -1,971 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="svg5800"
|
||||
version="1.1"
|
||||
viewBox="0 0 39.6875 39.687498"
|
||||
height="150"
|
||||
width="150"
|
||||
sodipodi:docname="icon-groups.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||
inkscape:export-filename="../94e4957b/kani-yellow-sign.png"
|
||||
inkscape:export-xdpi="86.699997"
|
||||
inkscape:export-ydpi="86.699997"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1391"
|
||||
inkscape:window-height="847"
|
||||
id="namedview108"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.3668237"
|
||||
inkscape:cx="80.342786"
|
||||
inkscape:cy="69.650216"
|
||||
inkscape:window-x="49"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="0,-35.3125"
|
||||
orientation="0,1"
|
||||
id="guide932"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleHorizontal"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="74.999998,39.687496"
|
||||
orientation="-1,0"
|
||||
id="guide934"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleVertical"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="4.7580685,-10.089218"
|
||||
orientation="0,-1"
|
||||
id="guide1652"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs5794">
|
||||
<radialGradient
|
||||
id="Gradient_4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="420.20801"
|
||||
cy="346.897"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8111" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8113" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="385.79401"
|
||||
cy="98.971001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8116" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8118" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_6"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="154.649"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8121" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8123" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="120.117"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8126" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8128" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_8"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="660.41699"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8131" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8133" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="625.88501"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8136" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8138" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="283.38901"
|
||||
cy="577.77899"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8141" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8143" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_11"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="213.711"
|
||||
cy="337.353"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8146" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8148" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="Gradient_12"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="395.94601"
|
||||
y1="909.60699"
|
||||
x2="398.86099"
|
||||
y2="889.30902">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8151" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8153" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="364.41199"
|
||||
y1="920.81097"
|
||||
x2="381.88199"
|
||||
y2="898.88202">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8156" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="400.103"
|
||||
y1="884.01398"
|
||||
x2="414.327"
|
||||
y2="886.43201">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8161" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8163" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="401.52899"
|
||||
y1="-883.02899"
|
||||
x2="418.35501"
|
||||
y2="-884.72101"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8166" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8168" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_1">
|
||||
<path
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c -2.74,0.34 -5.51,-0.08 -8.21,-0.56 v 0 c 1.75,0.6 3.93,1.12 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8171" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_16"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="406.53"
|
||||
y1="880.51599"
|
||||
x2="409.40302"
|
||||
y2="880.80499">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8174" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8176" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_17"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="452.20001"
|
||||
y1="905.45599"
|
||||
x2="444.604"
|
||||
y2="892.92102">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8179" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8181" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_18"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="462.254"
|
||||
y1="893.729"
|
||||
x2="456.45901"
|
||||
y2="887.92401">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8184" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8186" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_19"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="446.13501"
|
||||
y1="882.91602"
|
||||
x2="429.77499"
|
||||
y2="883.61603">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8189" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8191" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_20"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="443.24799"
|
||||
y1="-882.92798"
|
||||
x2="426.452"
|
||||
y2="-884.64899"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8194" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8196" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_2">
|
||||
<path
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -3.99,0.52 -9.46,1.2 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8199" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_21"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.23401"
|
||||
y1="880.48499"
|
||||
x2="435.36099"
|
||||
y2="880.78003">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8202" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8204" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="Gradient_22"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="421.086"
|
||||
cy="879.30603"
|
||||
r="5.8280001">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#E61F19"
|
||||
id="stop8207" />
|
||||
<stop
|
||||
offset="0.988"
|
||||
stop-color="#9E282C"
|
||||
id="stop8209" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#9E282C"
|
||||
id="stop8211" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_23"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="146.832"
|
||||
cy="-316.11899"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8214" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8216" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55.174999"
|
||||
cy="-176.464"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8219" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8221" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_25"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="565.53101"
|
||||
cy="-165.11301"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8224" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8226" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_26"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="333.47"
|
||||
cy="-63.138"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8229" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8231" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_27"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="536.58099"
|
||||
cy="578.03198"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8234" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8236" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_28"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="553.57397"
|
||||
cy="328.29001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8239" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8241" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_29"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="488.81201"
|
||||
cy="-304.62601"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8244" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8246" />
|
||||
</radialGradient>
|
||||
<symbol
|
||||
id="balloons"
|
||||
viewBox="0 0 825 962">
|
||||
<g
|
||||
style="fill:none;stroke:#eccb78;stroke-width:4.069;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="g8261">
|
||||
<path
|
||||
d="M 291.13,584.61 422.41,889.24 540.38,589.26"
|
||||
id="path8249" />
|
||||
<path
|
||||
d="m 426.95,357.75 -4.54,531.49"
|
||||
id="path8251" />
|
||||
<path
|
||||
d="M 158.17,411.35 421.71,889.24 667.1,402.98"
|
||||
id="path8253" />
|
||||
<path
|
||||
d="m 415.21,958.51 c 8.81,-23.5 6.08,-71.63 6.08,-71.63 -3.66,47 -29.02,70.1 -29.02,70.1"
|
||||
id="path8255" />
|
||||
<path
|
||||
d="m 456.29,956.29 c 0,0 -26.52,-21.77 -32.58,-68.52 0,0 -0.26,48.21 9.75,71.23"
|
||||
id="path8257" />
|
||||
<path
|
||||
d="m 404.06,957.77 c 0,0 13.62,-20.66 18.45,-69.2"
|
||||
id="path8259" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_4)"
|
||||
d="m 423.73,337.05 -21.46,35.03 c -1.86,3.04 0.32,6.93 3.89,6.93 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.83 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.28 -3.95,-2.28 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8263" />
|
||||
<path
|
||||
style="fill:url(#Gradient_5)"
|
||||
d="m 273.05,178.98 c 0,97.08 68.93,175.78 153.96,175.79 v 0 c 85.03,0 153.96,-78.7 153.97,-175.79 v 0 C 580.98,81.9 512.05,3.2 427.01,3.2 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8265" />
|
||||
<path
|
||||
style="fill:url(#Gradient_6)"
|
||||
d="m 158.17,425.62 -21.46,35.02 c -1.86,3.04 0.32,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 L 166,425.71 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8267" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_7)"
|
||||
d="m 7.37,267.55 c 0,97.08 68.93,175.78 153.97,175.78 v 0 c 85.03,0 153.96,-78.7 153.96,-175.78 v 0 C 315.3,170.47 246.37,91.77 161.34,91.77 v 0 C 76.31,91.77 7.38,170.47 7.37,267.55 Z"
|
||||
id="path8269" />
|
||||
<path
|
||||
style="fill:url(#Gradient_8)"
|
||||
d="m 663.94,425.62 -21.46,35.02 c -1.86,3.04 0.33,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8271" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_9)"
|
||||
d="m 513.14,267.55 c 0,97.08 68.93,175.78 153.96,175.78 v 0 c 85.03,0 153.96,-78.7 153.97,-175.78 v 0 C 821.07,170.47 752.14,91.77 667.1,91.77 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8273" />
|
||||
<path
|
||||
style="fill:url(#Gradient_10)"
|
||||
d="m 285.46,567.53 -16.21,37.74 c -1.41,3.27 1.31,6.82 4.83,6.3 v 0 l 41.28,-5.97 c 3.47,-0.5 5.1,-4.58 2.93,-7.33 v 0 l -25.06,-31.76 c -0.93,-1.17 -2.25,-1.74 -3.57,-1.74 v 0 c -1.72,0 -3.42,0.96 -4.2,2.76 z"
|
||||
id="path8275" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_11)"
|
||||
d="m 240.79,236.67 c -84.15,12.18 -141.11,99.94 -127.2,196.02 v 0 c 13.9,96.08 93.39,164.1 177.54,151.92 v 0 c 84.15,-12.18 141.1,-99.94 127.21,-196.02 v 0 C 405.52,300 336.93,235.26 260.34,235.26 v 0 c -6.47,0 -12.99,0.46 -19.55,1.41 z"
|
||||
id="path8277" />
|
||||
<path
|
||||
style="fill:url(#Gradient_27)"
|
||||
d="M 542.05,569.11 513.87,599 c -2.44,2.59 -1.1,6.85 2.38,7.59 v 0 l 40.83,8.54 c 3.43,0.72 6.36,-2.55 5.25,-5.88 v 0 l -12.64,-38.43 c -0.66,-2.01 -2.48,-3.13 -4.35,-3.14 v 0 c -1.18,0 -2.38,0.46 -3.29,1.43 z"
|
||||
id="path8279" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_28)"
|
||||
d="m 426.83,383.51 c -19.89,95.02 31.46,186.18 114.68,203.6 v 0 c 83.23,17.42 166.82,-45.49 186.71,-140.52 v 0 C 748.11,351.57 696.76,260.41 613.54,242.99 v 0 c -9.34,-1.96 -18.68,-2.9 -27.94,-2.89 v 0 c -73.25,0 -141.11,59.05 -158.77,143.41 z"
|
||||
id="path8281" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_23)"
|
||||
d="m 126.74,409.71 c 0,0 29.93,-94.86 60.85,-110.42 19.92,-10.03 -4.23,-30.39 -27.01,-14.05 -6.7,5.14 -12.35,11.69 -17.06,18.66 -14.36,21.28 -19.56,46.01 -20.09,71.27 v 0.02 c -0.07,11.6 1.32,23.12 3.31,34.52 z"
|
||||
id="path8283" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_24)"
|
||||
d="m 30.74,269.01 c 0,0 34.33,-93.36 65.93,-107.45 20.37,-9.09 -2.81,-30.55 -26.32,-15.3 0,0 -51.89,32.72 -39.61,122.75 z"
|
||||
id="path8285" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_25)"
|
||||
d="m 537.49,256.64 c 0,0 37.96,-91.94 70.09,-104.8 20.71,-8.29 -1.61,-30.64 -25.71,-16.31 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8287" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_26)"
|
||||
d="m 305.43,154.66 c 0,0 37.96,-91.94 70.09,-104.79 20.71,-8.28 -1.61,-30.64 -25.71,-16.32 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8289" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_29)"
|
||||
d="m 454.08,393.82 c 0,0 44.65,-88.88 77.64,-99.32 21.27,-6.73 0.66,-30.67 -24.42,-18.17 0,0 -55.25,26.66 -53.22,117.49 z"
|
||||
id="path8291" />
|
||||
<path
|
||||
style="fill:url(#Gradient_12)"
|
||||
d="m 375.83,907.75 9.08,1.65 c -1.21,2.8 0.79,11.89 0.79,11.89 v 0 c 8.26,-15.42 34.5,-34.41 33.81,-33.91 v 0 l 0.71,-5.79 c -24.03,1.57 -44.39,26.16 -44.39,26.16 z"
|
||||
id="path8293" />
|
||||
<path
|
||||
style="fill:url(#Gradient_13)"
|
||||
d="m 380.2,872.6 c 13.6,7.74 40.82,5.99 40.82,5.99 v 0 c -22.8,-5.81 -32.93,-7.21 -37.4,-7.21 v 0 c -4.17,0 -3.42,1.22 -3.42,1.22 z"
|
||||
id="path8295" />
|
||||
<path
|
||||
style="fill:url(#Gradient_14)"
|
||||
d="m 380.45,890.39 c 7.74,5.62 42.01,-3.08 42.01,-3.09 v 0 l -0.09,-10.01 c -42.04,-1.73 -42.31,-5.05 -42.31,-5.05 v 0 z"
|
||||
id="path8297" />
|
||||
<g
|
||||
clip-path="url(#Clip_1)"
|
||||
opacity="0.24"
|
||||
id="g8301">
|
||||
<path
|
||||
style="fill:url(#Gradient_15)"
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c 0,0 -3,0.5 -8.21,-0.56 2.01,0.59 4.41,1.58 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8299" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_16)"
|
||||
d="m 409.38,881 c -1.53,-0.45 -2.83,-0.68 -2.83,-0.68 v 0 c 1.01,0.28 1.95,0.5 2.83,0.68 z"
|
||||
id="path8303" />
|
||||
<path
|
||||
style="fill:url(#Gradient_17)"
|
||||
d="m 425.53,887.37 c 0,0 25.53,18.33 33.88,33.85 v 0 c 0,0 1.98,-9.1 0.76,-11.89 v 0 l 9.08,-1.67 c 0,0 -20.4,-24.55 -44.44,-26.08 v 0 z"
|
||||
id="path8305" />
|
||||
<path
|
||||
style="fill:url(#Gradient_18)"
|
||||
d="m 423.74,878.59 c 0,0 40.72,9.96 40.43,-5.69 v 0 c -0.01,-0.45 0.33,-1.72 -3.83,-1.73 v 0 c -4.58,0 -14.62,1.54 -36.6,7.42 z"
|
||||
id="path8307" />
|
||||
<path
|
||||
style="fill:url(#Gradient_19)"
|
||||
d="m 422.39,877.29 -0.07,10.01 c 0,0 34.28,8.63 42.01,3 v 0 l -0.11,-17.86 c 0,0 -0.29,1.43 -41.83,4.85 z"
|
||||
id="path8309" />
|
||||
<g
|
||||
clip-path="url(#Clip_2)"
|
||||
opacity="0.24"
|
||||
id="g8313">
|
||||
<path
|
||||
style="fill:url(#Gradient_20)"
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -9.75,1.64 -12.88,-1.55 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8311" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_21)"
|
||||
d="m 435.38,880.98 c 0.88,-0.18 1.83,-0.4 2.83,-0.69 v 0 c 0,0 -1.3,0.23 -2.83,0.69 z"
|
||||
id="path8315" />
|
||||
<path
|
||||
style="fill:url(#Gradient_22)"
|
||||
d="m 417.09,877.31 c 0,0 -1.77,8.19 0.74,11.61 v 0 l 9.25,-0.01 c 0,0 2.64,-7.59 0.88,-11.59 v 0 c 0,0 -4.62,-1 -7.84,-1 v 0 c -1.6,0 -2.86,0.25 -3.03,0.99 z"
|
||||
id="path8317" />
|
||||
</symbol>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5797">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Kani"
|
||||
style="display:inline"
|
||||
transform="translate(-40.228511,-7.4385631)">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 58.64796,20.686712 c 0.593984,1.435445 -1.021814,2.758664 -1.028747,2.780043 0.295135,-0.865737 0.607057,-1.564607 0.03337,-2.169704"
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 45.241311,20.592298 c -0.593984,1.435446 1.021817,2.758664 1.028745,2.780043 -0.29513,-0.865737 -0.607052,-1.564607 -0.03336,-2.169703"
|
||||
id="path5408"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 51.987557,13.088022 c 0.231137,-0.0028 0.452316,0.41556 0.863816,1.234019 1.245537,-1.369863 1.309249,-1.386448 1.738393,0.46805 0.02008,0.0084 0.04012,0.01694 0.06016,0.02556 1.56884,-0.940424 1.649896,-0.947779 1.530839,0.890464 0.03809,0.02825 0.07616,0.05688 0.114094,0.08598 1.607642,-0.636835 1.677152,-0.596707 1.270344,1.167751 0.01907,0.02062 0.03817,0.04112 0.05714,0.06198 1.638526,-0.442689 1.68437,-0.376169 1.073287,1.352673 0.02622,0.03761 0.05225,0.07587 0.07832,0.114001 1.846823,-0.197423 1.884762,-0.161352 0.945868,1.559317 0.0046,0.0085 0.0093,0.01665 0.01388,0.02519 0.756628,0.361696 1.007111,0.802551 1.365635,1.394295 0.02783,1.173596 -1.228321,2.185036 -3.03448,3.334494 0.620528,-1.150059 1.590923,-1.733058 1.777095,-3.159525 -0.272651,-0.513163 -0.736309,-0.690429 -1.134438,-0.921315 -4.348503,2.537775 -8.940015,2.567194 -13.520807,-0.09721 -0.399201,0.232267 -0.865611,0.408903 -1.139365,0.924145 0.186169,1.426465 1.156657,2.009374 1.777184,3.159433 -1.806157,-1.149458 -3.062397,-2.160808 -3.034571,-3.334406 0.348577,-0.575325 0.596425,-1.007821 1.305212,-1.363808 -0.885405,-1.628173 -0.801118,-1.643497 1.05722,-1.444312 0.01575,-0.02035 0.03142,-0.04095 0.04719,-0.06115 -0.641971,-1.812442 -0.601698,-1.859807 1.128965,-1.390279 -0.438017,-1.890928 -0.379489,-1.898641 1.374031,-1.201706 -0.132081,-1.993217 -0.08476,-1.989078 1.569908,-0.996615 0.441235,-1.910866 0.493297,-1.90518 1.755736,-0.516609 0.474851,-0.871405 0.724682,-1.307623 0.959377,-1.310414 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="matrix(-0.17662502,0,0,0.17662502,70.103346,-0.11715463)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 56.387729,20.084726 c 0.09014,7.22e-4 0.150252,0.0096 0.140377,0.0157 0,0 1.613304,2.108216 -0.05476,3.295613 a 1.4619408,1.7215836 52.206057 0 1 -0.253834,1.664464 1.4619408,1.7215836 52.206057 0 1 -1.865992,0.700707 l 0.62951,-1.519978 -1.624394,0.129882 a 1.4619408,1.7215836 52.206057 0 1 1.241047,-1.573829 1.4619408,1.7215836 52.206057 0 1 1.237758,0.0016 c 0.328934,-0.240918 0.817545,-0.870048 0.0072,-2.203434 -0.268129,-0.4412 0.272621,-0.512767 0.543076,-0.510674 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
id="path8665"
|
||||
d="m 83.960168,109.11313 c -0.27485,0.43011 -0.4985,0.69147 -0.49798,0.62578 0,0 -14.965898,1.38701 -15.636208,-10.186101 a 9.7471106,8.2770874 84.335985 0 1 -7.216103,-6.22894 9.7471106,8.2770874 84.335985 0 1 2.259156,-11.0566 l 5.392134,7.59511 4.268531,-8.17939 a 9.7471106,8.2770874 84.335985 0 1 3.80891,10.68931 9.7471106,8.2770874 84.335985 0 1 -3.73468,5.92977 c 0.16465,2.302521 1.70979,6.539611 10.54286,6.669381 2.92274,0.043 1.63761,2.85111 0.81319,4.14154 z"
|
||||
style="display:none;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-up" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="kani-claw-right-overlay"
|
||||
style="display:inline"
|
||||
transform="translate(-40.228511,-7.4385631)">
|
||||
<path
|
||||
d="m 43.974461,18.654981 c -0.619835,-0.549959 -0.74118,-1.238386 -0.561022,-2.010566 l 1.305506,0.677034 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523"
|
||||
inkscape:label="under-kani-claw" />
|
||||
<path
|
||||
id="path5732-74"
|
||||
d="m 45.523026,16.052623 c 0.385284,0.251515 0.679119,0.647427 0.81225,1.094423 0.175105,0.591814 0.04525,1.190806 -0.338923,1.563471 0.632215,1.725553 1.775814,1.157848 1.799979,1.135149 0.194316,-0.151243 0.914553,0.641231 -0.09409,0.923623 -1.575527,0.441116 -2.25651,-0.966983 -2.500338,-1.708031 -0.432965,0.03313 -0.886664,-0.138029 -1.245626,-0.469906 -0.54202,-0.502579 -0.767337,-1.275606 -0.557775,-1.913614 l 1.468083,0.74247 -8.5e-4,-0.228231 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 45.523026,16.052623 c 0.385284,0.251516 0.679119,0.647427 0.81225,1.094423 0.175105,0.591814 0.04525,1.190806 -0.338923,1.563471 0.632215,1.725551 1.775814,1.157846 1.799979,1.135147 0.194316,-0.151243 0.914553,0.641231 -0.09409,0.923624 -1.575527,0.441115 -2.25651,-0.966984 -2.500338,-1.70803 -0.432965,0.03313 -0.886664,-0.138029 -1.245631,-0.469906 C 43.414258,18.088773 43.188937,17.315746 43.3985,16.67774 l 1.468086,0.742469 -8.5e-4,-0.228232 z"
|
||||
id="path5728" />
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 45.523026,16.052623 c 0.385284,0.251516 0.679119,0.647427 0.81225,1.094423 0.175105,0.591814 0.04525,1.190806 -0.338923,1.563471 0.632215,1.725551 1.775814,1.157846 1.799979,1.135147 0.194316,-0.151243 0.914553,0.641231 -0.09409,0.923624 -1.575527,0.441115 -2.25651,-0.966984 -2.500338,-1.70803 -0.432965,0.03313 -0.886664,-0.138029 -1.245631,-0.469906 C 43.414258,18.088773 43.188937,17.315746 43.3985,16.67774 l 1.468086,0.742469 -8.5e-4,-0.228232 z"
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5404-5"
|
||||
d="m 61.756924,26.737804 c -0.593985,1.435446 1.021813,2.758664 1.028746,2.780044 C 62.490535,28.65211 62.178615,27.95324 62.7523,27.348143"
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 75.163573,26.64339 c 0.593985,1.435446 -1.021816,2.758664 -1.028744,2.780043 0.29513,-0.865737 0.607052,-1.564607 0.03337,-2.169702"
|
||||
id="path5408-6"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529-2"
|
||||
d="m 68.417329,19.139115 c -0.231139,-0.0028 -0.452317,0.415559 -0.863816,1.234018 -1.245538,-1.369863 -1.30925,-1.386448 -1.738394,0.46805 -0.02009,0.0084 -0.04012,0.01694 -0.06015,0.02556 -1.568841,-0.940423 -1.649896,-0.947778 -1.53084,0.890464 -0.03809,0.02825 -0.07616,0.05688 -0.114094,0.08598 -1.607641,-0.636835 -1.677153,-0.596707 -1.270345,1.167752 -0.01907,0.02062 -0.03817,0.04112 -0.05714,0.06198 -1.638525,-0.442689 -1.684371,-0.376169 -1.073286,1.352674 -0.02622,0.03761 -0.05225,0.07587 -0.07832,0.114002 -1.846824,-0.197422 -1.884762,-0.161352 -0.945868,1.559316 -0.0046,0.0085 -0.0093,0.01665 -0.01388,0.02519 -0.756627,0.361696 -1.00711,0.80255 -1.365635,1.394294 -0.02783,1.173597 1.228321,2.185036 3.03448,3.334495 -0.620528,-1.150059 -1.590924,-1.733057 -1.777095,-3.159526 0.272651,-0.513162 0.73631,-0.690429 1.134437,-0.921315 4.348504,2.537775 8.940017,2.567194 13.520809,-0.09721 0.3992,0.232267 0.865612,0.408903 1.139361,0.924145 -0.186169,1.426466 -1.156653,2.009373 -1.77718,3.159432 1.806152,-1.149458 3.062393,-2.160808 3.034567,-3.334404 -0.348577,-0.575327 -0.596425,-1.007823 -1.305212,-1.363809 0.885404,-1.628174 0.801118,-1.643498 -1.057215,-1.444312 -0.01575,-0.02035 -0.03142,-0.04095 -0.04719,-0.06115 0.64197,-1.812444 0.601698,-1.859809 -1.128964,-1.390281 0.438016,-1.890928 0.379488,-1.898639 -1.374033,-1.201706 0.132083,-1.993216 0.08478,-1.989077 -1.569906,-0.996615 -0.441235,-1.910865 -0.493298,-1.905179 -1.755737,-0.516608 -0.47485,-0.871404 -0.724681,-1.307623 -0.959377,-1.310414 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758-8"
|
||||
transform="matrix(0.17662502,0,0,0.17662502,50.30154,5.9339373)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399-5"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351-9"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415-4" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417-3" />
|
||||
</g>
|
||||
<g
|
||||
id="g355-9"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433-0"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435-5"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389-6"
|
||||
d="m 64.017157,26.135819 c -0.09015,7.21e-4 -0.150254,0.0096 -0.140378,0.0157 0,0 -1.613306,2.108215 0.05476,3.295613 a 1.7215836,1.4619408 37.793943 0 0 0.253834,1.664465 1.7215836,1.4619408 37.793943 0 0 1.865992,0.700706 l -0.629511,-1.519981 1.624394,0.129884 a 1.7215836,1.4619408 37.793943 0 0 -1.241046,-1.573829 1.7215836,1.4619408 37.793943 0 0 -1.237759,0.0016 c -0.328933,-0.240918 -0.817544,-0.870047 -0.0072,-2.203434 0.268129,-0.4412 -0.272621,-0.512766 -0.543076,-0.510674 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
d="m 76.430419,24.706073 c 0.619836,-0.549958 0.741181,-1.238386 0.561023,-2.010565 l -1.305501,0.677033 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523-3"
|
||||
inkscape:label="under-kani-claw" />
|
||||
<path
|
||||
id="path5732-74-6"
|
||||
d="m 74.881859,22.103715 c -0.385284,0.251515 -0.67912,0.647427 -0.812249,1.094423 -0.175107,0.591814 -0.04525,1.190806 0.338922,1.563471 -0.632214,1.725553 -1.775814,1.157848 -1.799979,1.135149 -0.194317,-0.151243 -0.914554,0.641231 0.09409,0.923623 1.575529,0.441116 2.256511,-0.966983 2.500339,-1.708031 0.432965,0.03313 0.886665,-0.138029 1.245622,-0.469905 0.54202,-0.50258 0.767337,-1.275607 0.557775,-1.913613 l -1.468079,0.742469 8.49e-4,-0.228232 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 74.881859,22.103715 c -0.385284,0.251516 -0.67912,0.647427 -0.812249,1.094424 -0.175107,0.591813 -0.04525,1.190805 0.338922,1.56347 -0.632214,1.725552 -1.775814,1.157847 -1.799979,1.135147 -0.194317,-0.151243 -0.914554,0.641232 0.09409,0.923624 1.575529,0.441115 2.256511,-0.966984 2.500339,-1.708029 0.432965,0.03313 0.886665,-0.13803 1.245626,-0.469906 0.542016,-0.50258 0.767337,-1.275607 0.557774,-1.913613 l -1.468082,0.742469 8.49e-4,-0.228231 z"
|
||||
id="path5728-3" />
|
||||
<path
|
||||
id="path5732-0"
|
||||
d="m 74.881859,22.103715 c -0.385284,0.251516 -0.67912,0.647427 -0.812249,1.094424 -0.175107,0.591813 -0.04525,1.190805 0.338922,1.56347 -0.632214,1.725552 -1.775814,1.157847 -1.799979,1.135147 -0.194317,-0.151243 -0.914554,0.641232 0.09409,0.923624 1.575529,0.441115 2.256511,-0.966984 2.500339,-1.708029 0.432965,0.03313 0.886665,-0.13803 1.245626,-0.469906 0.542016,-0.50258 0.767337,-1.275607 0.557774,-1.913613 l -1.468082,0.742469 8.49e-4,-0.228231 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5404-8"
|
||||
d="m 46.528932,35.750289 c -0.593985,1.435445 1.021812,2.758664 1.028747,2.780044 -0.295135,-0.865737 -0.607057,-1.564607 -0.03337,-2.169704"
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 59.935581,35.655876 c 0.593984,1.435446 -1.021816,2.758664 -1.028744,2.780042 0.29513,-0.865736 0.607052,-1.564606 0.03336,-2.169702"
|
||||
id="path5408-4"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529-0"
|
||||
d="m 53.189335,28.1516 c -0.231139,-0.0028 -0.452316,0.415558 -0.863816,1.234018 -1.245538,-1.369863 -1.30925,-1.386447 -1.738394,0.468051 -0.02009,0.0084 -0.04012,0.01694 -0.06016,0.02556 -1.568841,-0.940424 -1.649896,-0.947779 -1.530839,0.890464 -0.03809,0.02825 -0.07616,0.05689 -0.114095,0.08598 -1.60764,-0.636836 -1.677152,-0.596707 -1.270343,1.167752 -0.01907,0.02062 -0.03817,0.04112 -0.05714,0.06198 -1.638526,-0.442689 -1.684371,-0.376171 -1.073287,1.352673 -0.02622,0.03761 -0.05225,0.07587 -0.07832,0.114001 -1.846823,-0.197423 -1.884762,-0.161352 -0.945867,1.559317 -0.0046,0.0085 -0.0093,0.01665 -0.01388,0.02519 -0.756628,0.361696 -1.007111,0.802551 -1.365635,1.394294 -0.02783,1.173597 1.228321,2.185037 3.03448,3.334494 -0.620528,-1.150058 -1.590924,-1.733057 -1.777096,-3.159524 0.272652,-0.513163 0.73631,-0.69043 1.134438,-0.921315 4.348502,2.537775 8.940015,2.567192 13.520808,-0.09721 0.399201,0.232267 0.865612,0.408902 1.139366,0.924144 -0.186169,1.426466 -1.156658,2.009375 -1.777184,3.159432 1.806155,-1.149456 3.062395,-2.160806 3.03457,-3.334404 -0.348576,-0.575326 -0.596424,-1.007822 -1.305211,-1.363808 0.885404,-1.628174 0.801118,-1.643498 -1.05722,-1.444313 -0.01575,-0.02035 -0.03142,-0.04095 -0.04719,-0.06115 0.641971,-1.812444 0.601697,-1.859807 -1.128965,-1.390279 0.438017,-1.890929 0.379489,-1.898641 -1.374031,-1.201708 0.132081,-1.993216 0.08476,-1.989076 -1.569909,-0.996614 -0.441235,-1.910865 -0.493297,-1.905179 -1.755736,-0.516608 -0.474851,-0.871405 -0.724682,-1.307623 -0.959378,-1.310414 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:0.176626;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758-4"
|
||||
transform="matrix(0.17662502,0,0,0.17662502,35.073547,14.946424)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399-6"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351-4"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415-6" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417-4" />
|
||||
</g>
|
||||
<g
|
||||
id="g355-3"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433-8"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435-4"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389-0"
|
||||
d="m 48.789163,35.148303 c -0.09015,7.22e-4 -0.150253,0.0096 -0.140378,0.0157 0,0 -1.613304,2.108215 0.05476,3.295613 a 1.7215836,1.4619408 37.793943 0 0 0.253835,1.664464 1.7215836,1.4619408 37.793943 0 0 1.865992,0.700707 l -0.629512,-1.51998 1.624394,0.129883 a 1.7215836,1.4619408 37.793943 0 0 -1.241045,-1.57383 1.7215836,1.4619408 37.793943 0 0 -1.23776,0.0016 c -0.328933,-0.240918 -0.817544,-0.870048 -0.0072,-2.203435 0.268129,-0.4412 -0.272621,-0.512767 -0.543077,-0.510673 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
id="path5732-5"
|
||||
d="m 54.978485,39.313353 c 0.01268,-0.459938 0.196247,-0.917525 0.507459,-1.26491 0.412645,-0.458946 0.991007,-0.661794 1.509625,-0.529473 1.139473,-1.441813 0.05721,-2.119162 0.02521,-2.127874 -0.230574,-0.08642 0.06775,-1.114898 0.836266,-0.403225 1.200459,1.111651 0.357013,2.428876 -0.146824,3.024483 0.254828,0.351594 0.346438,0.827773 0.251514,1.307344 -0.144578,0.724888 -0.685353,1.321464 -1.338681,1.476808 l -0.135687,-1.639552 -0.194033,0.120174 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.176626;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g7998"
|
||||
inkscape:label="party-hat"
|
||||
transform="matrix(1.0107117,0,0,0.94642879,-34.697969,-6.0098395)"
|
||||
style="display:none">
|
||||
<path
|
||||
style="display:inline;fill:#1da1f2;fill-opacity:1;stroke:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path7024"
|
||||
inkscape:label="party-hat-background"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 90.866459,64.772976 -1.399384,3.650367 c 0,0 6.297977,-0.0079 9.604616,-2.229612 3.306639,-2.221751 6.641769,-4.763148 6.637539,-5.892882 -0.004,-1.129737 -1.2244,-3.398221 -1.2244,-3.398221 0,0 -1.76379,2.983434 -5.089689,4.759036 -3.325897,1.775606 -6.256176,3.317156 -8.528682,3.111312 z"
|
||||
id="path7711"
|
||||
inkscape:label="yellow-middle" />
|
||||
<path
|
||||
style="fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.283815,50.496253 c 0,0 2.017636,-0.742584 2.746046,-1.209859 0.68409,-0.438843 2.540819,-1.493505 2.505569,-1.916931 -0.0353,-0.423423 0.90713,1.638551 0.90713,1.638551 0,0 -0.43327,0.543192 -1.447199,1.610006 -1.01394,1.066813 -1.72817,1.358505 -2.26456,1.622681 -0.53638,0.264174 -2.0866,0.861497 -2.636383,0.793816 -0.549783,-0.06768 0.189397,-2.538264 0.189397,-2.538264 z"
|
||||
id="path7713"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="yellow-top" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 109.92717,71.488689 c 0,0 -2.20481,3.007619 -3.4367,4.221512 -1.06044,1.044951 -3.3987,2.32693 -5.45873,3.108264 -2.060039,0.78133 -7.390321,2.031263 -10.319319,2.035505 -2.53475,0.0037 -3.102127,-0.17882 -4.727213,-0.614261 -1.010264,-0.270699 -0.801047,2.045289 -0.801047,2.045289 l 4.858605,2.209687 10.217314,-0.32013 c 0,0 3.08806,-0.85865 3.26326,-0.9226 0.17519,-0.06395 5.61136,-3.775927 5.91906,-4.176562 0.30769,-0.400637 1.97931,-2.854544 1.85876,-3.106917 -0.12055,-0.25237 -1.37399,-4.479787 -1.37399,-4.479787 z"
|
||||
id="path7715"
|
||||
sodipodi:nodetypes="csssscccsssc"
|
||||
inkscape:label="yellow-bottom" />
|
||||
<path
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.208385,72.747325 c 0,0 6.251797,0.04012 9.907566,-1.876691 3.875559,-2.032049 5.147419,-2.116642 8.954089,-7.814465 -0.0353,-0.423423 1.59724,3.704345 1.59724,3.704345 0,0 -2.99139,5.115034 -6.19574,6.653752 -4.079519,1.958969 -6.324966,2.675602 -8.934752,3.106262 -1.713747,0.282798 -4.8213,0.352969 -6.27215,-0.01279 -0.537127,-0.135411 0.943747,-3.760409 0.943747,-3.760409 z"
|
||||
id="path7982"
|
||||
sodipodi:nodetypes="csccssscc"
|
||||
inkscape:label="white-middle" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 92.993027,57.289539 c 0,0 3.629855,-0.719631 5.482954,-2.090937 0.65332,-0.483462 3.662839,-3.285322 4.163269,-4.079419 -0.0353,-0.423423 0.98376,2.839616 0.98376,2.839616 0,0 -1.55545,1.919882 -2.68768,2.888013 -1.118619,0.956483 -3.276219,2.193755 -4.815637,2.748644 -1.634013,0.588985 -3.388075,0.798009 -3.937858,0.730328 -0.549783,-0.06768 0.811192,-3.036245 0.811192,-3.036245 z"
|
||||
id="path7979"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="white-top" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ff00ff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path508"
|
||||
inkscape:label="party-hat-outline"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:#8f57a8;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.307706,40.797374 8.863844,3.5236 c -4.511069,-1.476791 -5.455019,1.171445 -8.289058,2.243988 0,0 5.051628,-7.95802 4.765018,-7.734177 -1.618949,1.264417 -2.259979,9.16058 -2.259979,9.16058 l -0.26088,-9.396127 3.698779,7.921822 -7.078677,-2.809491 8.818747,-2.23602 z"
|
||||
id="path3171-3"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="display:inline;fill:#0056ed;fill-opacity:1;stroke:#ae00ff;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 96.516104,39.086314 5.923406,7.476417 c -3.172509,-3.530708 -5.311942,-1.706696 -8.303144,-2.191314 0,0 8.348654,-4.375959 7.988584,-4.324981 -2.03392,0.28796 -6.529397,6.811072 -6.529397,6.811072 l 4.462297,-8.273038 -0.747319,8.710783 -4.732664,-5.966807 8.758203,2.462516 z"
|
||||
id="path3171"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="fill:#744eaa;fill-opacity:1;stroke:#8f57a8;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.749242,80.805507 -1.299196,-0.793626 -0.72012,1.516668 -1.19957,0.02641 1.07959,1.592728 -0.479079,1.665647 1.727851,-0.04555 0.945116,1.102037 1.595689,-0.420439 1.013886,1.119783 1.616715,-0.611034 0.955484,0.869926 1.417278,-0.82042 1.399024,0.893951 1.62274,-0.936247 1.191522,0.880515 1.692439,-0.626057 1.62431,0.594614 1.273839,-0.730245 1.14228,0.675465 0.83977,-0.542118 1.7433,0.433922 1.37853,-0.883036 1.46376,0.789948 0.98369,-0.723702 1.56885,0.265388 0.83917,-1.064009 1.5817,0.538036 1.04635,-1.072595 1.45989,-0.386437 -0.0243,-1.46382 0.73064,-1.311775 -1.08662,-0.620199 -0.54503,-1.441178 -1.29888,0.821314 -1.72095,-0.803735 -0.89109,1.605976 -1.44802,-0.173747 -0.40144,0.954405 -1.25934,-0.74345 -1.14276,1.025692 -2.05145,-0.719347 c 0,0 -1.1538,1.054828 -1.21655,1.018337 -0.0627,-0.03649 -0.72908,-0.632037 -0.72908,-0.632037 l -2.781839,0.990357 -1.01136,-0.982973 -0.76464,0.897745 -1.265471,-0.508519 -1.392952,0.640072 -1.261957,-0.842494 -1.207529,1.021591 -2.137111,-1.168069 -0.83207,0.565255 -0.716719,-0.940683 -1.262123,0.222665 -0.854411,-1.073467 z"
|
||||
id="path3419"
|
||||
inkscape:label="purple-frizzy-bit" />
|
||||
</g>
|
||||
<g
|
||||
id="g571"
|
||||
transform="matrix(-0.37792196,-0.19227008,-0.19227008,0.37792196,160.95541,83.78303)"
|
||||
inkscape:export-filename="../fe6a9b8b/kani-stabby.png"
|
||||
inkscape:export-xdpi="370.63721"
|
||||
inkscape:export-ydpi="370.63721"
|
||||
style="display:none"
|
||||
inkscape:label="knife-left">
|
||||
<path
|
||||
d="M 327.32922,104.16963 313.23927,90.079688 246.31471,157.00414 c 0,0 -6.09712,4.9021 -4.45506,8.97393 1.6429,4.07209 4.34482,5.77218 11.55969,6.84567 6.14218,0.99798 6.56385,-1.72199 9.06459,-9.07879 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 5.35834,-9.35496 4.43089,-10.42811 12.07206,-10.21327 4.21357,0.0716 4.88879,-0.46249 6.31789,-1.74872 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439"
|
||||
style="fill:#c52a34;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path561" />
|
||||
<path
|
||||
d="M 333.98084,110.82126 313.52961,90.369671 c 0,0 66.27001,-67.178418 73.76936,-74.221626 7.49688,-7.0446203 13.081,-13.0810013 23.41845,-16.14946258 -0.68086,6.58883098 -6.21418,20.98428158 -13.48493,31.66357158 -7.2711,10.681759 -36.32483,51.549656 -63.25165,79.159106"
|
||||
style="fill:#b9b8b7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path563" />
|
||||
<path
|
||||
d="m 404.21431,2.595027 c -6.52039,3.3330447 -11.1573,8.142464 -16.91534,13.553018 -7.49935,7.043208 -73.76936,74.221626 -73.76936,74.221626 l 15.67956,15.678859 c 26.92717,-27.608745 55.97949,-68.476642 63.25094,-79.158049 5.17807,-7.605536 9.46362,-17.0825591 11.7542,-24.295454"
|
||||
style="fill:#999a99;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path565" />
|
||||
<path
|
||||
d="m 255.68936,173.17156 c -0.61955,0 -1.31989,-0.0656 -2.11762,-0.19541 -4.67209,-0.69397 -7.69193,-1.90252 -9.11972,-3.20187 l 0.0139,-0.014 c 1.82658,1.5197 4.5489,2.40839 8.9534,3.06351 0.81082,0.13188 1.52216,0.19899 2.15166,0.19899 4.13826,0 4.74239,-2.8925 6.91293,-9.27778 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 4.98299,-8.6995 4.53108,-10.23726 10.58792,-10.23726 0.4565,0 0.94862,0.009 1.48414,0.024 0.24729,0.004 0.48295,0.006 0.70661,0.006 3.58916,0 4.26614,-0.54433 5.61128,-1.75507 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439 v 0 c 0,0 -5.6,5.75451 -7.02875,7.03933 -1.34549,1.21109 -2.01824,1.7593 -5.61058,1.7593 -0.2226,0 -0.45649,-0.002 -0.70238,-0.006 -0.53269,-0.0152 -1.0227,-0.0236 -1.47708,-0.0236 -6.06319,0 -5.60035,1.54375 -10.5851,10.24714 -5.35693,9.35778 -17.62054,20.09429 -26.55122,29.02274 -8.92845,8.92803 -10.31434,4.2562 -12.81342,11.61408 -2.17593,6.40046 -2.71998,9.34932 -6.87133,9.34932 m 71.63986,-69.00193 -8.63636,-8.63635 v 0 l 8.63636,8.63635"
|
||||
style="fill:#cdccca;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path567" />
|
||||
<path
|
||||
d="m 255.571,173.02273 c -0.6295,0 -1.34084,-0.0671 -2.15166,-0.19899 -4.4045,-0.65512 -7.12682,-1.54381 -8.9534,-3.06351 l 74.22692,-74.22695 8.63636,8.63635 c 0,0 -5.60459,5.74958 -7.03334,7.03439 -1.34514,1.21074 -2.02212,1.75507 -5.61128,1.75507 -0.22366,0 -0.45932,-0.002 -0.70661,-0.006 -0.53552,-0.0152 -1.02764,-0.024 -1.48414,-0.024 -6.05684,0 -5.60493,1.53776 -10.58792,10.23726 -5.35587,9.35814 -17.63924,20.0762 -26.56932,29.0037 -8.92912,8.92874 -10.3536,4.21845 -12.85268,11.57524 -2.17054,6.38528 -2.77467,9.27778 -6.91293,9.27778"
|
||||
style="fill:#9b232b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path569" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 51 KiB |
|
@ -1,834 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="svg5800"
|
||||
version="1.1"
|
||||
viewBox="0 0 7.9374999 7.9374999"
|
||||
height="30"
|
||||
width="30"
|
||||
sodipodi:docname="icon-person.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||
inkscape:export-filename="../94e4957b/kani-yellow-sign.png"
|
||||
inkscape:export-xdpi="86.699997"
|
||||
inkscape:export-ydpi="86.699997"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1386"
|
||||
inkscape:window-height="847"
|
||||
id="namedview108"
|
||||
showgrid="false"
|
||||
inkscape:zoom="13.325447"
|
||||
inkscape:cx="8.8177156"
|
||||
inkscape:cy="23.001105"
|
||||
inkscape:window-x="54"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer3"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="-2.2872575,-58.804357"
|
||||
orientation="0,1"
|
||||
id="guide932"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleHorizontal"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="72.712742,16.195644"
|
||||
orientation="-1,0"
|
||||
id="guide934"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleVertical"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="2.4708111,-33.581074"
|
||||
orientation="0,-1"
|
||||
id="guide1652"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs5794">
|
||||
<radialGradient
|
||||
id="Gradient_4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="420.20801"
|
||||
cy="346.897"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8111" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8113" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="385.79401"
|
||||
cy="98.971001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8116" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8118" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_6"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="154.649"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8121" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8123" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="120.117"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8126" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8128" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_8"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="660.41699"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8131" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8133" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="625.88501"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8136" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8138" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="283.38901"
|
||||
cy="577.77899"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8141" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8143" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_11"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="213.711"
|
||||
cy="337.353"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8146" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8148" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="Gradient_12"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="395.94601"
|
||||
y1="909.60699"
|
||||
x2="398.86099"
|
||||
y2="889.30902">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8151" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8153" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="364.41199"
|
||||
y1="920.81097"
|
||||
x2="381.88199"
|
||||
y2="898.88202">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8156" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="400.103"
|
||||
y1="884.01398"
|
||||
x2="414.327"
|
||||
y2="886.43201">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8161" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8163" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="401.52899"
|
||||
y1="-883.02899"
|
||||
x2="418.35501"
|
||||
y2="-884.72101"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8166" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8168" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_1">
|
||||
<path
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c -2.74,0.34 -5.51,-0.08 -8.21,-0.56 v 0 c 1.75,0.6 3.93,1.12 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8171" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_16"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="406.53"
|
||||
y1="880.51599"
|
||||
x2="409.40302"
|
||||
y2="880.80499">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8174" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8176" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_17"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="452.20001"
|
||||
y1="905.45599"
|
||||
x2="444.604"
|
||||
y2="892.92102">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8179" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8181" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_18"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="462.254"
|
||||
y1="893.729"
|
||||
x2="456.45901"
|
||||
y2="887.92401">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8184" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8186" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_19"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="446.13501"
|
||||
y1="882.91602"
|
||||
x2="429.77499"
|
||||
y2="883.61603">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8189" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8191" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_20"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="443.24799"
|
||||
y1="-882.92798"
|
||||
x2="426.452"
|
||||
y2="-884.64899"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8194" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8196" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_2">
|
||||
<path
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -3.99,0.52 -9.46,1.2 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8199" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_21"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.23401"
|
||||
y1="880.48499"
|
||||
x2="435.36099"
|
||||
y2="880.78003">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8202" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8204" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="Gradient_22"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="421.086"
|
||||
cy="879.30603"
|
||||
r="5.8280001">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#E61F19"
|
||||
id="stop8207" />
|
||||
<stop
|
||||
offset="0.988"
|
||||
stop-color="#9E282C"
|
||||
id="stop8209" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#9E282C"
|
||||
id="stop8211" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_23"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="146.832"
|
||||
cy="-316.11899"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8214" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8216" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55.174999"
|
||||
cy="-176.464"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8219" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8221" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_25"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="565.53101"
|
||||
cy="-165.11301"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8224" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8226" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_26"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="333.47"
|
||||
cy="-63.138"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8229" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8231" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_27"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="536.58099"
|
||||
cy="578.03198"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8234" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8236" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_28"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="553.57397"
|
||||
cy="328.29001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8239" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8241" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_29"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="488.81201"
|
||||
cy="-304.62601"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8244" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8246" />
|
||||
</radialGradient>
|
||||
<symbol
|
||||
id="balloons"
|
||||
viewBox="0 0 825 962">
|
||||
<g
|
||||
style="fill:none;stroke:#eccb78;stroke-width:4.069;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="g8261">
|
||||
<path
|
||||
d="M 291.13,584.61 422.41,889.24 540.38,589.26"
|
||||
id="path8249" />
|
||||
<path
|
||||
d="m 426.95,357.75 -4.54,531.49"
|
||||
id="path8251" />
|
||||
<path
|
||||
d="M 158.17,411.35 421.71,889.24 667.1,402.98"
|
||||
id="path8253" />
|
||||
<path
|
||||
d="m 415.21,958.51 c 8.81,-23.5 6.08,-71.63 6.08,-71.63 -3.66,47 -29.02,70.1 -29.02,70.1"
|
||||
id="path8255" />
|
||||
<path
|
||||
d="m 456.29,956.29 c 0,0 -26.52,-21.77 -32.58,-68.52 0,0 -0.26,48.21 9.75,71.23"
|
||||
id="path8257" />
|
||||
<path
|
||||
d="m 404.06,957.77 c 0,0 13.62,-20.66 18.45,-69.2"
|
||||
id="path8259" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_4)"
|
||||
d="m 423.73,337.05 -21.46,35.03 c -1.86,3.04 0.32,6.93 3.89,6.93 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.83 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.28 -3.95,-2.28 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8263" />
|
||||
<path
|
||||
style="fill:url(#Gradient_5)"
|
||||
d="m 273.05,178.98 c 0,97.08 68.93,175.78 153.96,175.79 v 0 c 85.03,0 153.96,-78.7 153.97,-175.79 v 0 C 580.98,81.9 512.05,3.2 427.01,3.2 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8265" />
|
||||
<path
|
||||
style="fill:url(#Gradient_6)"
|
||||
d="m 158.17,425.62 -21.46,35.02 c -1.86,3.04 0.32,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 L 166,425.71 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8267" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_7)"
|
||||
d="m 7.37,267.55 c 0,97.08 68.93,175.78 153.97,175.78 v 0 c 85.03,0 153.96,-78.7 153.96,-175.78 v 0 C 315.3,170.47 246.37,91.77 161.34,91.77 v 0 C 76.31,91.77 7.38,170.47 7.37,267.55 Z"
|
||||
id="path8269" />
|
||||
<path
|
||||
style="fill:url(#Gradient_8)"
|
||||
d="m 663.94,425.62 -21.46,35.02 c -1.86,3.04 0.33,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8271" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_9)"
|
||||
d="m 513.14,267.55 c 0,97.08 68.93,175.78 153.96,175.78 v 0 c 85.03,0 153.96,-78.7 153.97,-175.78 v 0 C 821.07,170.47 752.14,91.77 667.1,91.77 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8273" />
|
||||
<path
|
||||
style="fill:url(#Gradient_10)"
|
||||
d="m 285.46,567.53 -16.21,37.74 c -1.41,3.27 1.31,6.82 4.83,6.3 v 0 l 41.28,-5.97 c 3.47,-0.5 5.1,-4.58 2.93,-7.33 v 0 l -25.06,-31.76 c -0.93,-1.17 -2.25,-1.74 -3.57,-1.74 v 0 c -1.72,0 -3.42,0.96 -4.2,2.76 z"
|
||||
id="path8275" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_11)"
|
||||
d="m 240.79,236.67 c -84.15,12.18 -141.11,99.94 -127.2,196.02 v 0 c 13.9,96.08 93.39,164.1 177.54,151.92 v 0 c 84.15,-12.18 141.1,-99.94 127.21,-196.02 v 0 C 405.52,300 336.93,235.26 260.34,235.26 v 0 c -6.47,0 -12.99,0.46 -19.55,1.41 z"
|
||||
id="path8277" />
|
||||
<path
|
||||
style="fill:url(#Gradient_27)"
|
||||
d="M 542.05,569.11 513.87,599 c -2.44,2.59 -1.1,6.85 2.38,7.59 v 0 l 40.83,8.54 c 3.43,0.72 6.36,-2.55 5.25,-5.88 v 0 l -12.64,-38.43 c -0.66,-2.01 -2.48,-3.13 -4.35,-3.14 v 0 c -1.18,0 -2.38,0.46 -3.29,1.43 z"
|
||||
id="path8279" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_28)"
|
||||
d="m 426.83,383.51 c -19.89,95.02 31.46,186.18 114.68,203.6 v 0 c 83.23,17.42 166.82,-45.49 186.71,-140.52 v 0 C 748.11,351.57 696.76,260.41 613.54,242.99 v 0 c -9.34,-1.96 -18.68,-2.9 -27.94,-2.89 v 0 c -73.25,0 -141.11,59.05 -158.77,143.41 z"
|
||||
id="path8281" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_23)"
|
||||
d="m 126.74,409.71 c 0,0 29.93,-94.86 60.85,-110.42 19.92,-10.03 -4.23,-30.39 -27.01,-14.05 -6.7,5.14 -12.35,11.69 -17.06,18.66 -14.36,21.28 -19.56,46.01 -20.09,71.27 v 0.02 c -0.07,11.6 1.32,23.12 3.31,34.52 z"
|
||||
id="path8283" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_24)"
|
||||
d="m 30.74,269.01 c 0,0 34.33,-93.36 65.93,-107.45 20.37,-9.09 -2.81,-30.55 -26.32,-15.3 0,0 -51.89,32.72 -39.61,122.75 z"
|
||||
id="path8285" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_25)"
|
||||
d="m 537.49,256.64 c 0,0 37.96,-91.94 70.09,-104.8 20.71,-8.29 -1.61,-30.64 -25.71,-16.31 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8287" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_26)"
|
||||
d="m 305.43,154.66 c 0,0 37.96,-91.94 70.09,-104.79 20.71,-8.28 -1.61,-30.64 -25.71,-16.32 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8289" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_29)"
|
||||
d="m 454.08,393.82 c 0,0 44.65,-88.88 77.64,-99.32 21.27,-6.73 0.66,-30.67 -24.42,-18.17 0,0 -55.25,26.66 -53.22,117.49 z"
|
||||
id="path8291" />
|
||||
<path
|
||||
style="fill:url(#Gradient_12)"
|
||||
d="m 375.83,907.75 9.08,1.65 c -1.21,2.8 0.79,11.89 0.79,11.89 v 0 c 8.26,-15.42 34.5,-34.41 33.81,-33.91 v 0 l 0.71,-5.79 c -24.03,1.57 -44.39,26.16 -44.39,26.16 z"
|
||||
id="path8293" />
|
||||
<path
|
||||
style="fill:url(#Gradient_13)"
|
||||
d="m 380.2,872.6 c 13.6,7.74 40.82,5.99 40.82,5.99 v 0 c -22.8,-5.81 -32.93,-7.21 -37.4,-7.21 v 0 c -4.17,0 -3.42,1.22 -3.42,1.22 z"
|
||||
id="path8295" />
|
||||
<path
|
||||
style="fill:url(#Gradient_14)"
|
||||
d="m 380.45,890.39 c 7.74,5.62 42.01,-3.08 42.01,-3.09 v 0 l -0.09,-10.01 c -42.04,-1.73 -42.31,-5.05 -42.31,-5.05 v 0 z"
|
||||
id="path8297" />
|
||||
<g
|
||||
clip-path="url(#Clip_1)"
|
||||
opacity="0.24"
|
||||
id="g8301">
|
||||
<path
|
||||
style="fill:url(#Gradient_15)"
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c 0,0 -3,0.5 -8.21,-0.56 2.01,0.59 4.41,1.58 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8299" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_16)"
|
||||
d="m 409.38,881 c -1.53,-0.45 -2.83,-0.68 -2.83,-0.68 v 0 c 1.01,0.28 1.95,0.5 2.83,0.68 z"
|
||||
id="path8303" />
|
||||
<path
|
||||
style="fill:url(#Gradient_17)"
|
||||
d="m 425.53,887.37 c 0,0 25.53,18.33 33.88,33.85 v 0 c 0,0 1.98,-9.1 0.76,-11.89 v 0 l 9.08,-1.67 c 0,0 -20.4,-24.55 -44.44,-26.08 v 0 z"
|
||||
id="path8305" />
|
||||
<path
|
||||
style="fill:url(#Gradient_18)"
|
||||
d="m 423.74,878.59 c 0,0 40.72,9.96 40.43,-5.69 v 0 c -0.01,-0.45 0.33,-1.72 -3.83,-1.73 v 0 c -4.58,0 -14.62,1.54 -36.6,7.42 z"
|
||||
id="path8307" />
|
||||
<path
|
||||
style="fill:url(#Gradient_19)"
|
||||
d="m 422.39,877.29 -0.07,10.01 c 0,0 34.28,8.63 42.01,3 v 0 l -0.11,-17.86 c 0,0 -0.29,1.43 -41.83,4.85 z"
|
||||
id="path8309" />
|
||||
<g
|
||||
clip-path="url(#Clip_2)"
|
||||
opacity="0.24"
|
||||
id="g8313">
|
||||
<path
|
||||
style="fill:url(#Gradient_20)"
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -9.75,1.64 -12.88,-1.55 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8311" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_21)"
|
||||
d="m 435.38,880.98 c 0.88,-0.18 1.83,-0.4 2.83,-0.69 v 0 c 0,0 -1.3,0.23 -2.83,0.69 z"
|
||||
id="path8315" />
|
||||
<path
|
||||
style="fill:url(#Gradient_22)"
|
||||
d="m 417.09,877.31 c 0,0 -1.77,8.19 0.74,11.61 v 0 l 9.25,-0.01 c 0,0 2.64,-7.59 0.88,-11.59 v 0 c 0,0 -4.62,-1 -7.84,-1 v 0 c -1.6,0 -2.86,0.25 -3.03,0.99 z"
|
||||
id="path8317" />
|
||||
</symbol>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5797">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Kani"
|
||||
style="display:inline"
|
||||
transform="translate(-42.515769,-15.696706)">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 43.650626,20.134541 c -0.251481,0.607741 0.432618,1.167966 0.435552,1.177018 -0.124954,-0.366537 -0.257016,-0.662425 -0.01414,-0.918611"
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 49.326742,20.094569 c 0.251483,0.60774 -0.432616,1.167965 -0.435551,1.177016 0.124954,-0.366536 0.257016,-0.662424 0.01414,-0.91861"
|
||||
id="path5408"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 46.470512,16.917403 c -0.09786,-0.0012 -0.191501,0.17594 -0.365723,0.52246 -0.527336,-0.579974 -0.55431,-0.586996 -0.736002,0.198163 -0.0085,0.0035 -0.01698,0.0072 -0.02547,0.01082 -0.664216,-0.398156 -0.698535,-0.401271 -0.648128,0.377006 -0.01614,0.01196 -0.03225,0.02409 -0.0483,0.0364 -0.680644,-0.269624 -0.710073,-0.252634 -0.537839,0.494404 -0.008,0.0088 -0.01615,0.01741 -0.02419,0.02624 -0.693719,-0.187426 -0.713129,-0.159264 -0.454408,0.572695 -0.0111,0.01592 -0.02212,0.03212 -0.03316,0.04827 -0.78191,-0.08358 -0.797973,-0.06831 -0.400463,0.660184 -0.0019,0.0036 -0.004,0.0071 -0.0059,0.0107 -0.320341,0.153135 -0.426391,0.339784 -0.578183,0.590318 -0.01178,0.496878 0.520047,0.925101 1.28474,1.411761 -0.262719,-0.486913 -0.673566,-0.733744 -0.752387,-1.337683 0.115435,-0.217263 0.311739,-0.292314 0.480299,-0.390067 1.84107,1.074445 3.78503,1.0869 5.724449,-0.04115 0.169012,0.09834 0.366482,0.173122 0.482384,0.391265 -0.07882,0.603939 -0.489707,0.850731 -0.752426,1.337643 0.764692,-0.486658 1.296561,-0.914844 1.284779,-1.411722 -0.147581,-0.243582 -0.252513,-0.426693 -0.552601,-0.57741 0.374863,-0.689338 0.339179,-0.695826 -0.447607,-0.611494 -0.0066,-0.0087 -0.0133,-0.01733 -0.01998,-0.02589 0.271799,-0.767354 0.254748,-0.787407 -0.47798,-0.588618 0.185447,-0.800583 0.160666,-0.803848 -0.58174,-0.508779 0.05592,-0.84389 0.03589,-0.842138 -0.664667,-0.421948 -0.186812,-0.809024 -0.208854,-0.806616 -0.743345,-0.218722 -0.201042,-0.368936 -0.306818,-0.553622 -0.406182,-0.554804 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="matrix(0.07477963,0,0,0.07477963,38.800638,11.326586)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 44.607564,19.879672 c -0.03817,2.95e-4 -0.06361,0.0041 -0.05943,0.0066 0,0 -0.683042,0.892578 0.02319,1.395299 a 0.72888529,0.61895752 37.793943 0 0 0.107467,0.704702 0.72888529,0.61895752 37.793943 0 0 0.790026,0.296666 l -0.266524,-0.643531 0.687738,0.05499 a 0.72888529,0.61895752 37.793943 0 0 -0.525436,-0.666329 0.72888529,0.61895752 37.793943 0 0 -0.524043,6.81e-4 c -0.139263,-0.102008 -0.346133,-0.368365 -0.0031,-0.932895 0.11352,-0.186796 -0.115423,-0.217097 -0.22993,-0.21621 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
id="path8665"
|
||||
d="m 83.960168,109.11313 c -0.27485,0.43011 -0.4985,0.69147 -0.49798,0.62578 0,0 -14.965898,1.38701 -15.636208,-10.186101 a 9.7471106,8.2770874 84.335985 0 1 -7.216103,-6.22894 9.7471106,8.2770874 84.335985 0 1 2.259156,-11.0566 l 5.392134,7.59511 4.268531,-8.17939 a 9.7471106,8.2770874 84.335985 0 1 3.80891,10.68931 9.7471106,8.2770874 84.335985 0 1 -3.73468,5.92977 c 0.16465,2.302521 1.70979,6.539611 10.54286,6.669381 2.92274,0.043 1.63761,2.85111 0.81319,4.14154 z"
|
||||
style="display:none;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-up" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="kani-claw-right-overlay"
|
||||
style="display:inline"
|
||||
transform="translate(-42.515769,-15.696706)">
|
||||
<path
|
||||
d="m 49.863102,19.274345 c 0.262426,-0.232841 0.313802,-0.524307 0.237527,-0.851234 l -0.552725,0.286643 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523"
|
||||
inkscape:label="under-kani-claw" />
|
||||
<path
|
||||
id="path5732-74"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730566 -0.751843,0.49021 -0.762075,0.4806 -0.08228,-0.06403 -0.387206,0.271485 0.03983,0.391045 0.66705,0.186759 0.955364,-0.409403 1.058596,-0.723148 0.183308,0.01403 0.375396,-0.05843 0.527375,-0.198949 0.22948,-0.212782 0.324876,-0.540067 0.23615,-0.810187 l -0.621558,0.314348 4.31e-4,-0.09663 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730565 -0.751843,0.49021 -0.762075,0.480599 -0.08228,-0.06403 -0.387206,0.271486 0.03984,0.391045 0.667048,0.186759 0.955363,-0.409403 1.058595,-0.723147 0.183308,0.01403 0.375397,-0.05843 0.527375,-0.198949 0.229479,-0.212782 0.324876,-0.540067 0.236151,-0.810187 l -0.621559,0.314348 4.31e-4,-0.09663 z"
|
||||
id="path5728" />
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730565 -0.751843,0.49021 -0.762075,0.480599 -0.08228,-0.06403 -0.387206,0.271486 0.03984,0.391045 0.667048,0.186759 0.955363,-0.409403 1.058595,-0.723147 0.183308,0.01403 0.375397,-0.05843 0.527375,-0.198949 0.229479,-0.212782 0.324876,-0.540067 0.236151,-0.810187 l -0.621559,0.314348 4.31e-4,-0.09663 z"
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g7998"
|
||||
inkscape:label="party-hat"
|
||||
transform="matrix(1.0107117,0,0,0.94642879,-36.985227,-14.267983)"
|
||||
style="display:none">
|
||||
<path
|
||||
style="display:inline;fill:#1da1f2;fill-opacity:1;stroke:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path7024"
|
||||
inkscape:label="party-hat-background"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 90.866459,64.772976 -1.399384,3.650367 c 0,0 6.297977,-0.0079 9.604616,-2.229612 3.306639,-2.221751 6.641769,-4.763148 6.637539,-5.892882 -0.004,-1.129737 -1.2244,-3.398221 -1.2244,-3.398221 0,0 -1.76379,2.983434 -5.089689,4.759036 -3.325897,1.775606 -6.256176,3.317156 -8.528682,3.111312 z"
|
||||
id="path7711"
|
||||
inkscape:label="yellow-middle" />
|
||||
<path
|
||||
style="fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.283815,50.496253 c 0,0 2.017636,-0.742584 2.746046,-1.209859 0.68409,-0.438843 2.540819,-1.493505 2.505569,-1.916931 -0.0353,-0.423423 0.90713,1.638551 0.90713,1.638551 0,0 -0.43327,0.543192 -1.447199,1.610006 -1.01394,1.066813 -1.72817,1.358505 -2.26456,1.622681 -0.53638,0.264174 -2.0866,0.861497 -2.636383,0.793816 -0.549783,-0.06768 0.189397,-2.538264 0.189397,-2.538264 z"
|
||||
id="path7713"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="yellow-top" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 109.92717,71.488689 c 0,0 -2.20481,3.007619 -3.4367,4.221512 -1.06044,1.044951 -3.3987,2.32693 -5.45873,3.108264 -2.060039,0.78133 -7.390321,2.031263 -10.319319,2.035505 -2.53475,0.0037 -3.102127,-0.17882 -4.727213,-0.614261 -1.010264,-0.270699 -0.801047,2.045289 -0.801047,2.045289 l 4.858605,2.209687 10.217314,-0.32013 c 0,0 3.08806,-0.85865 3.26326,-0.9226 0.17519,-0.06395 5.61136,-3.775927 5.91906,-4.176562 0.30769,-0.400637 1.97931,-2.854544 1.85876,-3.106917 -0.12055,-0.25237 -1.37399,-4.479787 -1.37399,-4.479787 z"
|
||||
id="path7715"
|
||||
sodipodi:nodetypes="csssscccsssc"
|
||||
inkscape:label="yellow-bottom" />
|
||||
<path
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.208385,72.747325 c 0,0 6.251797,0.04012 9.907566,-1.876691 3.875559,-2.032049 5.147419,-2.116642 8.954089,-7.814465 -0.0353,-0.423423 1.59724,3.704345 1.59724,3.704345 0,0 -2.99139,5.115034 -6.19574,6.653752 -4.079519,1.958969 -6.324966,2.675602 -8.934752,3.106262 -1.713747,0.282798 -4.8213,0.352969 -6.27215,-0.01279 -0.537127,-0.135411 0.943747,-3.760409 0.943747,-3.760409 z"
|
||||
id="path7982"
|
||||
sodipodi:nodetypes="csccssscc"
|
||||
inkscape:label="white-middle" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 92.993027,57.289539 c 0,0 3.629855,-0.719631 5.482954,-2.090937 0.65332,-0.483462 3.662839,-3.285322 4.163269,-4.079419 -0.0353,-0.423423 0.98376,2.839616 0.98376,2.839616 0,0 -1.55545,1.919882 -2.68768,2.888013 -1.118619,0.956483 -3.276219,2.193755 -4.815637,2.748644 -1.634013,0.588985 -3.388075,0.798009 -3.937858,0.730328 -0.549783,-0.06768 0.811192,-3.036245 0.811192,-3.036245 z"
|
||||
id="path7979"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="white-top" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ff00ff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path508"
|
||||
inkscape:label="party-hat-outline"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:#8f57a8;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.307706,40.797374 8.863844,3.5236 c -4.511069,-1.476791 -5.455019,1.171445 -8.289058,2.243988 0,0 5.051628,-7.95802 4.765018,-7.734177 -1.618949,1.264417 -2.259979,9.16058 -2.259979,9.16058 l -0.26088,-9.396127 3.698779,7.921822 -7.078677,-2.809491 8.818747,-2.23602 z"
|
||||
id="path3171-3"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="display:inline;fill:#0056ed;fill-opacity:1;stroke:#ae00ff;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 96.516104,39.086314 5.923406,7.476417 c -3.172509,-3.530708 -5.311942,-1.706696 -8.303144,-2.191314 0,0 8.348654,-4.375959 7.988584,-4.324981 -2.03392,0.28796 -6.529397,6.811072 -6.529397,6.811072 l 4.462297,-8.273038 -0.747319,8.710783 -4.732664,-5.966807 8.758203,2.462516 z"
|
||||
id="path3171"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="fill:#744eaa;fill-opacity:1;stroke:#8f57a8;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.749242,80.805507 -1.299196,-0.793626 -0.72012,1.516668 -1.19957,0.02641 1.07959,1.592728 -0.479079,1.665647 1.727851,-0.04555 0.945116,1.102037 1.595689,-0.420439 1.013886,1.119783 1.616715,-0.611034 0.955484,0.869926 1.417278,-0.82042 1.399024,0.893951 1.62274,-0.936247 1.191522,0.880515 1.692439,-0.626057 1.62431,0.594614 1.273839,-0.730245 1.14228,0.675465 0.83977,-0.542118 1.7433,0.433922 1.37853,-0.883036 1.46376,0.789948 0.98369,-0.723702 1.56885,0.265388 0.83917,-1.064009 1.5817,0.538036 1.04635,-1.072595 1.45989,-0.386437 -0.0243,-1.46382 0.73064,-1.311775 -1.08662,-0.620199 -0.54503,-1.441178 -1.29888,0.821314 -1.72095,-0.803735 -0.89109,1.605976 -1.44802,-0.173747 -0.40144,0.954405 -1.25934,-0.74345 -1.14276,1.025692 -2.05145,-0.719347 c 0,0 -1.1538,1.054828 -1.21655,1.018337 -0.0627,-0.03649 -0.72908,-0.632037 -0.72908,-0.632037 l -2.781839,0.990357 -1.01136,-0.982973 -0.76464,0.897745 -1.265471,-0.508519 -1.392952,0.640072 -1.261957,-0.842494 -1.207529,1.021591 -2.137111,-1.168069 -0.83207,0.565255 -0.716719,-0.940683 -1.262123,0.222665 -0.854411,-1.073467 z"
|
||||
id="path3419"
|
||||
inkscape:label="purple-frizzy-bit" />
|
||||
</g>
|
||||
<g
|
||||
id="g571"
|
||||
transform="matrix(-0.37792196,-0.19227008,-0.19227008,0.37792196,158.66815,75.524887)"
|
||||
inkscape:export-filename="../fe6a9b8b/kani-stabby.png"
|
||||
inkscape:export-xdpi="370.63721"
|
||||
inkscape:export-ydpi="370.63721"
|
||||
style="display:none"
|
||||
inkscape:label="knife-left">
|
||||
<path
|
||||
d="M 327.32922,104.16963 313.23927,90.079688 246.31471,157.00414 c 0,0 -6.09712,4.9021 -4.45506,8.97393 1.6429,4.07209 4.34482,5.77218 11.55969,6.84567 6.14218,0.99798 6.56385,-1.72199 9.06459,-9.07879 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 5.35834,-9.35496 4.43089,-10.42811 12.07206,-10.21327 4.21357,0.0716 4.88879,-0.46249 6.31789,-1.74872 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439"
|
||||
style="fill:#c52a34;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path561" />
|
||||
<path
|
||||
d="M 333.98084,110.82126 313.52961,90.369671 c 0,0 66.27001,-67.178418 73.76936,-74.221626 7.49688,-7.0446203 13.081,-13.0810013 23.41845,-16.14946258 -0.68086,6.58883098 -6.21418,20.98428158 -13.48493,31.66357158 -7.2711,10.681759 -36.32483,51.549656 -63.25165,79.159106"
|
||||
style="fill:#b9b8b7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path563" />
|
||||
<path
|
||||
d="m 404.21431,2.595027 c -6.52039,3.3330447 -11.1573,8.142464 -16.91534,13.553018 -7.49935,7.043208 -73.76936,74.221626 -73.76936,74.221626 l 15.67956,15.678859 c 26.92717,-27.608745 55.97949,-68.476642 63.25094,-79.158049 5.17807,-7.605536 9.46362,-17.0825591 11.7542,-24.295454"
|
||||
style="fill:#999a99;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path565" />
|
||||
<path
|
||||
d="m 255.68936,173.17156 c -0.61955,0 -1.31989,-0.0656 -2.11762,-0.19541 -4.67209,-0.69397 -7.69193,-1.90252 -9.11972,-3.20187 l 0.0139,-0.014 c 1.82658,1.5197 4.5489,2.40839 8.9534,3.06351 0.81082,0.13188 1.52216,0.19899 2.15166,0.19899 4.13826,0 4.74239,-2.8925 6.91293,-9.27778 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 4.98299,-8.6995 4.53108,-10.23726 10.58792,-10.23726 0.4565,0 0.94862,0.009 1.48414,0.024 0.24729,0.004 0.48295,0.006 0.70661,0.006 3.58916,0 4.26614,-0.54433 5.61128,-1.75507 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439 v 0 c 0,0 -5.6,5.75451 -7.02875,7.03933 -1.34549,1.21109 -2.01824,1.7593 -5.61058,1.7593 -0.2226,0 -0.45649,-0.002 -0.70238,-0.006 -0.53269,-0.0152 -1.0227,-0.0236 -1.47708,-0.0236 -6.06319,0 -5.60035,1.54375 -10.5851,10.24714 -5.35693,9.35778 -17.62054,20.09429 -26.55122,29.02274 -8.92845,8.92803 -10.31434,4.2562 -12.81342,11.61408 -2.17593,6.40046 -2.71998,9.34932 -6.87133,9.34932 m 71.63986,-69.00193 -8.63636,-8.63635 v 0 l 8.63636,8.63635"
|
||||
style="fill:#cdccca;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path567" />
|
||||
<path
|
||||
d="m 255.571,173.02273 c -0.6295,0 -1.34084,-0.0671 -2.15166,-0.19899 -4.4045,-0.65512 -7.12682,-1.54381 -8.9534,-3.06351 l 74.22692,-74.22695 8.63636,8.63635 c 0,0 -5.60459,5.74958 -7.03334,7.03439 -1.34514,1.21074 -2.02212,1.75507 -5.61128,1.75507 -0.22366,0 -0.45932,-0.002 -0.70661,-0.006 -0.53552,-0.0152 -1.02764,-0.024 -1.48414,-0.024 -6.05684,0 -5.60493,1.53776 -10.58792,10.23726 -5.35587,9.35814 -17.63924,20.0762 -26.56932,29.0037 -8.92912,8.92874 -10.3536,4.21845 -12.85268,11.57524 -2.17054,6.38528 -2.77467,9.27778 -6.91293,9.27778"
|
||||
style="fill:#9b232b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path569" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 39 KiB |
|
@ -1,834 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="svg5800"
|
||||
version="1.1"
|
||||
viewBox="0 0 7.9374999 7.9374999"
|
||||
height="30"
|
||||
width="30"
|
||||
sodipodi:docname="icon-robot.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
|
||||
inkscape:export-filename="../94e4957b/kani-yellow-sign.png"
|
||||
inkscape:export-xdpi="86.699997"
|
||||
inkscape:export-ydpi="86.699997"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1391"
|
||||
inkscape:window-height="791"
|
||||
id="namedview108"
|
||||
showgrid="false"
|
||||
inkscape:zoom="13.325447"
|
||||
inkscape:cx="13.958256"
|
||||
inkscape:cy="23.826593"
|
||||
inkscape:window-x="49"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="-2.2872575,-58.804357"
|
||||
orientation="0,1"
|
||||
id="guide932"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleHorizontal"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="72.712742,16.195644"
|
||||
orientation="-1,0"
|
||||
id="guide934"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="MiddleVertical"
|
||||
inkscape:color="rgb(222,221,218)" />
|
||||
<sodipodi:guide
|
||||
position="2.4708111,-33.581074"
|
||||
orientation="0,-1"
|
||||
id="guide1652"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs5794">
|
||||
<radialGradient
|
||||
id="Gradient_4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="420.20801"
|
||||
cy="346.897"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8111" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8113" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="385.79401"
|
||||
cy="98.971001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#B1DEF4"
|
||||
id="stop8116" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#10A7CE"
|
||||
id="stop8118" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_6"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="154.649"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8121" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8123" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="120.117"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7B6D3"
|
||||
id="stop8126" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF5D73"
|
||||
id="stop8128" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_8"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="660.41699"
|
||||
cy="435.46399"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8131" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8133" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="625.88501"
|
||||
cy="187.53799"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#F7AEB4"
|
||||
id="stop8136" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#F60012"
|
||||
id="stop8138" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="283.38901"
|
||||
cy="577.77899"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8141" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8143" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_11"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="213.711"
|
||||
cy="337.353"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FBDEAD"
|
||||
id="stop8146" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF9800"
|
||||
id="stop8148" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="Gradient_12"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="395.94601"
|
||||
y1="909.60699"
|
||||
x2="398.86099"
|
||||
y2="889.30902">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8151" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8153" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="364.41199"
|
||||
y1="920.81097"
|
||||
x2="381.88199"
|
||||
y2="898.88202">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8156" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="400.103"
|
||||
y1="884.01398"
|
||||
x2="414.327"
|
||||
y2="886.43201">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8161" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8163" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="401.52899"
|
||||
y1="-883.02899"
|
||||
x2="418.35501"
|
||||
y2="-884.72101"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8166" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8168" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_1">
|
||||
<path
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c -2.74,0.34 -5.51,-0.08 -8.21,-0.56 v 0 c 1.75,0.6 3.93,1.12 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8171" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_16"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="406.53"
|
||||
y1="880.51599"
|
||||
x2="409.40302"
|
||||
y2="880.80499">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8174" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8176" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_17"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="452.20001"
|
||||
y1="905.45599"
|
||||
x2="444.604"
|
||||
y2="892.92102">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8179" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8181" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_18"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="462.254"
|
||||
y1="893.729"
|
||||
x2="456.45901"
|
||||
y2="887.92401">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8184" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8186" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_19"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="446.13501"
|
||||
y1="882.91602"
|
||||
x2="429.77499"
|
||||
y2="883.61603">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FF1F19"
|
||||
id="stop8189" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#B7282C"
|
||||
id="stop8191" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="Gradient_20"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="443.24799"
|
||||
y1="-882.92798"
|
||||
x2="426.452"
|
||||
y2="-884.64899"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8194" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8196" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="Clip_2">
|
||||
<path
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -3.99,0.52 -9.46,1.2 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8199" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="Gradient_21"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.23401"
|
||||
y1="880.48499"
|
||||
x2="435.36099"
|
||||
y2="880.78003">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#AF2525"
|
||||
id="stop8202" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#90282C"
|
||||
id="stop8204" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="Gradient_22"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="421.086"
|
||||
cy="879.30603"
|
||||
r="5.8280001">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#E61F19"
|
||||
id="stop8207" />
|
||||
<stop
|
||||
offset="0.988"
|
||||
stop-color="#9E282C"
|
||||
id="stop8209" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#9E282C"
|
||||
id="stop8211" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_23"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="146.832"
|
||||
cy="-316.11899"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8214" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8216" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_24"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55.174999"
|
||||
cy="-176.464"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8219" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8221" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_25"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="565.53101"
|
||||
cy="-165.11301"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8224" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8226" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_26"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="333.47"
|
||||
cy="-63.138"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8229" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8231" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_27"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="536.58099"
|
||||
cy="578.03198"
|
||||
r="21.1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8234" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8236" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_28"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="553.57397"
|
||||
cy="328.29001"
|
||||
r="165.23399">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#C0E7C7"
|
||||
id="stop8239" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#229614"
|
||||
id="stop8241" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="Gradient_29"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="488.81201"
|
||||
cy="-304.62601"
|
||||
r="53.613998"
|
||||
gradientTransform="scale(1,-1)">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#FFFFFF"
|
||||
id="stop8244" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFFFFF"
|
||||
stop-opacity="0.001"
|
||||
id="stop8246" />
|
||||
</radialGradient>
|
||||
<symbol
|
||||
id="balloons"
|
||||
viewBox="0 0 825 962">
|
||||
<g
|
||||
style="fill:none;stroke:#eccb78;stroke-width:4.069;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="g8261">
|
||||
<path
|
||||
d="M 291.13,584.61 422.41,889.24 540.38,589.26"
|
||||
id="path8249" />
|
||||
<path
|
||||
d="m 426.95,357.75 -4.54,531.49"
|
||||
id="path8251" />
|
||||
<path
|
||||
d="M 158.17,411.35 421.71,889.24 667.1,402.98"
|
||||
id="path8253" />
|
||||
<path
|
||||
d="m 415.21,958.51 c 8.81,-23.5 6.08,-71.63 6.08,-71.63 -3.66,47 -29.02,70.1 -29.02,70.1"
|
||||
id="path8255" />
|
||||
<path
|
||||
d="m 456.29,956.29 c 0,0 -26.52,-21.77 -32.58,-68.52 0,0 -0.26,48.21 9.75,71.23"
|
||||
id="path8257" />
|
||||
<path
|
||||
d="m 404.06,957.77 c 0,0 13.62,-20.66 18.45,-69.2"
|
||||
id="path8259" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_4)"
|
||||
d="m 423.73,337.05 -21.46,35.03 c -1.86,3.04 0.32,6.93 3.89,6.93 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.83 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.28 -3.95,-2.28 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8263" />
|
||||
<path
|
||||
style="fill:url(#Gradient_5)"
|
||||
d="m 273.05,178.98 c 0,97.08 68.93,175.78 153.96,175.79 v 0 c 85.03,0 153.96,-78.7 153.97,-175.79 v 0 C 580.98,81.9 512.05,3.2 427.01,3.2 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8265" />
|
||||
<path
|
||||
style="fill:url(#Gradient_6)"
|
||||
d="m 158.17,425.62 -21.46,35.02 c -1.86,3.04 0.32,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 L 166,425.71 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8267" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_7)"
|
||||
d="m 7.37,267.55 c 0,97.08 68.93,175.78 153.97,175.78 v 0 c 85.03,0 153.96,-78.7 153.96,-175.78 v 0 C 315.3,170.47 246.37,91.77 161.34,91.77 v 0 C 76.31,91.77 7.38,170.47 7.37,267.55 Z"
|
||||
id="path8269" />
|
||||
<path
|
||||
style="fill:url(#Gradient_8)"
|
||||
d="m 663.94,425.62 -21.46,35.02 c -1.86,3.04 0.33,6.94 3.89,6.94 v 0 h 41.71 c 3.51,0 5.7,-3.8 3.94,-6.84 v 0 l -20.25,-35.03 c -0.88,-1.51 -2.41,-2.27 -3.95,-2.27 v 0 c -1.5,0 -2.99,0.72 -3.88,2.18 z"
|
||||
id="path8271" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_9)"
|
||||
d="m 513.14,267.55 c 0,97.08 68.93,175.78 153.96,175.78 v 0 c 85.03,0 153.96,-78.7 153.97,-175.78 v 0 C 821.07,170.47 752.14,91.77 667.1,91.77 v 0 c -85.03,0 -153.96,78.7 -153.96,175.78 z"
|
||||
id="path8273" />
|
||||
<path
|
||||
style="fill:url(#Gradient_10)"
|
||||
d="m 285.46,567.53 -16.21,37.74 c -1.41,3.27 1.31,6.82 4.83,6.3 v 0 l 41.28,-5.97 c 3.47,-0.5 5.1,-4.58 2.93,-7.33 v 0 l -25.06,-31.76 c -0.93,-1.17 -2.25,-1.74 -3.57,-1.74 v 0 c -1.72,0 -3.42,0.96 -4.2,2.76 z"
|
||||
id="path8275" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_11)"
|
||||
d="m 240.79,236.67 c -84.15,12.18 -141.11,99.94 -127.2,196.02 v 0 c 13.9,96.08 93.39,164.1 177.54,151.92 v 0 c 84.15,-12.18 141.1,-99.94 127.21,-196.02 v 0 C 405.52,300 336.93,235.26 260.34,235.26 v 0 c -6.47,0 -12.99,0.46 -19.55,1.41 z"
|
||||
id="path8277" />
|
||||
<path
|
||||
style="fill:url(#Gradient_27)"
|
||||
d="M 542.05,569.11 513.87,599 c -2.44,2.59 -1.1,6.85 2.38,7.59 v 0 l 40.83,8.54 c 3.43,0.72 6.36,-2.55 5.25,-5.88 v 0 l -12.64,-38.43 c -0.66,-2.01 -2.48,-3.13 -4.35,-3.14 v 0 c -1.18,0 -2.38,0.46 -3.29,1.43 z"
|
||||
id="path8279" />
|
||||
<path
|
||||
style="opacity:0.95;fill:url(#Gradient_28)"
|
||||
d="m 426.83,383.51 c -19.89,95.02 31.46,186.18 114.68,203.6 v 0 c 83.23,17.42 166.82,-45.49 186.71,-140.52 v 0 C 748.11,351.57 696.76,260.41 613.54,242.99 v 0 c -9.34,-1.96 -18.68,-2.9 -27.94,-2.89 v 0 c -73.25,0 -141.11,59.05 -158.77,143.41 z"
|
||||
id="path8281" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_23)"
|
||||
d="m 126.74,409.71 c 0,0 29.93,-94.86 60.85,-110.42 19.92,-10.03 -4.23,-30.39 -27.01,-14.05 -6.7,5.14 -12.35,11.69 -17.06,18.66 -14.36,21.28 -19.56,46.01 -20.09,71.27 v 0.02 c -0.07,11.6 1.32,23.12 3.31,34.52 z"
|
||||
id="path8283" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_24)"
|
||||
d="m 30.74,269.01 c 0,0 34.33,-93.36 65.93,-107.45 20.37,-9.09 -2.81,-30.55 -26.32,-15.3 0,0 -51.89,32.72 -39.61,122.75 z"
|
||||
id="path8285" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_25)"
|
||||
d="m 537.49,256.64 c 0,0 37.96,-91.94 70.09,-104.8 20.71,-8.29 -1.61,-30.64 -25.71,-16.31 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8287" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_26)"
|
||||
d="m 305.43,154.66 c 0,0 37.96,-91.94 70.09,-104.79 20.71,-8.28 -1.61,-30.64 -25.71,-16.32 0,0 -53.13,30.67 -44.38,121.11 z"
|
||||
id="path8289" />
|
||||
<path
|
||||
style="opacity:0.7;fill:url(#Gradient_29)"
|
||||
d="m 454.08,393.82 c 0,0 44.65,-88.88 77.64,-99.32 21.27,-6.73 0.66,-30.67 -24.42,-18.17 0,0 -55.25,26.66 -53.22,117.49 z"
|
||||
id="path8291" />
|
||||
<path
|
||||
style="fill:url(#Gradient_12)"
|
||||
d="m 375.83,907.75 9.08,1.65 c -1.21,2.8 0.79,11.89 0.79,11.89 v 0 c 8.26,-15.42 34.5,-34.41 33.81,-33.91 v 0 l 0.71,-5.79 c -24.03,1.57 -44.39,26.16 -44.39,26.16 z"
|
||||
id="path8293" />
|
||||
<path
|
||||
style="fill:url(#Gradient_13)"
|
||||
d="m 380.2,872.6 c 13.6,7.74 40.82,5.99 40.82,5.99 v 0 c -22.8,-5.81 -32.93,-7.21 -37.4,-7.21 v 0 c -4.17,0 -3.42,1.22 -3.42,1.22 z"
|
||||
id="path8295" />
|
||||
<path
|
||||
style="fill:url(#Gradient_14)"
|
||||
d="m 380.45,890.39 c 7.74,5.62 42.01,-3.08 42.01,-3.09 v 0 l -0.09,-10.01 c -42.04,-1.73 -42.31,-5.05 -42.31,-5.05 v 0 z"
|
||||
id="path8297" />
|
||||
<g
|
||||
clip-path="url(#Clip_1)"
|
||||
opacity="0.24"
|
||||
id="g8301">
|
||||
<path
|
||||
style="fill:url(#Gradient_15)"
|
||||
d="m 408.16,886.73 c 2.63,0.16 5.1,-0.27 7.57,-1.06 3.52,-1.3 2.99,-1.72 1.65,-1.82 v 0 l 0.21,-2.29 c 0,0 -3,0.5 -8.21,-0.56 2.01,0.59 4.41,1.58 4.79,2.94 -0.02,0 -0.03,0 -0.03,0 0,0 -3.11,3.22 -12.86,1.6 2.22,0.78 4.56,0.96 6.88,1.19 z"
|
||||
id="path8299" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_16)"
|
||||
d="m 409.38,881 c -1.53,-0.45 -2.83,-0.68 -2.83,-0.68 v 0 c 1.01,0.28 1.95,0.5 2.83,0.68 z"
|
||||
id="path8303" />
|
||||
<path
|
||||
style="fill:url(#Gradient_17)"
|
||||
d="m 425.53,887.37 c 0,0 25.53,18.33 33.88,33.85 v 0 c 0,0 1.98,-9.1 0.76,-11.89 v 0 l 9.08,-1.67 c 0,0 -20.4,-24.55 -44.44,-26.08 v 0 z"
|
||||
id="path8305" />
|
||||
<path
|
||||
style="fill:url(#Gradient_18)"
|
||||
d="m 423.74,878.59 c 0,0 40.72,9.96 40.43,-5.69 v 0 c -0.01,-0.45 0.33,-1.72 -3.83,-1.73 v 0 c -4.58,0 -14.62,1.54 -36.6,7.42 z"
|
||||
id="path8307" />
|
||||
<path
|
||||
style="fill:url(#Gradient_19)"
|
||||
d="m 422.39,877.29 -0.07,10.01 c 0,0 34.28,8.63 42.01,3 v 0 l -0.11,-17.86 c 0,0 -0.29,1.43 -41.83,4.85 z"
|
||||
id="path8309" />
|
||||
<g
|
||||
clip-path="url(#Clip_2)"
|
||||
opacity="0.24"
|
||||
id="g8313">
|
||||
<path
|
||||
style="fill:url(#Gradient_20)"
|
||||
d="m 436.63,886.65 c 2.32,-0.16 4.66,-0.45 6.88,-1.19 -9.75,1.64 -12.88,-1.55 -12.88,-1.55 0,0 -0.01,0.01 -0.03,0 0.38,-1.36 2.78,-2.34 4.78,-2.94 -5.2,1.07 -8.18,0.51 -8.18,0.51 l 0.23,2.22 0.01,0.01 c -1.35,0.13 -1.9,0.59 1.62,1.88 2.44,0.98 4.99,0.96 7.57,1.06 z"
|
||||
id="path8311" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:url(#Gradient_21)"
|
||||
d="m 435.38,880.98 c 0.88,-0.18 1.83,-0.4 2.83,-0.69 v 0 c 0,0 -1.3,0.23 -2.83,0.69 z"
|
||||
id="path8315" />
|
||||
<path
|
||||
style="fill:url(#Gradient_22)"
|
||||
d="m 417.09,877.31 c 0,0 -1.77,8.19 0.74,11.61 v 0 l 9.25,-0.01 c 0,0 2.64,-7.59 0.88,-11.59 v 0 c 0,0 -4.62,-1 -7.84,-1 v 0 c -1.6,0 -2.86,0.25 -3.03,0.99 z"
|
||||
id="path8317" />
|
||||
</symbol>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5797">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Kani"
|
||||
style="display:inline"
|
||||
transform="translate(-42.515769,-15.696706)">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 43.650626,20.134541 c -0.251481,0.607741 0.432618,1.167966 0.435552,1.177018 -0.124954,-0.366537 -0.257016,-0.662425 -0.01414,-0.918611"
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-rear-claw-left"
|
||||
inkscape:export-filename="../1d28c49c/party-kani.png"
|
||||
inkscape:export-xdpi="160.64"
|
||||
inkscape:export-ydpi="160.64" />
|
||||
<path
|
||||
style="fill:#803300;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 49.326742,20.094569 c 0.251483,0.60774 -0.432616,1.167965 -0.435551,1.177016 0.124954,-0.366536 0.257016,-0.662424 0.01414,-0.91861"
|
||||
id="path5408"
|
||||
inkscape:label="kani-rear-claw-right" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 46.470512,16.917403 c -0.09786,-0.0012 -0.191501,0.17594 -0.365723,0.52246 -0.527336,-0.579974 -0.55431,-0.586996 -0.736002,0.198163 -0.0085,0.0035 -0.01698,0.0072 -0.02547,0.01082 -0.664216,-0.398156 -0.698535,-0.401271 -0.648128,0.377006 -0.01614,0.01196 -0.03225,0.02409 -0.0483,0.0364 -0.680644,-0.269624 -0.710073,-0.252634 -0.537839,0.494404 -0.008,0.0088 -0.01615,0.01741 -0.02419,0.02624 -0.693719,-0.187426 -0.713129,-0.159264 -0.454408,0.572695 -0.0111,0.01592 -0.02212,0.03212 -0.03316,0.04827 -0.78191,-0.08358 -0.797973,-0.06831 -0.400463,0.660184 -0.0019,0.0036 -0.004,0.0071 -0.0059,0.0107 -0.320341,0.153135 -0.426391,0.339784 -0.578183,0.590318 -0.01178,0.496878 0.520047,0.925101 1.28474,1.411761 -0.262719,-0.486913 -0.673566,-0.733744 -0.752387,-1.337683 0.115435,-0.217263 0.311739,-0.292314 0.480299,-0.390067 1.84107,1.074445 3.78503,1.0869 5.724449,-0.04115 0.169012,0.09834 0.366482,0.173122 0.482384,0.391265 -0.07882,0.603939 -0.489707,0.850731 -0.752426,1.337643 0.764692,-0.486658 1.296561,-0.914844 1.284779,-1.411722 -0.147581,-0.243582 -0.252513,-0.426693 -0.552601,-0.57741 0.374863,-0.689338 0.339179,-0.695826 -0.447607,-0.611494 -0.0066,-0.0087 -0.0133,-0.01733 -0.01998,-0.02589 0.271799,-0.767354 0.254748,-0.787407 -0.47798,-0.588618 0.185447,-0.800583 0.160666,-0.803848 -0.58174,-0.508779 0.05592,-0.84389 0.03589,-0.842138 -0.664667,-0.421948 -0.186812,-0.809024 -0.208854,-0.806616 -0.743345,-0.218722 -0.201042,-0.368936 -0.306818,-0.553622 -0.406182,-0.554804 z"
|
||||
style="display:inline;fill:#5791e8;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||
inkscape:label="kani-body" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="matrix(0.07477963,0,0,0.07477963,38.800638,11.326586)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani-face">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399"
|
||||
inkscape:label="kani-smile" />
|
||||
<g
|
||||
id="g351"
|
||||
inkscape:label="kani-eye-left">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355"
|
||||
inkscape:label="kani-eye-right">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 44.607564,19.879672 c -0.03817,2.95e-4 -0.06361,0.0041 -0.05943,0.0066 0,0 -0.683042,0.892578 0.02319,1.395299 a 0.72888529,0.61895752 37.793943 0 0 0.107467,0.704702 0.72888529,0.61895752 37.793943 0 0 0.790026,0.296666 l -0.266524,-0.643531 0.687738,0.05499 a 0.72888529,0.61895752 37.793943 0 0 -0.525436,-0.666329 0.72888529,0.61895752 37.793943 0 0 -0.524043,6.81e-4 c -0.139263,-0.102008 -0.346133,-0.368365 -0.0031,-0.932895 0.11352,-0.186796 -0.115423,-0.217097 -0.22993,-0.21621 z"
|
||||
style="display:inline;fill:#5791e8;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-down" />
|
||||
<path
|
||||
id="path8665"
|
||||
d="m 83.960168,109.11313 c -0.27485,0.43011 -0.4985,0.69147 -0.49798,0.62578 0,0 -14.965898,1.38701 -15.636208,-10.186101 a 9.7471106,8.2770874 84.335985 0 1 -7.216103,-6.22894 9.7471106,8.2770874 84.335985 0 1 2.259156,-11.0566 l 5.392134,7.59511 4.268531,-8.17939 a 9.7471106,8.2770874 84.335985 0 1 3.80891,10.68931 9.7471106,8.2770874 84.335985 0 1 -3.73468,5.92977 c 0.16465,2.302521 1.70979,6.539611 10.54286,6.669381 2.92274,0.043 1.63761,2.85111 0.81319,4.14154 z"
|
||||
style="display:none;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="kani-claw-left-up" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="kani-claw-right-overlay"
|
||||
style="display:inline"
|
||||
transform="translate(-42.515769,-15.696706)">
|
||||
<path
|
||||
d="m 49.863102,19.274345 c 0.262426,-0.232841 0.313802,-0.524307 0.237527,-0.851234 l -0.552725,0.286643 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523"
|
||||
inkscape:label="under-kani-claw" />
|
||||
<path
|
||||
id="path5732-74"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730566 -0.751843,0.49021 -0.762075,0.4806 -0.08228,-0.06403 -0.387206,0.271485 0.03983,0.391045 0.66705,0.186759 0.955364,-0.409403 1.058596,-0.723148 0.183308,0.01403 0.375396,-0.05843 0.527375,-0.198949 0.22948,-0.212782 0.324876,-0.540067 0.23615,-0.810187 l -0.621558,0.314348 4.31e-4,-0.09663 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730565 -0.751843,0.49021 -0.762075,0.480599 -0.08228,-0.06403 -0.387206,0.271486 0.03984,0.391045 0.667048,0.186759 0.955363,-0.409403 1.058595,-0.723147 0.183308,0.01403 0.375397,-0.05843 0.527375,-0.198949 0.229479,-0.212782 0.324876,-0.540067 0.236151,-0.810187 l -0.621559,0.314348 4.31e-4,-0.09663 z"
|
||||
id="path5728" />
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 49.20747,18.172558 c -0.16312,0.106491 -0.287526,0.274108 -0.343892,0.463358 -0.07413,0.250562 -0.01916,0.504164 0.143494,0.661943 -0.267667,0.730565 -0.751843,0.49021 -0.762075,0.480599 -0.08228,-0.06403 -0.387206,0.271486 0.03984,0.391045 0.667048,0.186759 0.955363,-0.409403 1.058595,-0.723147 0.183308,0.01403 0.375397,-0.05843 0.527375,-0.198949 0.229479,-0.212782 0.324876,-0.540067 0.236151,-0.810187 l -0.621559,0.314348 4.31e-4,-0.09663 z"
|
||||
style="display:inline;opacity:1;fill:#5791e8;fill-opacity:1;stroke:#000000;stroke-width:0.0747797;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g7998"
|
||||
inkscape:label="party-hat"
|
||||
transform="matrix(1.0107117,0,0,0.94642879,-36.985227,-14.267983)"
|
||||
style="display:none">
|
||||
<path
|
||||
style="display:inline;fill:#1da1f2;fill-opacity:1;stroke:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path7024"
|
||||
inkscape:label="party-hat-background"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 90.866459,64.772976 -1.399384,3.650367 c 0,0 6.297977,-0.0079 9.604616,-2.229612 3.306639,-2.221751 6.641769,-4.763148 6.637539,-5.892882 -0.004,-1.129737 -1.2244,-3.398221 -1.2244,-3.398221 0,0 -1.76379,2.983434 -5.089689,4.759036 -3.325897,1.775606 -6.256176,3.317156 -8.528682,3.111312 z"
|
||||
id="path7711"
|
||||
inkscape:label="yellow-middle" />
|
||||
<path
|
||||
style="fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.283815,50.496253 c 0,0 2.017636,-0.742584 2.746046,-1.209859 0.68409,-0.438843 2.540819,-1.493505 2.505569,-1.916931 -0.0353,-0.423423 0.90713,1.638551 0.90713,1.638551 0,0 -0.43327,0.543192 -1.447199,1.610006 -1.01394,1.066813 -1.72817,1.358505 -2.26456,1.622681 -0.53638,0.264174 -2.0866,0.861497 -2.636383,0.793816 -0.549783,-0.06768 0.189397,-2.538264 0.189397,-2.538264 z"
|
||||
id="path7713"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="yellow-top" />
|
||||
<path
|
||||
style="display:inline;fill:#ffd60f;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 109.92717,71.488689 c 0,0 -2.20481,3.007619 -3.4367,4.221512 -1.06044,1.044951 -3.3987,2.32693 -5.45873,3.108264 -2.060039,0.78133 -7.390321,2.031263 -10.319319,2.035505 -2.53475,0.0037 -3.102127,-0.17882 -4.727213,-0.614261 -1.010264,-0.270699 -0.801047,2.045289 -0.801047,2.045289 l 4.858605,2.209687 10.217314,-0.32013 c 0,0 3.08806,-0.85865 3.26326,-0.9226 0.17519,-0.06395 5.61136,-3.775927 5.91906,-4.176562 0.30769,-0.400637 1.97931,-2.854544 1.85876,-3.106917 -0.12055,-0.25237 -1.37399,-4.479787 -1.37399,-4.479787 z"
|
||||
id="path7715"
|
||||
sodipodi:nodetypes="csssscccsssc"
|
||||
inkscape:label="yellow-bottom" />
|
||||
<path
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.208385,72.747325 c 0,0 6.251797,0.04012 9.907566,-1.876691 3.875559,-2.032049 5.147419,-2.116642 8.954089,-7.814465 -0.0353,-0.423423 1.59724,3.704345 1.59724,3.704345 0,0 -2.99139,5.115034 -6.19574,6.653752 -4.079519,1.958969 -6.324966,2.675602 -8.934752,3.106262 -1.713747,0.282798 -4.8213,0.352969 -6.27215,-0.01279 -0.537127,-0.135411 0.943747,-3.760409 0.943747,-3.760409 z"
|
||||
id="path7982"
|
||||
sodipodi:nodetypes="csccssscc"
|
||||
inkscape:label="white-middle" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ff00ff;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 92.993027,57.289539 c 0,0 3.629855,-0.719631 5.482954,-2.090937 0.65332,-0.483462 3.662839,-3.285322 4.163269,-4.079419 -0.0353,-0.423423 0.98376,2.839616 0.98376,2.839616 0,0 -1.55545,1.919882 -2.68768,2.888013 -1.118619,0.956483 -3.276219,2.193755 -4.815637,2.748644 -1.634013,0.588985 -3.388075,0.798009 -3.937858,0.730328 -0.549783,-0.06768 0.811192,-3.036245 0.811192,-3.036245 z"
|
||||
id="path7979"
|
||||
sodipodi:nodetypes="csccsssc"
|
||||
inkscape:label="white-top" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ff00ff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 84.970159,82.659204 98.594291,41.592222 113.931,82.386454 c 0,0 -8.7088,2.847069 -15.025249,2.754354 -6.316442,-0.09272 -13.935592,-2.481604 -13.935592,-2.481604 z"
|
||||
id="path508"
|
||||
inkscape:label="party-hat-outline"
|
||||
sodipodi:nodetypes="cccsc" />
|
||||
<path
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:#8f57a8;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 95.307706,40.797374 8.863844,3.5236 c -4.511069,-1.476791 -5.455019,1.171445 -8.289058,2.243988 0,0 5.051628,-7.95802 4.765018,-7.734177 -1.618949,1.264417 -2.259979,9.16058 -2.259979,9.16058 l -0.26088,-9.396127 3.698779,7.921822 -7.078677,-2.809491 8.818747,-2.23602 z"
|
||||
id="path3171-3"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="display:inline;fill:#0056ed;fill-opacity:1;stroke:#ae00ff;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 96.516104,39.086314 5.923406,7.476417 c -3.172509,-3.530708 -5.311942,-1.706696 -8.303144,-2.191314 0,0 8.348654,-4.375959 7.988584,-4.324981 -2.03392,0.28796 -6.529397,6.811072 -6.529397,6.811072 l 4.462297,-8.273038 -0.747319,8.710783 -4.732664,-5.966807 8.758203,2.462516 z"
|
||||
id="path3171"
|
||||
sodipodi:nodetypes="cccscccccc"
|
||||
inkscape:label="pompom" />
|
||||
<path
|
||||
style="fill:#744eaa;fill-opacity:1;stroke:#8f57a8;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.749242,80.805507 -1.299196,-0.793626 -0.72012,1.516668 -1.19957,0.02641 1.07959,1.592728 -0.479079,1.665647 1.727851,-0.04555 0.945116,1.102037 1.595689,-0.420439 1.013886,1.119783 1.616715,-0.611034 0.955484,0.869926 1.417278,-0.82042 1.399024,0.893951 1.62274,-0.936247 1.191522,0.880515 1.692439,-0.626057 1.62431,0.594614 1.273839,-0.730245 1.14228,0.675465 0.83977,-0.542118 1.7433,0.433922 1.37853,-0.883036 1.46376,0.789948 0.98369,-0.723702 1.56885,0.265388 0.83917,-1.064009 1.5817,0.538036 1.04635,-1.072595 1.45989,-0.386437 -0.0243,-1.46382 0.73064,-1.311775 -1.08662,-0.620199 -0.54503,-1.441178 -1.29888,0.821314 -1.72095,-0.803735 -0.89109,1.605976 -1.44802,-0.173747 -0.40144,0.954405 -1.25934,-0.74345 -1.14276,1.025692 -2.05145,-0.719347 c 0,0 -1.1538,1.054828 -1.21655,1.018337 -0.0627,-0.03649 -0.72908,-0.632037 -0.72908,-0.632037 l -2.781839,0.990357 -1.01136,-0.982973 -0.76464,0.897745 -1.265471,-0.508519 -1.392952,0.640072 -1.261957,-0.842494 -1.207529,1.021591 -2.137111,-1.168069 -0.83207,0.565255 -0.716719,-0.940683 -1.262123,0.222665 -0.854411,-1.073467 z"
|
||||
id="path3419"
|
||||
inkscape:label="purple-frizzy-bit" />
|
||||
</g>
|
||||
<g
|
||||
id="g571"
|
||||
transform="matrix(-0.37792196,-0.19227008,-0.19227008,0.37792196,158.66815,75.524887)"
|
||||
inkscape:export-filename="../fe6a9b8b/kani-stabby.png"
|
||||
inkscape:export-xdpi="370.63721"
|
||||
inkscape:export-ydpi="370.63721"
|
||||
style="display:none"
|
||||
inkscape:label="knife-left">
|
||||
<path
|
||||
d="M 327.32922,104.16963 313.23927,90.079688 246.31471,157.00414 c 0,0 -6.09712,4.9021 -4.45506,8.97393 1.6429,4.07209 4.34482,5.77218 11.55969,6.84567 6.14218,0.99798 6.56385,-1.72199 9.06459,-9.07879 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 5.35834,-9.35496 4.43089,-10.42811 12.07206,-10.21327 4.21357,0.0716 4.88879,-0.46249 6.31789,-1.74872 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439"
|
||||
style="fill:#c52a34;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path561" />
|
||||
<path
|
||||
d="M 333.98084,110.82126 313.52961,90.369671 c 0,0 66.27001,-67.178418 73.76936,-74.221626 7.49688,-7.0446203 13.081,-13.0810013 23.41845,-16.14946258 -0.68086,6.58883098 -6.21418,20.98428158 -13.48493,31.66357158 -7.2711,10.681759 -36.32483,51.549656 -63.25165,79.159106"
|
||||
style="fill:#b9b8b7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path563" />
|
||||
<path
|
||||
d="m 404.21431,2.595027 c -6.52039,3.3330447 -11.1573,8.142464 -16.91534,13.553018 -7.49935,7.043208 -73.76936,74.221626 -73.76936,74.221626 l 15.67956,15.678859 c 26.92717,-27.608745 55.97949,-68.476642 63.25094,-79.158049 5.17807,-7.605536 9.46362,-17.0825591 11.7542,-24.295454"
|
||||
style="fill:#999a99;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path565" />
|
||||
<path
|
||||
d="m 255.68936,173.17156 c -0.61955,0 -1.31989,-0.0656 -2.11762,-0.19541 -4.67209,-0.69397 -7.69193,-1.90252 -9.11972,-3.20187 l 0.0139,-0.014 c 1.82658,1.5197 4.5489,2.40839 8.9534,3.06351 0.81082,0.13188 1.52216,0.19899 2.15166,0.19899 4.13826,0 4.74239,-2.8925 6.91293,-9.27778 2.49908,-7.35679 3.92356,-2.6465 12.85268,-11.57524 8.93008,-8.9275 21.21345,-19.64556 26.56932,-29.0037 4.98299,-8.6995 4.53108,-10.23726 10.58792,-10.23726 0.4565,0 0.94862,0.009 1.48414,0.024 0.24729,0.004 0.48295,0.006 0.70661,0.006 3.58916,0 4.26614,-0.54433 5.61128,-1.75507 1.42875,-1.28481 7.03334,-7.03439 7.03334,-7.03439 v 0 c 0,0 -5.6,5.75451 -7.02875,7.03933 -1.34549,1.21109 -2.01824,1.7593 -5.61058,1.7593 -0.2226,0 -0.45649,-0.002 -0.70238,-0.006 -0.53269,-0.0152 -1.0227,-0.0236 -1.47708,-0.0236 -6.06319,0 -5.60035,1.54375 -10.5851,10.24714 -5.35693,9.35778 -17.62054,20.09429 -26.55122,29.02274 -8.92845,8.92803 -10.31434,4.2562 -12.81342,11.61408 -2.17593,6.40046 -2.71998,9.34932 -6.87133,9.34932 m 71.63986,-69.00193 -8.63636,-8.63635 v 0 l 8.63636,8.63635"
|
||||
style="fill:#cdccca;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path567" />
|
||||
<path
|
||||
d="m 255.571,173.02273 c -0.6295,0 -1.34084,-0.0671 -2.15166,-0.19899 -4.4045,-0.65512 -7.12682,-1.54381 -8.9534,-3.06351 l 74.22692,-74.22695 8.63636,8.63635 c 0,0 -5.60459,5.74958 -7.03334,7.03439 -1.34514,1.21074 -2.02212,1.75507 -5.61128,1.75507 -0.22366,0 -0.45932,-0.002 -0.70661,-0.006 -0.53552,-0.0152 -1.02764,-0.024 -1.48414,-0.024 -6.05684,0 -5.60493,1.53776 -10.58792,10.23726 -5.35587,9.35814 -17.63924,20.0762 -26.56932,29.0037 -8.92912,8.92874 -10.3536,4.21845 -12.85268,11.57524 -2.17054,6.38528 -2.77467,9.27778 -6.91293,9.27778"
|
||||
style="fill:#9b232b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0352778"
|
||||
id="path569" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 39 KiB |
|
@ -1,168 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="256"
|
||||
height="256"
|
||||
viewBox="0 0 135.46667 135.46666"
|
||||
version="1.1"
|
||||
id="svg1084"
|
||||
sodipodi:docname="kani-waving.svg"
|
||||
inkscape:version="1.2 (dc2aeda, 2022-05-15)"
|
||||
inkscape:export-filename="logo-180.png"
|
||||
inkscape:export-xdpi="33.75"
|
||||
inkscape:export-ydpi="33.75"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title332">Kanidm Square Logo</title>
|
||||
<sodipodi:namedview
|
||||
id="namedview39"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="178"
|
||||
inkscape:cy="304.5"
|
||||
inkscape:window-width="1389"
|
||||
inkscape:window-height="847"
|
||||
inkscape:window-x="51"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1084">
|
||||
<sodipodi:guide
|
||||
position="-52.916665,67.733332"
|
||||
orientation="0,1"
|
||||
id="guide145"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="vertical_middle"
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="121.97292,175.15416"
|
||||
orientation="-1,0"
|
||||
id="guide777"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="13.49375,173.03749"
|
||||
orientation="-1,0"
|
||||
id="guide779"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="22.754166,121.97292"
|
||||
orientation="0,1"
|
||||
id="guide781"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="4.4979168,13.758333"
|
||||
orientation="0,1"
|
||||
id="guide783"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1081" />
|
||||
<metadata
|
||||
id="metadata330">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>Kanidm Square Logo</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
transform="matrix(1.0952772,0,0,1.0952772,-42.847275,-49.68044)"
|
||||
inkscape:label="kani"
|
||||
style="display:inline">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 62.537712,110.23377 c -3.36297,8.12708 5.78522,15.61876 5.82446,15.73981 -1.67096,-4.90156 -3.43697,-8.85836 -0.189,-12.28424"
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 138.4423,109.69923 c 3.36297,8.12708 -5.78522,15.61876 -5.82446,15.7398 1.67096,-4.90155 3.43697,-8.85835 0.189,-12.28423"
|
||||
id="path5408" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 100.24698,67.21217 c -1.308628,-0.01556 -2.560878,2.352773 -4.890668,6.986654 -7.05187,-7.755768 -7.41258,-7.849666 -9.84229,2.649966 -0.11364,0.04758 -0.22709,0.0959 -0.34055,0.144695 -8.88231,-5.324406 -9.34124,-5.366051 -8.66717,5.041551 -0.21569,0.159933 -0.43121,0.322088 -0.64596,0.486794 -9.102,-3.605578 -9.49555,-3.378386 -7.19232,6.611477 -0.10784,0.11671 -0.21599,0.23284 -0.3235,0.35089 -9.27685,-2.506375 -9.53641,-2.129764 -6.07663,7.65845 -0.14847,0.21295 -0.29578,0.42957 -0.44338,0.64544 -10.45618,-1.11775 -10.67098,-0.91353 -5.35523,8.828413 -0.026,0.0482 -0.0526,0.0943 -0.0786,0.14263 -4.28381,2.04782 -5.70197,4.54381 -7.73183,7.89409 -0.15756,6.64457 6.9544,12.37105 17.18035,18.87895 -3.51325,-6.5113 -9.00735,-9.81207 -10.0614,-17.88832 1.54367,-2.90538 4.16877,-3.90901 6.42286,-5.21622 24.61995,14.36815 50.615808,14.53471 76.550928,-0.55035 2.26015,1.31503 4.90084,2.31509 6.45076,5.23224 -1.05405,8.07624 -6.54866,11.3765 -10.06191,17.8878 10.22594,-6.5079 17.33842,-12.23387 17.18086,-18.87844 -1.97354,-3.25733 -3.37677,-5.706 -7.38973,-7.72149 5.01291,-9.218263 4.53571,-9.305023 -5.98567,-8.177293 -0.0891,-0.1152 -0.17795,-0.23186 -0.26717,-0.34623 3.63467,-10.261532 3.40665,-10.529692 -6.39186,-7.87136 2.47993,-10.705895 2.14854,-10.749554 -7.77938,-6.803718 0.74781,-11.285018 0.47993,-11.261581 -8.88835,-5.642548 -2.49815,-10.818768 -2.79293,-10.786576 -9.94048,-2.924887 -2.68846,-4.933638 -4.10296,-7.403383 -5.43173,-7.419184 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 75.334492,106.8255 c -0.51041,0.004 -0.85068,0.0544 -0.79478,0.0889 0,0 -9.13406,11.93611 0.31006,18.65881 a 9.7471106,8.2770874 37.793943 0 0 1.43712,9.42372 9.7471106,8.2770874 37.793943 0 0 10.56473,3.9672 l -3.56412,-8.60569 9.19685,0.73536 a 9.7471106,8.2770874 37.793943 0 0 -7.02645,-8.91057 9.7471106,8.2770874 37.793943 0 0 -7.00784,0.009 c -1.86231,-1.36401 -4.6287,-4.92596 -0.0408,-12.47521 1.51807,-2.49795 -1.54349,-2.90314 -3.07475,-2.89129 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="path5389" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="translate(-2.3193819,-7.5517449)"
|
||||
style="display:inline"
|
||||
inkscape:label="kani">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399" />
|
||||
<g
|
||||
id="g351">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 111.51646,83.878113 c -0.0644,2.604234 0.83829,5.245703 2.49515,7.301842 2.19739,2.716867 5.40747,4.034785 8.37885,3.439994 6.01625,8.488971 -0.30315,11.998681 -0.4866,12.038481 -1.32922,0.42046 0.0534,6.32365 4.60901,2.5271 7.11608,-5.93031 2.73673,-13.62732 0.0641,-17.143859 1.54476,-1.912559 2.20351,-4.57778 1.80861,-7.317326 -0.6031,-4.141273 -3.48425,-7.674191 -7.13223,-8.745669 l -1.25194,9.229861 -1.06142,-0.736985 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="arm-up"
|
||||
transform="matrix(1.0952772,0,0,1.0952772,-42.847275,-49.680439)">
|
||||
<set id="show_frame0" attributeName="visibility" attributeType="CSS" to="visible"
|
||||
begin="0ms; hide_frame1.end" dur="500ms" fill="freeze"/>
|
||||
<set id="hide_frame0" attributeName="visibility" attributeType="CSS" to="hidden"
|
||||
begin="show_frame0.end" dur="1ms" fill="freeze"/>
|
||||
</path>
|
||||
<path
|
||||
id="path294"
|
||||
d="m 136.84733,83.996879 c -2.18137,1.42401 -3.84498,3.66555 -4.59874,6.19631 -0.99138,3.35068 -0.25622,6.742 1.91889,8.85192 -3.57942,9.769591 -10.05414,6.555411 -10.19096,6.426891 -1.10017,-0.85629 -5.17794,3.63047 0.53268,5.22929 8.92019,2.49747 12.77572,-5.47478 14.1562,-9.67038 2.45132,0.18756 5.02004,-0.78148 7.05239,-2.660471 3.06875,-2.84546 4.34444,-7.22212 3.15795,-10.83433 l -8.31186,4.20365 0.005,-1.29218 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="arm-down"
|
||||
transform="matrix(1.0952772,0,0,1.0952772,-42.847275,-49.680439)" visibility="hidden">
|
||||
<set id="show_frame1" attributeName="visibility" attributeType="CSS" to="visible"
|
||||
begin="hide_frame0.end" dur="500ms" fill="freeze"/>
|
||||
<set id="hide_frame1" attributeName="visibility" attributeType="CSS" to="hidden"
|
||||
begin="show_frame1.end" dur="1ms" fill="freeze"/>
|
||||
</path>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 48 KiB |
|
@ -1,252 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 135.46667 135.46666"
|
||||
version="1.1"
|
||||
id="svg1084"
|
||||
sodipodi:docname="logo-square.svg"
|
||||
inkscape:version="1.2 (dc2aeda, 2022-05-15)"
|
||||
inkscape:export-filename="logo-180.png"
|
||||
inkscape:export-xdpi="33.75"
|
||||
inkscape:export-ydpi="33.75"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title332">Kanidm Square Logo</title>
|
||||
<sodipodi:namedview
|
||||
id="namedview39"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="234.5"
|
||||
inkscape:cy="304.5"
|
||||
inkscape:window-width="1389"
|
||||
inkscape:window-height="847"
|
||||
inkscape:window-x="51"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1084">
|
||||
<sodipodi:guide
|
||||
position="-52.916665,67.733332"
|
||||
orientation="0,1"
|
||||
id="guide145"
|
||||
inkscape:locked="false"
|
||||
inkscape:label="vertical_middle"
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="121.97292,175.15416"
|
||||
orientation="-1,0"
|
||||
id="guide777"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="13.49375,173.03749"
|
||||
orientation="-1,0"
|
||||
id="guide779"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="22.754166,121.97292"
|
||||
orientation="0,1"
|
||||
id="guide781"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
<sodipodi:guide
|
||||
position="4.4979168,13.758333"
|
||||
orientation="0,1"
|
||||
id="guide783"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,134,229)" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1081" />
|
||||
<metadata
|
||||
id="metadata330">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>Kanidm Square Logo</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<rect
|
||||
style="fill:#ffffff;stroke-width:0.243721"
|
||||
id="rect443"
|
||||
width="135.46666"
|
||||
height="135.46666"
|
||||
x="0"
|
||||
y="0"
|
||||
inkscape:label="background"
|
||||
sodipodi:insensitive="true" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="matrix(0.91407203,0,0,0.91407203,-34.121105,-24.362694)"
|
||||
inkscape:label="kani">
|
||||
<path
|
||||
id="path5404"
|
||||
d="m 62.537712,110.23377 c -3.36297,8.12708 5.78522,15.61876 5.82446,15.73981 -1.67096,-4.90156 -3.43697,-8.85836 -0.189,-12.28424"
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:#803300;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 138.4423,109.69923 c 3.36297,8.12708 -5.78522,15.61876 -5.82446,15.7398 1.67096,-4.90155 3.43697,-8.85835 0.189,-12.28423"
|
||||
id="path5408" />
|
||||
<path
|
||||
id="path4529"
|
||||
d="m 100.24698,67.21217 c -1.308628,-0.01556 -2.560878,2.352773 -4.890668,6.986654 -7.05187,-7.755768 -7.41258,-7.849666 -9.84229,2.649966 -0.11364,0.04758 -0.22709,0.0959 -0.34055,0.144695 -8.88231,-5.324406 -9.34124,-5.366051 -8.66717,5.041551 -0.21569,0.159933 -0.43121,0.322088 -0.64596,0.486794 -9.102,-3.605578 -9.49555,-3.378386 -7.19232,6.611477 -0.10784,0.11671 -0.21599,0.23284 -0.3235,0.35089 -9.27685,-2.506375 -9.53641,-2.129764 -6.07663,7.65845 -0.14847,0.21295 -0.29578,0.42957 -0.44338,0.64544 -10.45618,-1.11775 -10.67098,-0.91353 -5.35523,8.828413 -0.026,0.0482 -0.0526,0.0943 -0.0786,0.14263 -4.28381,2.04782 -5.70197,4.54381 -7.73183,7.89409 -0.15756,6.64457 6.9544,12.37105 17.18035,18.87895 -3.51325,-6.5113 -9.00735,-9.81207 -10.0614,-17.88832 1.54367,-2.90538 4.16877,-3.90901 6.42286,-5.21622 24.61995,14.36815 50.615808,14.53471 76.550928,-0.55035 2.26015,1.31503 4.90084,2.31509 6.45076,5.23224 -1.05405,8.07624 -6.54866,11.3765 -10.06191,17.8878 10.22594,-6.5079 17.33842,-12.23387 17.18086,-18.87844 -1.97354,-3.25733 -3.37677,-5.706 -7.38973,-7.72149 5.01291,-9.218263 4.53571,-9.305023 -5.98567,-8.177293 -0.0891,-0.1152 -0.17795,-0.23186 -0.26717,-0.34623 3.63467,-10.261532 3.40665,-10.529692 -6.39186,-7.87136 2.47993,-10.705895 2.14854,-10.749554 -7.77938,-6.803718 0.74781,-11.285018 0.47993,-11.261581 -8.88835,-5.642548 -2.49815,-10.818768 -2.79293,-10.786576 -9.94048,-2.924887 -2.68846,-4.933638 -4.10296,-7.403383 -5.43173,-7.419184 z"
|
||||
style="display:inline;fill:#ff6600;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<g
|
||||
id="g5758"
|
||||
transform="translate(-2.3193819,-7.5517449)"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="display:inline;fill:#d45500;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.808992,121.55238 c -0.682767,-0.0559 4.468828,10.17565 8.051908,0.17277 0.24133,-0.67372 -3.69223,2.90976 -8.051908,-0.17277 z"
|
||||
id="path5399" />
|
||||
<g
|
||||
id="g351">
|
||||
<path
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 93.212672,111.5632 c -5.131386,10.99206 5.618332,14.73472 4.412511,4.11951 -0.319289,-3.2881 -2.328089,-7.17448 -4.412511,-4.11951 z"
|
||||
id="path5415" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.394393,112.41429 c -1.183441,1.51896 -0.08172,3.83605 -0.09872,3.98526 1.674403,1.64132 1.61267,-4.77034 0.09872,-3.98526 z"
|
||||
id="path5417" />
|
||||
</g>
|
||||
<g
|
||||
id="g355">
|
||||
<path
|
||||
id="path5433"
|
||||
d="m 109.6169,111.5632 c -5.13141,10.99206 5.61836,14.73472 4.41254,4.11951 -0.31929,-3.2881 -2.3281,-7.17448 -4.41254,-4.11951 z"
|
||||
style="fill:#000000;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435"
|
||||
d="m 111.79864,112.41429 c -1.18345,1.51896 -0.0817,3.83605 -0.0987,3.98526 1.67441,1.64132 1.61267,-4.77034 0.0987,-3.98526 z"
|
||||
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path5389"
|
||||
d="m 75.334492,106.8255 c -0.51041,0.004 -0.85068,0.0544 -0.79478,0.0889 0,0 -9.13406,11.93611 0.31006,18.65881 a 9.7471106,8.2770874 37.793943 0 0 1.43712,9.42372 9.7471106,8.2770874 37.793943 0 0 10.56473,3.9672 l -3.56412,-8.60569 9.19685,0.73536 a 9.7471106,8.2770874 37.793943 0 0 -7.02645,-8.91057 9.7471106,8.2770874 37.793943 0 0 -7.00784,0.009 c -1.86231,-1.36401 -4.6287,-4.92596 -0.0408,-12.47521 1.51807,-2.49795 -1.54349,-2.90314 -3.07475,-2.89129 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<g
|
||||
transform="translate(-12.063571,-65.570169)"
|
||||
id="g5751"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 142.55119,137.92594 27.3632,-15.27364 21.39613,38.33184 -27.36321,15.27364 z"
|
||||
id="path5730" />
|
||||
<path
|
||||
id="path5734"
|
||||
d="m 142.55119,137.92594 27.3632,-15.27364 21.39613,38.33184 -27.36321,15.27364 -6.27068,-11.23547 c 3.50932,-3.1137 4.19635,-7.01138 3.17635,-11.38324 l -7.39141,3.83317 z"
|
||||
style="display:inline;opacity:1;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<g
|
||||
id="g1027"
|
||||
transform="matrix(0.86024749,-0.10202883,0.10202883,0.86024749,30.096406,71.933538)"
|
||||
style="display:inline">
|
||||
<path
|
||||
id="path4529-1"
|
||||
d="m 142.60294,99.070411 c -0.25799,0.104739 -0.3086,0.672471 -0.384,1.773409 -2.02218,-0.940695 -2.10067,-0.929408 -1.71256,1.33048 -0.0183,0.0187 -0.0366,0.0375 -0.0549,0.0564 -2.18101,-0.31296 -2.27447,-0.28333 -1.28505,1.70286 -0.0291,0.0491 -0.0581,0.0987 -0.0866,0.1487 -2.08254,0.0423 -2.14104,0.11931 -0.86643,1.88938 -0.0116,0.0318 -0.0232,0.0635 -0.0346,0.0955 -2.02632,0.27237 -2.04621,0.36762 -0.56133,2.00288 -0.0116,0.054 -0.0226,0.10863 -0.0338,0.16313 -2.1433,0.64191 -2.16862,0.69967 -0.32345,2.17298 -0.001,0.0115 -0.002,0.0228 -0.004,0.0345 -0.67172,0.75455 -0.74436,1.361 -0.86664,2.18542 0.51637,1.31647 2.38318,1.85412 4.92525,2.2886 -1.22549,-0.98801 -2.57514,-1.18304 -3.44709,-2.68058 0.0635,-0.6971 0.49586,-1.1102 0.83039,-1.55228 6.0132,0.79095 11.12666,-1.31742 14.97206,-6.41277 0.55169,0.0718 1.1521,0.0505 1.69641,0.49515 0.45839,1.67116 -0.34771,2.77114 -0.50064,4.33785 1.47008,-2.11891 2.39377,-3.82799 1.81562,-5.11852 -0.65544,-0.47646 -1.13239,-0.84126 -2.08564,-0.90614 0.2242,-2.22125 0.12343,-2.19897 -1.84772,-1.11119 -0.027,-0.0153 -0.054,-0.0308 -0.081,-0.0459 -0.13212,-2.312418 -0.19894,-2.346242 -1.90222,-1.01773 -0.39525,-2.304482 -0.46385,-2.285755 -2.08647,-0.69401 -0.78276,-2.275429 -0.83337,-2.248771 -2.2084,-0.374874 -1.38113,-1.916624 -1.4363,-1.886031 -2.19098,0.244914 -0.93375,-0.746434 -1.41465,-1.114437 -1.67661,-1.008099 z"
|
||||
style="fill:#2a3455;fill-opacity:1;stroke:#cccccc;stroke-width:0.212762;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5389-8"
|
||||
d="m 140.97831,108.89338 c -0.0997,0.0432 -0.1624,0.0807 -0.1486,0.0829 0,0 -0.80881,3.09385 1.59758,3.63486 a 2.0738233,1.7610569 15.019669 0 0 1.05807,1.73034 2.0738233,1.7610569 15.019669 0 0 2.39928,-0.0919 l -1.40796,-1.39467 1.86476,-0.61321 a 2.0738233,1.7610569 15.019669 0 0 -2.1123,-1.16933 2.0738233,1.7610569 15.019669 0 0 -1.37407,0.57883 c -0.47768,-0.11421 -1.31374,-0.58513 -1.03548,-2.44396 0.0921,-0.61507 -0.54189,-0.4424 -0.84131,-0.31396 z"
|
||||
style="fill:#2a3455;fill-opacity:1;stroke:#cccccc;stroke-width:0.212762;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5732-7"
|
||||
d="m 151.16542,99.348723 c -0.31065,0.459014 -0.45239,1.035767 -0.39183,1.594317 0.0815,0.73897 0.505,1.34373 1.10549,1.57849 0.10244,2.21135 -1.43246,2.11407 -1.46989,2.10013 -0.28634,-0.0774 -0.71677,1.13867 0.53519,0.98198 1.95562,-0.24473 2.05537,-2.12623 1.98064,-3.063 0.49633,-0.1651 0.92044,-0.56676 1.16438,-1.10276 0.36766,-0.81095 0.25745,-1.774612 -0.27281,-2.385521 l -1.28437,1.509221 -0.10531,-0.25395 z"
|
||||
style="fill:#2a3455;fill-opacity:1;stroke:#cccccc;stroke-width:0.212762;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#b1b3b8;fill-opacity:1;stroke:#b1b3b8;stroke-width:0.165543;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 157.03788,77.939189 c -0.10179,0.05 1.49878,1.067004 1.15909,-0.658823 -0.0229,-0.116239 -0.27783,0.726935 -1.15909,0.658823 z"
|
||||
id="path5399-5"
|
||||
transform="matrix(1.1463308,0.13595947,-0.13595947,1.1463308,-22.801274,-2.4500009)" />
|
||||
<g
|
||||
id="g364"
|
||||
transform="matrix(1.1463308,0.13595947,-0.13595947,1.1463308,-22.801274,-2.4500009)">
|
||||
<path
|
||||
style="fill:#b1b3b8;fill-opacity:1;stroke:#b1b3b8;stroke-width:0.0438px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 155.39466,76.994381 c 0.20359,1.997829 2.04911,1.617431 0.97679,0.211015 -0.32445,-0.440244 -0.93981,-0.822131 -0.97679,-0.211015 z"
|
||||
id="path5415-5" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.0438px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 155.77699,76.930181 c -0.0393,0.316333 0.31396,0.552158 0.32421,0.574809 0.37728,0.09117 -0.17566,-0.814887 -0.32421,-0.574809 z"
|
||||
id="path5417-5" />
|
||||
</g>
|
||||
<g
|
||||
id="g374"
|
||||
transform="matrix(1.1463308,0.13595947,-0.13595947,1.1463308,-22.801274,-2.4500009)">
|
||||
<path
|
||||
id="path5433-8"
|
||||
d="m 157.72622,75.602125 c 0.20358,1.997831 2.04911,1.617429 0.97679,0.211012 -0.32445,-0.440244 -0.93981,-0.82213 -0.97679,-0.211012 z"
|
||||
style="fill:#b1b3b8;fill-opacity:1;stroke:#b1b3b8;stroke-width:0.0438px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5435-2"
|
||||
d="m 158.10855,75.537924 c -0.0393,0.316333 0.31396,0.552158 0.32421,0.574808 0.37728,0.09117 -0.17566,-0.814886 -0.32421,-0.574808 z"
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.0438px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:1.71585px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0428963"
|
||||
x="94.641426"
|
||||
y="157.04494"
|
||||
id="text167"
|
||||
transform="rotate(-28.988077,144.6719,16.286147)"><tspan
|
||||
id="tspan165"
|
||||
x="94.641426"
|
||||
y="157.04494"
|
||||
style="fill:#cccccc;stroke-width:0.0428963">PASSPORT</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:2.03519px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0508798"
|
||||
x="92.063805"
|
||||
y="154.54707"
|
||||
id="text163"
|
||||
transform="rotate(-29.037466,144.42409,16.321288)"><tspan
|
||||
id="tspan161"
|
||||
x="92.063805"
|
||||
y="154.54707"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'.PingFang SC';-inkscape-font-specification:'.PingFang SC';fill:#cccccc;stroke-width:0.0508798">AUTHSTRALIA</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:2.70471px;line-height:1.25;font-family:sans-serif;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.0676183"
|
||||
x="93.162766"
|
||||
y="128.62389"
|
||||
id="text1127"
|
||||
transform="rotate(-29.176231,143.73222,16.419399)"><tspan
|
||||
id="tspan1125"
|
||||
x="93.162766"
|
||||
y="128.62389"
|
||||
style="fill:#cccccc;stroke-width:0.0676183">KANIDM</tspan></text>
|
||||
</g>
|
||||
<path
|
||||
d="m 145.61485,98.730679 c 3.50932,-3.1137 4.19635,-7.01138 3.17635,-11.38324 l -7.3914,3.83317 z"
|
||||
style="display:inline;fill:#2a3455;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path523" />
|
||||
<path
|
||||
id="path5732"
|
||||
d="m 136.84733,83.996879 c -2.18137,1.42401 -3.84498,3.66555 -4.59874,6.19631 -0.99138,3.35068 -0.25622,6.742 1.91889,8.85192 -3.57942,9.769591 -10.05414,6.555411 -10.19096,6.426891 -1.10017,-0.85629 -5.17794,3.63047 0.53268,5.22929 8.92019,2.49747 12.77572,-5.47478 14.1562,-9.67038 2.45132,0.18756 5.02004,-0.78148 7.05239,-2.660471 3.06875,-2.84546 4.34444,-7.22212 3.15795,-10.83433 l -8.31186,4.20365 0.005,-1.29218 z"
|
||||
style="display:inline;fill:#ff6600;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 16 KiB |