init commit

This commit is contained in:
Martin Drechsel
2025-04-02 18:54:55 +02:00
commit 2c5ec6b281
126 changed files with 21323 additions and 0 deletions

27
src/app.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<div>
<NuxtLayout :data-theme="currentTheme">
<NuxtPage />
<NuxtSnackbar />
</NuxtLayout>
</div>
</template>
<script setup lang="ts">
const { currentTheme } = storeToRefs(useUiStore());
</script>
<style>
.fade-enter-active {
transition: all 1s ease-out;
}
.fade-leave-active {
transition: all 1s ease-out reverse;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@ -0,0 +1,155 @@
<template>
<div class="browser">
<div class="browser-controls">
<button
@click="$emit('goBack', activeTabId)"
:disabled="!activeTabId"
>
</button>
<button
@click="$emit('goForward', activeTabId)"
:disabled="!activeTabId"
>
</button>
<button @click="$emit('createTab')">+</button>
<HaexBrowserUrlBar
:url="activeTab?.url || ''"
:isLoading="activeTab?.isLoading || false"
@submit="handleUrlSubmit"
/>
</div>
<HaexBrowserTabBar
:tabs="tabs"
:activeTabId="activeTabId"
@closeTab="$emit('closeTab', $event)"
@activateTab="$emit('activateTab', $event)"
/>
<div
class="browser-content"
ref="contentRef"
>
<!-- Die eigentlichen Webview-Inhalte werden von Tauri verwaltet -->
<div
v-if="!activeTabId"
class="empty-state"
>
<p>
Kein Tab geöffnet. Erstellen Sie einen neuen Tab mit dem + Button.
</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { Window } from '@tauri-apps/api/window';
import { getCurrentWebview, Webview } from '@tauri-apps/api/webview';
/* const appWindow = new Window('uniqueLabel');
const webview = new Webview(appWindow, 'theUniqueLabel', {
url: 'https://www.google.de',
x: 0,
y: 0,
height: 1000,
width: 1000,
});
webview.once('tauri://created', function () {
console.log('create new webview');
}); */
interface Tab {
id: string;
title: string;
url: string;
isLoading: boolean;
isActive: boolean;
window_label: string;
}
interface Props {
tabs: Tab[];
activeTabId: string | null;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: 'createTab'): void;
(e: 'closeTab', tabId: string): void;
(e: 'navigate', tabId: string, url: string): void;
(e: 'goBack', tabId: string | null): void;
(e: 'goForward', tabId: string | null): void;
(e: 'activateTab', tabId: string | null): void;
}>();
const { initializeAsync, processNavigation, injectContentScripts } =
useBrowserExtensionStore();
const contentRef = ref<HTMLDivElement | null>(null);
//const extensionManager = ref<ExtensionManager>(new ExtensionManager());
const activeTab = computed(() =>
props.tabs?.find((tab) => tab.id === props.activeTabId)
);
onMounted(async () => {
// Initialisiere das Erweiterungssystem
await initializeAsync();
// Aktualisiere die Webview-Größe
await updateWebviewBoundsAsync();
//window.addEventListener('resize', updateWebviewBounds);
});
// Wenn ein neuer Tab aktiviert wird, injiziere Content-Scripts
/* watch(
() => props.activeTabId,
async (newTabId) => {
if (newTabId && props.tabs.length > 0) {
const activeTab = props.tabs.find((tab) => tab.id === newTabId);
if (activeTab) {
// Warte kurz, bis die Seite geladen ist
setTimeout(() => {
injectContentScripts(activeTab.window_label);
}, 500);
// Aktualisiere die Webview-Größe
updateWebviewBounds();
}
}
}
); */
const handleUrlSubmit = (url: string) => {
if (props.activeTabId) {
// Prüfe URL mit Erweiterungen vor der Navigation
if (processNavigation(url)) {
emit('navigate', props.activeTabId, url);
} else {
console.log('Navigation blockiert durch Erweiterung');
// Hier könnten Sie eine Benachrichtigung anzeigen
}
}
};
const updateWebviewBoundsAsync = async () => {
if (!contentRef.value) return;
const rect = contentRef.value.getBoundingClientRect();
const bounds = {
x: rect.left,
y: rect.top,
width: rect.width,
height: rect.height,
};
/* await invoke('update_window_bounds', {
contentBounds: { x: bounds.x, y: bounds.y },
contentSize: { width: bounds.width, height: bounds.height },
}); */
};
</script>

View File

@ -0,0 +1,43 @@
<template>
<div class="tab-bar">
<div
v-for="tab in tabs"
:key="tab.id"
class="tab"
:class="{ active: tab.id === activeTabId }"
@click="$emit('activateTab', tab.id)"
>
<span class="tab-title">
{{ tab.title || 'Neuer Tab' }}
</span>
<button
class="tab-close"
@click.stop="$emit('closeTab', tab.id)"
>
×
</button>
</div>
</div>
</template>
<script setup lang="ts">
interface Tab {
id: string;
title: string;
url: string;
isLoading: boolean;
isActive: boolean;
}
interface Props {
tabs: Tab[];
activeTabId: string | null;
}
defineProps<Props>();
defineEmits<{
(e: 'closeTab', tabId: string): void;
(e: 'activateTab', tabId: string): void;
}>();
</script>

View File

@ -0,0 +1,57 @@
<template>
<form
class="url-bar"
@submit.prevent="handleSubmit"
>
<input
type="text"
v-model="inputValue"
placeholder="URL eingeben"
/>
<span
v-if="isLoading"
class="loading-indicator"
>Laden...</span
>
<button
v-else
type="submit"
>
Go
</button>
</form>
</template>
<script setup lang="ts">
const props = defineProps({
url: {
type: String,
default: '',
},
isLoading: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['submit']);
const inputValue = ref(props.url);
watch(
() => props.url,
(newUrl) => {
inputValue.value = newUrl;
}
);
const handleSubmit = () => {
// URL validieren und ggf. Protokoll hinzufügen
let processedUrl = inputValue.value.trim();
if (processedUrl && !processedUrl.match(/^[a-zA-Z]+:\/\//)) {
processedUrl = 'https://' + processedUrl;
}
emit('submit', processedUrl);
};
</script>

View File

@ -0,0 +1,79 @@
<template>
<div class="fixed z-10">
<div
class="dropdown relative inline-flex [--placement:top] [--strategy:absolute]"
>
<button
:id
class="dropdown-toggle btn btn-primary btn-lg btn-square dropdown-open:rotate-45"
aria-haspopup="menu"
aria-expanded="false"
aria-label="Menu"
>
<Icon
:name="icon"
size="46"
/>
</button>
<div
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60 rtl:left-0 bg-transparent"
role="menu"
aria-orientation="vertical"
:aria-labelledby="id"
>
<ul
class="dropdown-open:ease-in dropdown-open:translate-x-0 -translate-x-1 rtl:translate-x-1 transition duration-300 ease-out"
data-dropdown-transition
>
<li
v-for="link in menu"
class="dropdown-item hover:bg-transparent"
>
<NuxtLinkLocale
v-if="link.to"
:to="link.to"
class="btn btn-primary flex items-center no-underline rounded-lg flex-nowrap"
>
<Icon
v-if="link.icon"
:name="link.icon"
class="me-3"
/>
{{ link.label }}
</NuxtLinkLocale>
<button
v-else
@click="link.action"
class="link hover:link-primary flex items-center no-underline w-full"
>
<Icon
v-if="link.icon"
:name="link.icon"
class="me-3"
/>
{{ link.label }}
</button>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { IActionMenuItem } from './types';
defineProps({
menu: {
type: Array as PropType<IActionMenuItem[]>,
},
icon: {
type: String,
default: 'mdi:plus',
},
});
const id = useId();
</script>

View File

@ -0,0 +1,25 @@
<template>
<button
class="btn join-item"
:class="{
'btn-sm':
currentScreenSize === 'sm' ||
currentScreenSize === '' ||
currentScreenSize === 'xs',
}"
:type
>
<slot />
</button>
</template>
<script setup lang="ts">
const { currentScreenSize } = storeToRefs(useUiStore());
defineProps({
type: {
type: String as PropType<'reset' | 'submit' | 'button'>,
default: 'button',
},
});
</script>

8
src/components/ui/button/types.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import type { RouteLocationRaw } from 'vue-router';
export interface IActionMenuItem {
label: string;
icon?: string;
action?: () => Promise<unknown>;
to?: RouteLocationRaw;
}

View File

@ -0,0 +1,121 @@
<template>
<slot
name="trigger"
:id
>
</slot>
<div
:id
class="overlay modal overlay-open:opacity-100 hidden modal-middle [--tab-accessibility-limited:false] overflow-scroll p-0 sm:p-4"
role="dialog"
ref="modalRef"
>
<div
class="overlay-animation-target overlay-open:mt-4 overlay-open:duration-500 mt-12 transition-all ease-out modal-dialog overlay-open:opacity-100"
>
<div class="modal-content">
<div class="modal-header">
<slot name="title">
<h3
v-if="title"
class="modal-title text-base sm:text-lg"
>
{{ title }}
</h3>
</slot>
<button
type="button"
class="btn btn-text btn-circle btn-sm absolute end-3 top-3"
:aria-label="t('close')"
@click="open = false"
tabindex="1"
>
<Icon
name="mdi:close"
size="18"
/>
</button>
</div>
<div class="modal-body text-sm sm:text-base py-1">
<slot />
</div>
<div class="modal-footer flex-wrap">
<slot name="buttons" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { HSOverlay } from 'flyonui/flyonui';
export interface IDom {
class?: String;
text: String;
}
const id = useId();
defineProps({
trigger: {
type: Object as PropType<IDom>,
default: () => ({
class: '',
text: '',
}),
},
title: {
type: String,
default: '',
},
description: {
type: Object as PropType<IDom>,
default: () => ({
class: '',
text: '',
}),
required: false,
},
});
const open = defineModel<boolean>('open', { default: false });
const { t } = useI18n();
const modalRef = useTemplateRef('modalRef');
const modal = ref<HSOverlay>();
watch(open, async () => {
if (open.value) {
//console.log('open modal', modal.value?.open);
await modal.value?.open();
} else {
await modal.value?.close(true);
}
});
onMounted(() => {
if (!modalRef.value) return;
modal.value = new HSOverlay(modalRef.value, { isClosePrev: true });
modal.value.on('close', () => {
console.log('close it from event', open.value);
open.value = false;
});
});
</script>
<i18n lang="json">
{
"de": {
"close": "Schließen"
},
"en": {
"close": "Close"
}
}
</i18n>

View File

@ -0,0 +1,58 @@
<template>
<button
type="button"
class="btn btn-primary"
aria-haspopup="dialog"
aria-expanded="false"
aria-controls="basic-modal"
data-overlay="#basic-modal"
>
Open modal
</button>
<div
id="basic-modal"
class="overlay modal overlay-open:opacity-100 hidden"
role="dialog"
tabindex="-1"
>
<div class="modal-dialog overlay-open:opacity-100">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Dialog Title</h3>
<button
type="button"
class="btn btn-text btn-circle btn-sm absolute end-3 top-3"
aria-label="Close"
data-overlay="#basic-modal"
>
<span class="icon-[tabler--x] size-4"></span>
</button>
</div>
<div class="modal-body">
This is some placeholder content to show the scrolling behavior for
modals. Instead of repeating the text in the modal, we use an inline
style to set a minimum height, thereby extending the length of the
overall modal and demonstrating the overflow scrolling. When content
becomes longer than the height of the viewport, scrolling will move
the modal as needed.
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-soft btn-secondary"
data-overlay="#basic-modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
>
Save changes
</button>
</div>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,5 @@
<template>
<h3 class="modal-title">
<slot />
</h3>
</template>

View File

@ -0,0 +1,199 @@
<template>
<span>
<fieldset class="join w-full">
<slot name="prepend" />
<span class="input-group join-item">
<span
v-if="prependIcon || prependLabel"
class="input-group-text"
>
<label v-if="prependLabel">
{{ prependLabel }}
</label>
<Icon :name="prependIcon" />
</span>
<div class="relative w-full">
<input
:id
:name="name ?? id"
:placeholder="placeholder || label"
:type
:autofocus
class="input input-floating peer join-item"
:class="{
'input-sm':
currentScreenSize === 'sm' ||
currentScreenSize === '' ||
currentScreenSize === 'xs',
}"
v-bind="$attrs"
v-model="input"
ref="inputRef"
:readonly="read_only"
/>
<label
v-if="label"
:for="id"
class="input-floating-label"
>
{{ label }}
</label>
</div>
<span
v-if="appendIcon || appendLabel"
class="input-group-text"
>
<label
v-if="appendLabel"
class=""
>
{{ appendLabel }}
</label>
<Icon :name="appendIcon" />
</span>
</span>
<slot name="append" />
<UiButton
v-if="withCopyButton"
class="btn-outline btn-accent h-auto"
@click="copy(`${input}`)"
>
<Icon :name="copied ? 'mdi:check' : 'mdi:content-copy'" />
</UiButton>
<!-- <button
v-if="withCopyButton"
class="btn btn-outline btn-accent join-item h-auto"
:class="{
'btn-sm':
currentScreenSize === 'sm' ||
currentScreenSize === '' ||
currentScreenSize === 'xs',
}"
@click="copy(`${input}`)"
type="button"
>
<Icon :name="copied ? 'mdi:check' : 'mdi:content-copy'" />
</button> -->
</fieldset>
<span
class="flex flex-col px-2 pt-0.5"
v-show="errors"
>
<span
v-for="error in errors"
class="label-text-alt text-error"
>
{{ error }}
</span>
</span>
</span>
</template>
<script setup lang="ts">
import { type ZodSchema } from 'zod';
const inputRef = useTemplateRef('inputRef');
defineExpose({ inputRef });
defineOptions({
inheritAttrs: false,
});
const props = defineProps({
placeholder: {
type: String,
default: '',
},
type: {
type: String as PropType<
| 'button'
| 'checkbox'
| 'color'
| 'date'
| 'datetime-local'
| 'email'
| 'file'
| 'hidden'
| 'image'
| 'month'
| 'number'
| 'password'
| 'radio'
| 'range'
| 'reset'
| 'search'
| 'submit'
| 'tel'
| 'text'
| 'time'
| 'url'
| 'week'
>,
default: 'text',
},
label: String,
name: String,
prependIcon: {
type: String,
default: '',
},
prependLabel: String,
appendIcon: {
type: String,
default: '',
},
appendLabel: String,
rules: Object as PropType<ZodSchema>,
checkInput: Boolean,
withCopyButton: Boolean,
autofocus: Boolean,
read_only: Boolean,
});
const input = defineModel<string | number | undefined | null>({
default: '',
required: true,
});
const { currentScreenSize } = storeToRefs(useUiStore());
onMounted(() => {
if (props.autofocus && inputRef.value) inputRef.value.focus();
});
const errors = defineModel<string[] | undefined>('errors');
const id = useId();
watch(input, () => checkInput());
watch(
() => props.checkInput,
() => {
checkInput();
}
);
const emit = defineEmits(['error']);
const checkInput = () => {
if (props.rules) {
const result = props.rules.safeParse(input.value);
//console.log('check result', result.error, props.rules);
if (!result.success) {
errors.value = result.error.errors.map((error) => error.message);
emit('error', errors.value);
} else {
errors.value = [];
}
}
};
const { copy, copied } = useClipboard();
</script>

View File

@ -0,0 +1,54 @@
<template>
<UiInput
:check-input
:label="label || t('password')"
:placeholder="placeholder || t('password')"
:rules
:type="type"
:autofocus
v-model="value"
>
<template #append>
<UiButton
class="btn-outline btn-accent h-auto"
@click="tooglePasswordType"
>
<Icon :name="type === 'password' ? 'mdi:eye' : 'mdi:eye-off'" />
</UiButton>
</template>
</UiInput>
</template>
<script setup lang="ts">
import type { ZodSchema } from 'zod';
const { t } = useI18n();
const { currentScreenSize } = storeToRefs(useUiStore());
const value = defineModel<string | number | null | undefined>();
defineProps({
label: String,
placeholder: String,
checkInput: Boolean,
rules: Object as PropType<ZodSchema>,
autofocus: Boolean,
});
const type = ref<'password' | 'text'>('password');
const tooglePasswordType = () => {
type.value = type.value === 'password' ? 'text' : 'password';
};
</script>
<i18n lang="json">
{
"de": {
"password": "Passwort"
},
"en": {
"password": "Password"
}
}
</i18n>

View File

@ -0,0 +1,56 @@
<template>
<UiInput
:autofocus
:check-input="checkInput"
:label="label || t('url')"
:placeholder="placeholder || t('url')"
:read_only
:rules
:with-copy-button
v-model.trim="value"
>
<template #append>
<UiButton
v-if="read_only"
@click="openUrl(`${value}`)"
class="btn-outline btn-accent h-auto"
:class="{
disabled: !value?.length,
}"
>
<Icon name="streamline:web" />
</UiButton>
</template>
</UiInput>
</template>
<script setup lang="ts">
import type { ZodSchema } from 'zod';
import { openUrl } from '@tauri-apps/plugin-opener';
const { t } = useI18n();
const { currentScreenSize } = storeToRefs(useUiStore());
const value = defineModel<string | null | undefined>();
defineProps({
label: String,
placeholder: String,
checkInput: Boolean,
rules: Object as PropType<ZodSchema>,
autofocus: Boolean,
withCopyButton: Boolean,
read_only: Boolean,
});
</script>
<i18n lang="json">
{
"de": {
"url": "Url"
},
"en": {
"url": "Url"
}
}
</i18n>

View File

@ -0,0 +1,91 @@
<template>
<svg
id="logo"
class="fill-current stroke-current w-[160px]"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 286.3 85"
xml:space="preserve"
>
<switch>
<g>
<g class="logo-imagesss">
<circle
fill="white"
cx="42.5"
cy="42.5"
r="40"
></circle>
<path
d="M42.3,83.4c-22.6,0-40.9-18.4-40.9-40.9c0-22.6,18.4-40.9,40.9-40.9c22.6,0,40.9,18.4,40.9,40.9
C83.3,65.1,64.9,83.4,42.3,83.4z M42.3,5.8C22.1,5.8,5.7,22.3,5.7,42.5s16.5,36.7,36.7,36.7S79,62.7,79,42.5S62.6,5.8,42.3,5.8z
"
></path>
<g>
<g>
<polygon
points="38.8,69.8 38.8,31.7 22.3,31.7 22.3,38.5 29.8,38.5 29.8,69.8 "
></polygon>
<path
d="M34.1,13.2c-3.3,0-6,2.6-6,5.9c0,3.3,2.6,6,5.9,6c3.3,0,6-2.6,6-6
C39.9,15.9,37.3,13.2,34.1,13.2z"
></path>
</g>
<g>
<polygon
points="45.9,69.8 45.9,31.7 62.4,31.7 62.4,38.5 54.9,38.5 54.9,69.8 "
></polygon>
<path
d="M50.6,13.2c3.3,0,6,2.6,6,5.9c0,3.3-2.6,6-5.9,6c-3.3,0-6-2.6-6-6
C44.8,15.9,47.4,13.2,50.6,13.2z"
></path>
</g>
</g>
</g>
<g class="logo-textsss">
<path
d="M136.1,63.6c-4,0-5.3-2.6-5.3-6V38.5h10.6v-6.7h-10.6v-6.7h-9c0,7,0,29.1,0,32.7
c0,4.2,1.6,7.5,3.8,9.7c2.3,2.2,5.6,3.3,9.8,3.3c5.1,0,8.4-1.8,10.6-4.2l-4.7-6C140.2,62.1,138.5,63.6,136.1,63.6z"
></path>
<path
d="M217.7,30.7c-4.9,0-8.2,1.6-10.4,3.8c-2.2-2.2-5.5-3.8-10.4-3.8c-15,0-14.9,12.1-14.9,15
s0,24.1,0,24.1h9V45.7c0-8.5,4.9-8.3,5.9-8.3c1,0,5.9-0.3,5.9,8.3v24.1h0h9h0V45.7c0-8.5,4.9-8.3,5.9-8.3c1,0,5.9-0.3,5.9,8.3
v24.1h9c0,0,0-21.2,0-24.1C232.6,42.8,232.7,30.7,217.7,30.7z"
></path>
<path
d="M273.2,46.4c-4.3-1.4-6-2.5-6-5.2c0-2,1.1-3.8,4.3-3.8c3.2,0,4.5,3.3,5.1,4.8
c2.7-1.5,5.3-2.9,6.6-3.6c-2.5-6-6.3-7.9-12-7.9c-8,0-11.7,5.5-11.7,10.6c0,6.5,2.9,9.8,11.2,12.2c6,1.8,6.5,4.7,6.2,6.2
c-0.3,1.7-1.6,3.6-5.3,3.6c-3.6,0-5.8-3.8-6.8-5.4c-1.8,1.1-3.4,2.1-6.4,3.8c2.1,5,6.8,9.1,13.5,9.1c7.9,0,12.9-5.1,12.9-12.1
C284.9,51,279.6,48.5,273.2,46.4z"
></path>
<g>
<polygon
points="239.7,69.8 239.7,31.7 256.2,31.7 256.2,38.5 248.7,38.5 248.7,69.8 "
></polygon>
<path
d="M244.4,13.2c3.3,0,6,2.6,6,5.9c0,3.3-2.6,6-5.9,6c-3.3,0-6-2.6-6-6
C238.6,15.9,241.2,13.2,244.4,13.2z"
></path>
</g>
<g>
<polygon
points="114.7,69.8 114.7,31.7 98.1,31.7 98.1,38.5 105.7,38.5 105.7,69.8 "
></polygon>
<path
d="M110,13.2c-3.3,0-6,2.6-6,5.9c0,3.3,2.6,6,5.9,6c3.3,0,6-2.6,6-6C115.8,15.9,113.2,13.2,110,13.2
z"
></path>
</g>
<path
d="M176.4,52.4v-3.7c0-12.3-4.7-18-14.8-18c-9.3,0-14.7,6.6-14.7,18v4c0,11.5,5.8,18.2,15.8,18.2
c6.6,0,10.8-3.7,12.7-7.9c-2.2-1.4-4.6-2.8-6.1-3.8c-1,1.7-2.9,4.4-6.7,4.4c-5.8,0-7-5.9-7-10.9v-0.2H176.4z M155.7,45.7
c0.2-7.1,3.3-8.2,6-8.2c2.6,0,5.9,1,6,8.2H155.7z"
></path>
</g>
</g>
</switch>
</svg>
</template>

View File

@ -0,0 +1,24 @@
<template>
<UiTooltip
:tooltip="tooltip ?? label"
direction="right-end"
>
<button
class="link flex items-center justify-center py-3 hover:text-primary tooltip-toogle bg w-full"
@click="$emit('click')"
>
<Icon
:name="icon"
class="size-8"
/>
</button>
</UiTooltip>
</template>
<script setup lang="ts">
defineProps<{
label: string;
tooltip?: string;
icon: string;
}>();
</script>

View File

@ -0,0 +1,109 @@
<template>
<aside
class="flex shrink-0 transition-[width] ease-in duration-300 z-30 h-full overflow-hidden fixed sm:relative left-0 shadow border-r border-base-300"
>
<div class="sm:flex flex-col w-14 bg-base-200 shrink-0 h-full hidden">
<img
src="/logo.svg"
class="bg-primary p-3 size-16"
/>
<div class="flex flex-col justify-between h-full overflow-y-scroll z-10">
<div class="flex flex-col space-y-2 text-base-content/90">
<template v-for="item in menu.top">
<UiSidebarLink
v-if="item.to"
:to="item.to ?? ''"
:icon="item.icon"
:label="$t(item.label)"
/>
<UiSidebarButton
v-else
:icon="item.icon"
:label="$t(item.label)"
@click="item.click"
/>
</template>
</div>
<div class="flex flex-col space-y-2 text-base-content/90">
<template v-for="item in menu.bottom">
<UiSidebarLink
v-if="item.to"
:to="item.to ?? ''"
:icon="item.icon"
:label="$t(item.label)"
/>
<UiSidebarButton
v-else
:icon="item.icon"
:label="$t(item.label)"
@click="item.click"
/>
</template>
<!-- <UiSidebarLink
v-for="item in menu.bottom"
:icon="item.icon"
:to="item.to ?? ''"
:label="item.label"
@click="item.click"
/> -->
</div>
</div>
</div>
<!-- <div class="bg-base-100 flex flex-col w-full overflow-clip">
<div
class="h-16 flex items-center sm:justify-center justify-end md:justify-start bg-base-300 shrink-0"
>
<button
class="top-3 left-2 absolute z-30 duration-1000 btn btn-square btn-primary transition-opacity btn-outline sm:hidden"
@click="show = !show"
>
<Icon
name="mdi:menu"
size="28"
/>
</button>
<span
class="px-4 font-semibold text-base-content shrink-0 sm:bg-transparent bg-primary h-full flex items-center rounded-l-lg"
>
<p>Haex Vault</p>
</span>
<img
src="/logo.svg"
class="bg-primary p-3 size-16 shrink-0 sm:hidden rounded-r-lg"
/>
<button
class="btn btn-square btn-primary btn-outline mr-2 ml-auto hidden sm:flex"
@click="show = false"
>
<Icon
name="mdi:close"
size="28"
/>
</button>
</div>
<div class="overflow-scroll flex pb-4 relative">
<slot />
</div>
</div> -->
</aside>
</template>
<script lang="ts" setup>
defineProps({
menu: {
type: Object as PropType<ISidebarMenu>,
default: () => {},
},
});
//const show = ref(true);
const { show } = storeToRefs(useSidebarStore());
</script>

View File

@ -0,0 +1,61 @@
<template>
<li
@click="triggerNavigate"
class="hover:text-primary"
>
<UiTooltip
:tooltip="tooltip ?? name"
direction="right-end"
>
<NuxtLinkLocale
:class="{ ['bg-base-300']: isActive }"
:to="{
name: type === 'browser' ? 'haexBrowser' : 'haexExtension',
params: type === 'browser' ? {} : { extensionId: id },
}"
class="flex items-center justify-center cursor-pointer tooltip-toogle"
ref="link"
>
<Icon
:name="icon"
class="shrink-0 size-6"
/>
</NuxtLinkLocale>
</UiTooltip>
</li>
</template>
<script setup lang="ts">
import { type ISidebarItem } from '#imports';
const props = defineProps<ISidebarItem>();
const router = useRouter();
const isActive = computed(() => {
if (props.type === 'browser') {
return router.currentRoute.value.name === 'haexBrowser';
} else if (props.type === 'extension') {
return (
router.currentRoute.value.name === 'haexExtension' &&
getSingleRouteParam(router.currentRoute.value.params.extensionId) ===
props.id
);
}
});
const link = useTemplateRef('link');
const triggerNavigate = () => link.value?.$el.click();
/* computed(() => {
const found = useRouter()
.getRoutes()
.find((route) => route.name === useLocaleRoute()(props.to)?.name);
console.log('found route', found, useRoute());
return (
found?.name === useRoute().name ||
found?.children.some((child) => child.name === useRoute().name)
);
}); */
</script>

View File

@ -0,0 +1,268 @@
<template>
<nav
class="navbar bg-base-100 max-sm:rounded-box max-sm:shadow sm:border-b border-base-content/25 sm:z-[1] relative"
>
<button
type="button"
class="btn btn-text max-sm:btn-square sm:hidden me-2"
aria-haspopup="dialog"
aria-expanded="false"
aria-controls="sidebar"
data-overlay="#sidebar"
>
<span class="icon-[tabler--menu-2] size-5"></span>
</button>
<div class="flex flex-1 items-center">
<a
class="link text-base-content link-neutral text-xl font-semibold no-underline"
href="#"
>
<UiTextGradient>Haex Hub</UiTextGradient>
</a>
</div>
<div class="navbar-end flex items-center gap-4">
<div
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
>
<button
id="dropdown-scrollable"
type="button"
class="dropdown-toggle btn btn-text btn-circle dropdown-open:bg-base-content/10 size-10"
aria-haspopup="menu"
aria-expanded="false"
aria-label="Dropdown"
>
<div class="indicator">
<span
v-show="notifications.length"
class="indicator-item bg-error size-2 rounded-full text-sm"
></span>
<span
class="icon-[tabler--bell] text-base-content size-[1.375rem]"
></span>
</div>
</button>
<div
class="dropdown-menu dropdown-open:opacity-100 hidden"
role="menu"
aria-orientation="vertical"
aria-labelledby="dropdown-scrollable"
>
<div class="dropdown-header justify-center">
<h6 class="text-base-content text-base">
{{ t('notifications.label') }}
</h6>
</div>
<div
class="vertical-scrollbar horizontal-scrollbar rounded-scrollbar text-base-content/80 max-h-56 overflow-auto max-md:max-w-60"
>
<div
class="dropdown-item"
v-for="notification in notifications"
>
<div class="avatar">
<div class="w-10 rounded-full">
<img
v-if="notification.image"
:src="notification.image"
:alt="notification.alt ?? 'notification avatar'"
/>
<Icon
v-else-if="notification.icon"
:name="notification.icon"
/>
</div>
</div>
<div class="w-60">
<h6 class="truncate text-base">
{{ notification.title }}
</h6>
<small class="text-base-content/50 truncate">
{{ notification.description }}
</small>
</div>
</div>
</div>
<a
href="#"
class="dropdown-footer justify-center gap-1"
>
<span class="icon-[tabler--eye] size-4"></span>
{{ t('notifications.view_all') }}
</a>
</div>
</div>
<div
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
>
<button
id="dropdown-scrollable"
type="button"
class="dropdown-toggle flex items-center"
aria-haspopup="menu"
aria-expanded="false"
aria-label="Dropdown"
>
<div class="avatar">
<div class="size-9.5 rounded-full">
<img
src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png"
alt="avatar 1"
/>
</div>
</div>
</button>
<ul
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60"
role="menu"
aria-orientation="vertical"
aria-labelledby="dropdown-avatar"
>
<li class="dropdown-header gap-2">
<div class="avatar">
<div class="w-10 rounded-full">
<img
src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png"
alt="avatar"
/>
</div>
</div>
<div>
<h6 class="text-base-content text-base font-semibold">
John Doe
</h6>
<small class="text-base-content/50">Admin</small>
</div>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--user]"></span>
My Profile
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--settings]"></span>
Settings
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--receipt-rupee]"></span>
Billing
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--help-triangle]"></span>
FAQs
</a>
</li>
<li class="dropdown-footer gap-2">
<a
class="btn btn-error btn-soft btn-block"
href="#"
>
<span class="icon-[tabler--logout]"></span>
Sign out
</a>
</li>
</ul>
</div>
</div>
</nav>
<aside
id="sidebar"
class="overlay sm:shadow-none overlay-open:translate-x-0 drawer drawer-start hidden max-w-64 sm:absolute sm:z-0 sm:flex sm:translate-x-0 pt-16"
role="dialog"
tabindex="-1"
>
<div class="drawer-body px-2 pt-4">
<ul class="menu p-0">
<li v-for="item in menu">
<a href="#">
<span class="icon-[tabler--home] size-5"></span>
Home
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--user] size-5"></span>
Account
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--message] size-5"></span>
Notifications
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--mail] size-5"></span>
Email
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--calendar] size-5"></span>
Calendar
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--shopping-bag] size-5"></span>
Product
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--login] size-5"></span>
Sign In
</a>
</li>
<li>
<a href="#">
<span class="icon-[tabler--logout-2] size-5"></span>
Sign Out
</a>
</li>
</ul>
</div>
</aside>
</template>
<script setup lang="ts">
const { t } = useI18n();
const { notifications } = storeToRefs(useNotificationStore());
const { menu } = storeToRefs(useSidebarStore());
</script>
<i18n lang="yaml">
de:
notifications:
label: Benachrichtigungen
view_all: Alle ansehen
en:
notifications:
label: Notifications
view_all: View all
</i18n>

View File

@ -0,0 +1,7 @@
<template>
<p
class="bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent font-black"
>
<slot />
</p>
</template>

View File

@ -0,0 +1,61 @@
<template>
<div class="tooltip [--prevent-popper:false]">
<div
class="tooltip-toggle"
aria-label="Tooltip"
>
<slot>
<button class="btn btn-square">
<Icon name="mdi:chevron-up-box-outline" />
</button>
</slot>
<span
class="tooltip-content tooltip-shown:opacity-100 tooltip-shown:visible z-40"
role="tooltip"
>
<span
class="tooltip-body"
v-bind="$attrs"
>
{{ tooltip }}
</span>
</span>
</div>
</div>
</template>
<script setup lang="ts">
import type { PropType } from 'vue';
const props = defineProps({
direction: {
type: String as PropType<
| 'top'
| 'top-start'
| 'top-end'
| 'bottom'
| 'bottom-start'
| 'bottom-end'
| 'right'
| 'right-start'
| 'right-end'
| 'left'
| 'left-start'
| 'left-end'
>,
default: 'top',
},
tooltip: String,
trigger: {
type: String as PropType<'focus' | 'hover' | 'click'>,
default: 'hover',
},
});
defineOptions({
inheritAttrs: false,
});
</script>

View File

@ -0,0 +1,165 @@
<template>
<UiDialog
:title="t('title')"
v-model:open="open"
>
<template #trigger="{ id }">
<button
class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1 whitespace-nowrap flex-nowrap"
@click="open = true"
>
<Icon name="mdi:plus" />
{{ t('database.create') }}
</button>
</template>
<form
class="flex flex-col gap-4"
@submit="onCreateAsync"
>
<!-- @keyup.enter="onCreateAsync" -->
<UiInput
:check-input="check"
:label="t('database.label')"
:placeholder="t('database.placeholder')"
:rules="vaultDatabaseSchema.name"
autofocus
prepend-icon="mdi:safe"
v-model="database.name"
/>
<UiInputPassword
:check-input="check"
:rules="vaultDatabaseSchema.password"
prepend-icon="mdi:key-outline"
v-model="database.password"
/>
</form>
<template #buttons>
<UiButton
class="btn-error"
@click="onClose"
>
{{ t('abort') }}
</UiButton>
<UiButton
class="btn-primary"
@click="onCreateAsync"
>
{{ t('create') }}
</UiButton>
</template>
</UiDialog>
</template>
<script setup lang="ts">
import { save } from '@tauri-apps/plugin-dialog';
import { useVaultStore } from '~/stores/vault';
import { vaultDatabaseSchema } from './schema';
const check = ref(false);
const open = ref();
const { t } = useI18n();
const database = reactive<{
name: string;
password: string;
path: string | null;
type: 'password' | 'text';
}>({
name: '',
password: '',
path: '',
type: 'password',
});
const initDatabase = () => {
database.name = t('database.name');
database.password = '';
database.path = '';
database.type = 'password';
};
initDatabase();
const { add } = useSnackbar();
const { createAsync } = useVaultStore();
//const { show } = storeToRefs(useSidebarStore());
const onCreateAsync = async () => {
check.value = true;
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name);
const passwordCheck = vaultDatabaseSchema.password.safeParse(
database.password
);
console.log(
'checks',
database.name,
nameCheck,
database.password,
passwordCheck
);
if (!nameCheck.success || !passwordCheck.success) return;
open.value = false;
try {
database.path = await save({ defaultPath: `${database.name}.db` });
console.log('data', database);
if (database.path && database.password) {
const vaultId = await createAsync({
path: database.path,
password: database.password,
});
//show.value = true;
await navigateTo(
useLocaleRoute()({ name: 'vault', params: { vaultId } })
);
}
} catch (error) {
console.error(error);
add({ type: 'error', text: JSON.stringify(error) });
}
};
const onClose = () => {
open.value = false;
initDatabase();
};
</script>
<i18n lang="json">
{
"de": {
"database": {
"label": "Datenbankname",
"placeholder": "Passwörter",
"create": "Neue Vault anlegen",
"name": "Passwörter"
},
"title": "Neue Datenbank anlegen",
"create": "Erstellen",
"abort": "Abbrechen",
"description": "Haex Vault für deine geheimsten Geheimnisse"
},
"en": {
"database": {
"label": "Databasename",
"placeholder": "Databasename",
"create": "Create new Vault",
"name": "Passwords"
},
"title": "Create New Database",
"create": "Create",
"abort": "Abort",
"description": "Haex Vault for your most secret secrets"
}
}
</i18n>

View File

@ -0,0 +1,179 @@
<template>
<UiDialog v-model:open="isOpen">
<!-- @close="initDatabase" -->
<template #trigger>
<button
class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1"
@click="onLoadDatabase"
>
<Icon name="mdi:folder-open-outline" />
{{ t('database.open') }}
</button>
</template>
<UiInputPassword
:check-input="check"
:rules="vaultDatabaseSchema.password"
@keyup.enter="onOpenDatabase"
autofocus
prepend-icon="mdi:key-outline"
v-model="database.password"
/>
<template #buttons>
<UiButton
class="btn-error"
@click="onClose"
>
{{ t('abort') }}
</UiButton>
<UiButton
type="submit"
class="btn-primary"
@click="onOpenDatabase"
>
{{ t('open') }}
</UiButton>
</template>
</UiDialog>
</template>
<script setup lang="ts">
import { open } from '@tauri-apps/plugin-dialog';
import { vaultDatabaseSchema } from './schema';
const { t } = useI18n();
const isOpen = defineModel('isOpen', { type: Boolean });
const props = defineProps({
path: String,
});
const check = ref(false);
const database = reactive<{
name: string;
password: string;
path: string | null;
type: 'password' | 'text';
}>({
name: '',
password: '',
path: '',
type: 'password',
});
const initDatabase = () => {
database.name = '';
database.password = '';
database.path = '';
database.type = 'password';
};
initDatabase();
const { add } = useSnackbar();
const handleError = (error: unknown) => {
isOpen.value = false;
add({ type: 'error', text: JSON.stringify(error) });
//console.error(error);
};
const { openAsync } = useVaultStore();
//const { show } = storeToRefs(useSidebarStore());
const onLoadDatabase = async () => {
try {
database.path = await open({
multiple: false,
directory: false,
filters: [
{
name: 'HaexVault',
extensions: ['db'],
},
],
});
if (!database.path) return;
isOpen.value = true;
} catch (error) {
handleError(error);
}
};
const localePath = useLocalePath();
const onOpenDatabase = async () => {
try {
check.value = true;
const path = database.path || props.path;
const pathCheck = vaultDatabaseSchema.path.safeParse(path);
const passwordCheck = vaultDatabaseSchema.password.safeParse(
database.password
);
if (!pathCheck.success || !passwordCheck.success || !path) {
add({ type: 'error', text: 'params falsch' });
return;
}
//console.log('try to open', path);
const vaultId = await openAsync({
path,
password: database.password,
});
if (!vaultId) {
add({ type: 'error', text: 'Vault konnte nicht geöffnet werden' });
return;
}
onClose();
/* await navigateTo(
localePath({
name: 'vaultGroup',
params: {
vaultId,
},
query: {
showSidebar: 'true',
},
})
); */
} catch (error) {
console.log(error);
handleError(error);
}
};
const onClose = () => {
initDatabase();
isOpen.value = false;
};
</script>
<i18n lang="json">
{
"de": {
"open": "Öffnen",
"abort": "Abbrechen",
"database": {
"open": "Vault öffnen"
}
},
"en": {
"open": "Open",
"abort": "Abort",
"database": {
"open": "Open Vault"
}
}
}
</i18n>

View File

@ -0,0 +1,7 @@
import { z } from 'zod';
export const vaultDatabaseSchema = {
password: z.string().min(6).max(255),
name: z.string().min(1).max(255),
path: z.string().min(4).endsWith('.db'),
};

View File

@ -0,0 +1,250 @@
<template>
<VaultCard
@close="onClose"
@submit="onSubmit"
>
<template #header>
<div class="flex flex-wrap items-center justify-between w-full px-2 py-3">
<div class="w-full flex gap-2 justify-between items-center">
<div class="flex items-center gap-2">
<button
class="btn btn-square btn-primary btn-outline"
@click="onBack"
>
<Icon
name="mdi:chevron-left"
size="32"
/>
</button>
<button
class="btn btn-square btn-error btn-outline"
@click="onBack"
>
<Icon
name="mdi:trash-can-outline"
size="28"
/>
</button>
</div>
<slot name="buttons">
<div
v-if="read_only"
class="h-full"
>
<button
class="btn btn-square btn-primary btn-outline"
@click="read_only = false"
>
<Icon
name="mdi:pencil-outline"
size="24"
/>
</button>
</div>
<div
v-else
class="gap-2 h-full hidden md:flex"
>
<button
class="btn btn-square btn-error btn-outline"
@click="onClose"
>
<Icon name="mdi:close" />
<span class="hidden"> {{ t('abort') }} </span>
</button>
<button
class="btn btn-square btn-success btn-outline"
@click="onSubmit"
>
<Icon name="mdi:check" />
<span class="hidden"> {{ t('create') }} </span>
</button>
</div>
</slot>
</div>
<div
class="flex flex-col items-center w-full min-h-14 gap-2 py-1"
:class="{ '-ml-6': !show }"
:style="{ color }"
>
<Icon
v-if="icon"
:name="icon"
size="28"
/>
<h5
v-show="read_only"
class="overflow-hidden whitespace-nowrap"
>
{{ title }}
</h5>
</div>
</div>
</template>
<div class="h-full">
<slot />
<div
v-show="!read_only"
class="fixed bottom-2 left-0 w-full flex items-center justify-between px-4 md:hidden"
>
<div
class="transition-all duration-500"
:class="{ 'pl-96': show }"
>
<button
class="btn btn-square btn-error btn-outline"
@click="onClose"
>
<Icon name="mdi:close" />
<span class="hidden"> {{ t('abort') }} </span>
</button>
</div>
<div>
<button
class="btn btn-square btn-success"
@click="onSubmit"
>
<Icon name="mdi:check" />
<span class="hidden"> {{ t('create') }} </span>
</button>
</div>
<div></div>
</div>
<!-- <UiButtonAction
class=""
icon="mdi:content-save-outline"
><Icon name="mdi:content-save-outline" />
</UiButtonAction> -->
</div>
</VaultCard>
<VaultModalSaveChanges
v-model="showConfirmation"
@reject="onReject"
@submit="onSubmit"
/>
</template>
<script setup lang="ts">
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
const { t } = useI18n();
const { show } = storeToRefs(useSidebarStore());
const read_only = defineModel<boolean>('read_only', { default: false });
const props = defineProps({
color: String,
hasChanges: Boolean,
icon: String,
title: String,
});
const emit = defineEmits<{
back: [void];
close: [void];
reject: [to?: RouteLocationNormalizedLoadedGeneric];
submit: [to?: RouteLocationNormalizedLoadedGeneric];
}>();
const showConfirmation = ref(false);
const to = ref<RouteLocationNormalizedLoadedGeneric>();
const isApprovedForLeave = ref(false);
const wantToGoBack = ref(false);
const onSubmit = () => {
showConfirmation.value = false;
isApprovedForLeave.value = true;
if (wantToGoBack.value) {
wantToGoBack.value = false;
read_only.value = true;
emit('submit');
} else {
emit('submit', to.value);
}
};
const onReject = () => {
showConfirmation.value = false;
isApprovedForLeave.value = true;
read_only.value = true;
if (wantToGoBack.value) {
wantToGoBack.value = false;
emit('back');
} else emit('reject', to.value);
};
const onBack = () => {
if (props.hasChanges) {
wantToGoBack.value = true;
showConfirmation.value = true;
} else {
emit('back');
}
};
const onClose = () => {
if (props.hasChanges) {
showConfirmation.value = true;
} else {
emit('close'); //read_only.value = true;
}
};
const onDelete = () => {};
onBeforeRouteLeave((_to, _from, next) => {
//console.log('check before leave', _to, _from);
to.value = _to;
if (isApprovedForLeave.value) {
isApprovedForLeave.value = false;
next();
} else if (props.hasChanges) {
showConfirmation.value = true;
} else {
next();
}
});
</script>
<i18n lang="json">
{
"de": {
"create": "Anlegen",
"abort": "Abbrechen",
"entry": {
"title": "Titel",
"username": "Nutzername",
"password": "Passwort",
"url": "Url"
},
"tab": {
"details": "Details",
"keyValue": "Extra",
"history": "Verlauf"
}
},
"en": {
"create": "Create",
"abort": "Abort",
"entry": {
"title": "Title",
"username": "Username",
"password": "Password",
"url": "Url"
},
"tab": {
"details": "Details",
"keyValue": "Extra",
"history": "History"
}
}
}
</i18n>

View File

@ -0,0 +1,42 @@
<template>
<div
class="bg-base-100 w-full mx-auto shadow h-full overflow-hidden pt-[7.5rem]"
>
<div
class="fixed top-0 right-0 z-10 transition-all duration-700 w-full font-semibold text-lg h-[7.5rem]"
:class="{ 'pl-96': show }"
>
<div
class="justify-center items-center flex flex-wrap border-b rounded-b border-secondary h-full"
:class="{ 'pl-12': !show }"
>
<slot name="header" />
</div>
</div>
<div class="h-full overflow-scroll bg-base-200">
<slot />
</div>
</div>
</template>
<script setup lang="ts">
const { show } = storeToRefs(useSidebarStore());
const emit = defineEmits(['close', 'submit']);
const { escape, enter } = useMagicKeys();
watchEffect(async () => {
if (escape.value) {
await nextTick();
emit('close');
}
});
watchEffect(async () => {
if (enter.value) {
await nextTick();
emit('submit');
}
});
</script>

View File

@ -0,0 +1,32 @@
<template>
<UiDialog :title="t('title')">
<form class="flex flex-col">
<UiInput v-model="vaultItem.title" />
<UiInput v-model="vaultItem.username" />
<UiInput v-model="vaultItem.password" />
<UiInput v-model="vaultItem.note" />
</form>
</UiDialog>
</template>
<script setup lang="ts">
const { t } = useI18n();
const vaultItem = reactive({
title: '',
username: '',
password: '',
note: '',
});
</script>
<i18n lang="json">
{
"de": {
"title": "Eintrag erstellen"
},
"en": {
"title": "Create Entry"
}
}
</i18n>

View File

@ -0,0 +1,117 @@
<template>
<VaultCardEdit
v-if="vaultGroup"
:color="vaultGroup.color ?? 'text-base-content'"
:has-changes="hasChanges"
:icon="vaultGroup.icon ?? 'mdi:folder-outline'"
:title="vaultGroup.name ?? ''"
@back="$emit('back')"
@close="$emit('close')"
@reject="(to) => $emit('reject', to)"
@submit="(to) => $emit('submit', to)"
v-model:read_only="read_only"
>
<div class="flex flex-col gap-4 w-full p-4">
<UiInput
v-show="!read_only"
:label="t('vaultGroup.name')"
:placeholder="t('vaultGroup.name')"
:rules="vaultGroupSchema.name"
:with-copy-button="read_only"
:read_only
autofocus
v-model.trim="vaultGroup.name"
/>
<UiInput
v-show="!read_only || vaultGroup.description?.length"
:read_only
:label="t('vaultGroup.description')"
:placeholder="t('vaultGroup.description')"
:rules="vaultGroupSchema.description"
:with-copy-button="read_only"
v-model.trim="vaultGroup.description"
/>
<UiColorPicker
:read_only
:label="t('vaultGroup.color')"
:placeholder="t('vaultGroup.color')"
v-model="vaultGroup.color"
/>
<UiIconPicker
:read_only
:label="t('vaultGroup.icon')"
:placeholder="t('vaultGroup.icon')"
v-model="vaultGroup.icon"
/>
</div>
</VaultCardEdit>
</template>
<script setup lang="ts">
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
import {
vaultGroupSchema,
type SelectVaultGroup,
} from '~/database/schemas/vault';
const { t } = useI18n();
const showConfirmation = ref(false);
const vaultGroup = defineModel<SelectVaultGroup>({ required: true });
const read_only = defineModel<boolean>('read_only');
const props = defineProps({
originally: Object as PropType<SelectVaultGroup>,
});
defineEmits<{
submit: [to?: RouteLocationNormalizedLoadedGeneric];
close: [void];
back: [void];
reject: [to?: RouteLocationNormalizedLoadedGeneric];
}>();
const hasChanges = computed(() => {
console.log('group has changes', props.originally, vaultGroup.value);
if (!props.originally) {
if (
vaultGroup.value.color?.length ||
vaultGroup.value.description?.length ||
vaultGroup.value.icon?.length ||
vaultGroup.value.name?.length
) {
return true;
} else {
return false;
}
}
return JSON.stringify(props.originally) !== JSON.stringify(vaultGroup.value);
});
/* const onClose = () => {
if (props.originally) vaultGroup.value = { ...props.originally };
emit('close');
}; */
</script>
<i18n lang="json">
{
"de": {
"vaultGroup": {
"name": "Name",
"description": "Beschreibung",
"icon": "Icon",
"color": "Farbe"
}
},
"en": {
"vaultGroup": {
"name": "Name",
"description": "Description",
"icon": "Icon",
"color": "Color"
}
}
}
</i18n>

View File

@ -0,0 +1,42 @@
<template>
<UiListButton
v-if="entry"
:key="entry.id"
@click="navigateToEntryAsync(entry.id)"
class="text-base-content"
>
<div class="flex items-center gap-3">
<div class="w-8">
<Icon
v-if="entry.icon || groupIcon"
:name="entry.icon || groupIcon!"
/>
</div>
<div class="flex flex-col items-start">
<div v-if="!entry.title && !entry.username && !entry.url">
{{ entry.id }}
</div>
<div class="font-semibold">
{{ entry.title }}
</div>
<span class="text-sm">
{{ entry.username }}
</span>
<span class="text-sm">
{{ entry.url }}
</span>
</div>
</div>
</UiListButton>
</template>
<script setup lang="ts">
import type { SelectVaultEntry } from '~/database/schemas/vault';
defineProps({
entry: Object as PropType<SelectVaultEntry>,
groupIcon: [String, null],
});
const { navigateToEntryAsync } = useVaultEntryStore();
</script>

View File

@ -0,0 +1,7 @@
<template>
<UiList>
<slot />
</UiList>
</template>
<script setup lang="ts"></script>

View File

@ -0,0 +1,78 @@
<template>
<UiDialog
v-model:open="showConfirmation"
:title="t('dialog.title')"
>
{{ t('dialog.question') }}
<template #buttons>
<UiButton
class="btn-outline btn-error focus:bg-primary"
tabindex="10"
@click="$emit('reject')"
>
<Icon name="mdi:cancel" />
<span class="hidden sm:block">
{{ t('dialog.reject') }}
</span>
</UiButton>
<UiButton
class="btn-outline focus:bg-primary"
tabindex="11"
ref="abortButtonRef"
@click="showConfirmation = false"
>
<Icon name="mdi:close" />
<span class="hidden sm:block">
{{ t('dialog.abort') }}
</span>
</UiButton>
<UiButton
class="btn-outline btn-success"
tabindex="12"
@click="$emit('submit')"
>
<Icon name="mdi:check" />
<span class="hidden sm:block">
{{ t('dialog.save') }}
</span>
</UiButton>
</template>
</UiDialog>
</template>
<script setup lang="ts">
const showConfirmation = defineModel<boolean>();
const abortButtonRef = useTemplateRef('abortButtonRef');
const { t } = useI18n();
const { currentScreenSize } = storeToRefs(useUiStore());
onUpdated(() => {
abortButtonRef.value?.$el.focus();
});
defineEmits(['submit', 'reject']);
</script>
<i18n lang="json">
{
"de": {
"dialog": {
"title": "Ungespeicherte Änderungen",
"question": "Möchten Sie die Änderungen speichern?",
"reject": "Verwerfen",
"abort": "Abbrechen",
"save": "Speichern"
}
},
"en": {
"dialog": {
"title": "Unsaved Changes",
"question": "Would you like to save the changes?",
"reject": "Reject",
"abort": "Abort",
"save": "Save"
}
}
}
</i18n>

96
src/composables/helper.ts Normal file
View File

@ -0,0 +1,96 @@
import { H3Error } from 'h3';
export const bytesToBase64DataUrlAsync = async (
bytes: Uint8Array,
type = 'application/octet-stream'
) => {
return await new Promise((resolve, reject) => {
const reader = Object.assign(new FileReader(), {
onload: () => resolve(reader.result),
onerror: () => reject(reader.error),
});
reader.readAsDataURL(new File([new Blob([bytes])], '', { type }));
});
};
export const blobToImageAsync = (blob: Blob): Promise<HTMLImageElement> => {
return new Promise((resolve) => {
console.log('transform blob', blob);
const url = URL.createObjectURL(blob);
let img = new Image();
img.onload = () => {
URL.revokeObjectURL(url);
resolve(img);
};
img.src = url;
});
};
export const deepToRaw = <T extends Record<string, any>>(sourceObj: T): T => {
const objectIterator = (input: any): any => {
if (Array.isArray(input)) {
return input.map((item) => objectIterator(item));
}
if (isRef(input) || isReactive(input) || isProxy(input)) {
return objectIterator(toRaw(input));
}
if (input && typeof input === 'object') {
return Object.keys(input).reduce((acc, key) => {
acc[key as keyof typeof acc] = objectIterator(input[key]);
return acc;
}, {} as T);
}
return input;
};
return objectIterator(sourceObj);
};
export const readableFileSize = (sizeInByte: number | string = 0) => {
if (!sizeInByte) {
return '0 KB';
}
const size =
typeof sizeInByte === 'string' ? parseInt(sizeInByte) : sizeInByte;
const sizeInKb = size / 1024;
const sizeInMb = sizeInKb / 1024;
const sizeInGb = sizeInMb / 1024;
const sizeInTb = sizeInGb / 1024;
if (sizeInTb > 1) return `${sizeInTb.toFixed(2)} TB`;
if (sizeInGb > 1) return `${sizeInGb.toFixed(2)} GB`;
if (sizeInMb > 1) return `${sizeInMb.toFixed(2)} MB`;
return `${sizeInKb.toFixed(2)} KB`;
};
import type { LocationQueryValue, RouteLocationRawI18n } from 'vue-router';
export const getSingleRouteParam = (
param: string | string[] | LocationQueryValue | LocationQueryValue[]
): string => {
const _param = Array.isArray(param) ? param.at(0) ?? '' : param ?? '';
//console.log('found param', _param, param);
return _param;
};
export const isRouteActive = (
to: RouteLocationRawI18n,
exact: boolean = false
) =>
computed(() => {
const found = useRouter()
.getRoutes()
.find((route) => route.name === useLocaleRoute()(to)?.name);
//console.log('found route', found, useRouter().currentRoute.value, to);
return exact
? found?.name === useRouter().currentRoute.value.name
: found?.name === useRouter().currentRoute.value.name ||
found?.children.some(
(child) => child.name === useRouter().currentRoute.value.name
);
});
export const isKey = <T extends object>(x: T, k: PropertyKey): k is keyof T => {
return k in x;
};

16
src/i18n/i18n.config.ts Normal file
View File

@ -0,0 +1,16 @@
/* import de from '@/stores/sidebar/de.json';
import en from '@/stores/sidebar/en.json'; */
export default defineI18nConfig(() => {
return {
legacy: false,
messages: {
de: {
//sidebar: de,
},
en: {
//sidebar: en,
},
},
};
});

271
src/layouts/app.vue Normal file
View File

@ -0,0 +1,271 @@
<template>
<div class="w-full h-full flex flex-col">
<nav
class="navbar bg-base-100 max-sm:rounded-box max-sm:shadow sm:border-b border-base-content/25 sm:z-20 relative"
>
<button
type="button"
class="btn btn-text max-sm:btn-square sm:hidden me-2"
aria-haspopup="dialog"
aria-expanded="false"
aria-controls="sidebar"
data-overlay="#sidebar"
>
<span class="icon-[tabler--menu-2] size-5"></span>
</button>
<div class="flex flex-1 items-center">
<a
class="link text-base-content link-neutral text-xl font-semibold no-underline"
href="#"
>
<UiTextGradient>Haex Hub</UiTextGradient>
</a>
</div>
<div class="navbar-end flex items-center gap-4">
<div
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
>
<button
id="dropdown-scrollable"
type="button"
class="dropdown-toggle btn btn-text btn-circle dropdown-open:bg-base-content/10 size-10"
aria-haspopup="menu"
aria-expanded="false"
aria-label="Dropdown"
>
<div class="indicator">
<span
v-show="notifications.length"
class="indicator-item bg-error size-2 rounded-full text-sm"
></span>
<span
class="icon-[tabler--bell] text-base-content size-[1.375rem]"
></span>
</div>
</button>
<div
class="dropdown-menu dropdown-open:opacity-100 hidden"
role="menu"
aria-orientation="vertical"
aria-labelledby="dropdown-scrollable"
>
<div class="dropdown-header justify-center">
<h6 class="text-base-content text-base">
{{ t('notifications.label') }}
</h6>
</div>
<div
class="vertical-scrollbar horizontal-scrollbar rounded-scrollbar text-base-content/80 max-h-56 overflow-auto max-md:max-w-60"
>
<div
class="dropdown-item"
v-for="notification in notifications"
>
<div class="avatar">
<div class="w-10 rounded-full">
<img
v-if="notification.image"
:src="notification.image"
:alt="notification.alt ?? 'notification avatar'"
/>
<Icon
v-else-if="notification.icon"
:name="notification.icon"
/>
</div>
</div>
<div class="w-60">
<h6 class="truncate text-base">
{{ notification.title }}
</h6>
<small class="text-base-content/50 truncate">
{{ notification.description }}
</small>
</div>
</div>
</div>
<a
href="#"
class="dropdown-footer justify-center gap-1"
>
<span class="icon-[tabler--eye] size-4"></span>
{{ t('notifications.view_all') }}
</a>
</div>
</div>
<div
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
>
<button
id="dropdown-scrollable"
type="button"
class="dropdown-toggle flex items-center"
aria-haspopup="menu"
aria-expanded="false"
aria-label="Dropdown"
>
<div class="avatar">
<div class="size-9.5 rounded-full">
<img
src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png"
alt="avatar 1"
/>
</div>
</div>
</button>
<ul
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60"
role="menu"
aria-orientation="vertical"
aria-labelledby="dropdown-avatar"
>
<li class="dropdown-header gap-2">
<div class="avatar">
<div class="w-10 rounded-full">
<img
src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png"
alt="avatar"
/>
</div>
</div>
<div>
<h6 class="text-base-content text-base font-semibold">
John Doe
</h6>
<small class="text-base-content/50">Admin</small>
</div>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--user]"></span>
My Profile
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--settings]"></span>
Settings
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--receipt-rupee]"></span>
Billing
</a>
</li>
<li>
<a
class="dropdown-item"
href="#"
>
<span class="icon-[tabler--help-triangle]"></span>
FAQs
</a>
</li>
<li class="dropdown-footer gap-2">
<button
class="btn btn-error btn-soft btn-block"
@click="onVaultCloseAsync"
>
<span class="icon-[tabler--logout]"></span>
{{ t('vault.close') }}
</button>
</li>
</ul>
</div>
</div>
</nav>
<aside
id="sidebar"
class="overlay sm:shadow-none overlay-open:translate-x-0 drawer drawer-start hidden sm:absolute max-w-14 sm:flex sm:translate-x-0 sm:pt-16 z-10"
role="dialog"
tabindex="-1"
>
<div class="drawer-body px-0 pt-4">
<ul class="menu p-0">
<!-- <li
> -->
<UiSidebarLink
v-bind="item"
v-for="item in menu"
:key="item.id"
/>
<!-- <UiTooltip
:tooltip="item.tooltip || item.name"
direction="right-start"
>
<NuxtLinkLocale
:class="{ ['bg-base-300']: isActive(item.id).value }"
:to="{
name: 'extension',
params: { extensionId: item.id, vaultId: 'test' },
}"
class="flex items-center justify-start hover:text-primary cursor-pointer tooltip-toogle"
>
<Icon
:name="item.icon"
class="size-6"
/>
<i
:class="item.icon"
class="shrink-0 size-8"
/>
</NuxtLinkLocale>
</UiTooltip> -->
<!-- </li> -->
</ul>
</div>
</aside>
<div class="overflow-hidden transition-all relative w-full">
<div class="h-full overflow-scroll sm:pl-14">
<NuxtPage />
</div>
</div>
<!-- <main class="sm:pl-14">
<NuxtPage />
</main> -->
</div>
</template>
<script setup lang="ts">
const { t } = useI18n();
const { notifications } = storeToRefs(useNotificationStore());
const { menu } = storeToRefs(useSidebarStore());
const { isActive } = useExtensionsStore();
const onExtensionSelectAsync = async (id: string) => {};
const onVaultCloseAsync = async () => {};
</script>
<i18n lang="yaml">
de:
notifications:
label: Benachrichtigungen
view_all: Alle ansehen
vault:
close: Vault schließen
en:
notifications:
label: Notifications
view_all: View all
vault:
close: Close vault
</i18n>

5
src/layouts/default.vue Normal file
View File

@ -0,0 +1,5 @@
<template>
<div class="w-screen h-screen overflow-scroll bg-base-200">
<slot />
</div>
</template>

155
src/pages/index.vue Normal file
View File

@ -0,0 +1,155 @@
<template>
<div class="items-center justify-center min-h-full flex w-full">
<div class="flex flex-col justify-center items-center gap-4 max-w-3xl">
<img
src="/logo.svg"
class="bg-primary p-3 size-16 rounded-full"
alt="HaexVault Logo"
/>
<span
class="flex flex-wrap font-bold text-pretty text-xl gap-2 justify-center"
>
<p class="whitespace-nowrap">
{{ t('welcome') }}
</p>
<UiTextGradient>Haex Hub</UiTextGradient>
</span>
<div class="flex flex-col md:flex-row gap-4 w-full">
<VaultButtonCreate />
<!-- <VaultButtonOpen
v-model:isOpen="passwordPromptOpen"
:path="vaultPath"
/> -->
<NuxtLinkLocale
:to="{
name: 'haexBrowser',
params: { vaultId: 'test' },
}"
>test link</NuxtLinkLocale
>
<!-- <button @click="test">test</button>
<NuxtLinkLocale
:to="{ name: 'vaultGroup', params: { vaultId: 'test' } }"
>test link</NuxtLinkLocale
> -->
<!-- <UiTreeFolder
@edit="test"
:value="tests"
v-for="tests in [1, 2, 3]"
/>
<UiTreeFolder
@edit="test"
value="test123"
/> -->
</div>
<div
v-show="lastVaults.length"
class="w-full"
>
<div class="font-thin text-sm justify-start px-2 pb-1">
{{ t('lastUsed') }}
</div>
<div
class="relative border-base-content/25 divide-base-content/25 flex w-full flex-col divide-y rounded-md border first:*:rounded-t-md last:*:rounded-b-md overflow-scroll"
>
<div
class="flex items-center justify-between group h-12 overflow-x-scroll"
v-for="vault in lastVaults"
:key="vault.path"
>
<button
class="link link-accent flex items-center no-underline justify-between text-nowrap text-xs md:text-base shrink w-full py-2 px-4"
@click="
passwordPromptOpen = true;
vaultPath = vault.path;
"
>
<span class="block md:hidden">
{{ vault.name }}
</span>
<span class="hidden md:block">
{{ vault.path }}
</span>
</button>
<button
class="absolute right-2 btn btn-square btn-error btn-xs hidden group-hover:flex min-w-6"
>
<Icon
name="mdi:trash-can-outline"
@click="removeVaultAsync(vault.path)"
/>
</button>
</div>
</div>
</div>
<div class="flex flex-col items-center gap-2">
<h4>{{ t('sponsors') }}</h4>
<div>
<button @click="openUrl('https://itemis.com')">
<UiLogoItemis class="text-[#00457C]" />
</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { openUrl } from '@tauri-apps/plugin-opener';
const passwordPromptOpen = ref(false);
const vaultPath = ref('');
definePageMeta({
name: 'vaultOpen',
});
const { t } = useI18n();
const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore();
const { lastVaults } = storeToRefs(useLastVaultStore());
await syncLastVaultsAsync();
/* const { $pluginManager } = useNuxtApp();
console.log('$pluginManager', $pluginManager);
async function loadModule() {
try {
// Dynamisches Laden des Moduls
const file = await open({
multiple: false,
directory: false,
});
const moduleUrl =
'/home/haex/Projekte/haex-vault-2/haex-vault/src/extensions/test/testPlugin.ts'; // Pfad relativ zum Server-Root
await $pluginManager.loadDynamicModule(file);
console.log('Modul erfolgreich geladen');
} catch (error) {
console.error('Fehler beim Laden des Moduls:', error);
}
}
//await loadModule(); */
</script>
<i18n lang="json">
{
"de": {
"welcome": "Viel Spass mit",
"lastUsed": "Zuletzt verwendete Vaults",
"sponsors": "Powered by"
},
"en": {
"welcome": "Have fun with",
"lastUsed": "Last used Vaults",
"sponsors": "Powered by"
}
}
</i18n>

10
src/pages/test.vue Normal file
View File

@ -0,0 +1,10 @@
<template>
<UiSidebarTest />
</template>
<script setup lang="ts">
definePageMeta({
name: 'test',
});
</script>

7
src/pages/vault.vue Normal file
View File

@ -0,0 +1,7 @@
<template>
<div>
<NuxtLayout name="app">
<NuxtPage />
</NuxtLayout>
</div>
</template>

View File

@ -0,0 +1,127 @@
<template>
<div>
browser
<HaexBrowser
:tabs="tabs"
:activeTabId="activeTabId"
@createTab="createNewTab"
@closeTab="closeTab"
@navigate="navigateToUrl"
@goBack="goBack"
@goForward="goForward"
/>
</div>
</template>
<script setup lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
import { Window, getCurrentWindow } from '@tauri-apps/api/window';
import { Webview } from '@tauri-apps/api/webview';
definePageMeta({
name: 'haexBrowser',
});
interface Tab {
id: string;
title: string;
url: string;
isLoading: boolean;
isActive: boolean;
window_label: string;
}
const tabs = ref<Tab[]>([]);
const activeTabId = ref<string | null>(null);
let unlistenTabCreated: UnlistenFn | null = null;
let unlistenTabClosed: UnlistenFn | null = null;
onMounted(async () => {
// Erstelle einen ersten Tab beim Start
createNewTab('https://www.google.com');
// Höre auf Tab-Events
unlistenTabCreated = await listen('tab-created', (event) => {
const newTab = event.payload as Tab;
tabs.value = tabs.value.map((tab) => ({
...tab,
isActive: tab.id === newTab.id,
}));
if (!tabs.value.some((tab) => tab.id === newTab.id)) {
tabs.value.push(newTab);
}
activeTabId.value = newTab.id;
});
unlistenTabClosed = await listen('tab-closed', (event) => {
const closedTabId = event.payload as string;
tabs.value = tabs.value.filter((tab) => tab.id !== closedTabId);
});
});
onUnmounted(() => {
if (unlistenTabCreated) unlistenTabCreated();
if (unlistenTabClosed) unlistenTabClosed();
});
const createNewTab = async (url: string = 'about:blank') => {
try {
/* const appWindow = new Window('uniqueLabel111', {
fullscreen: true,
});
*/
/* const appWindow = getCurrentWindow();
const webview = new Webview(appWindow, 'theUniqueLabel', {
url: 'https://github.com/tauri-apps/tauri',
height: 1000,
width: 1000,
x: 110,
y: 0,
});
await webview.show(); */
//console.log('create webview', webview);
const tab_id = 'foo';
await invoke('create_tab', { url, tabId: 'foo' });
} catch (error) {
console.error('Fehler beim Erstellen des Tabs:', error);
}
};
const closeTab = async (tabId: string) => {
try {
//await invoke('close_tab', { tabId });
} catch (error) {
console.error('Fehler beim Schließen des Tabs:', error);
}
};
const navigateToUrl = async (tabId: string, url: string) => {
try {
//await invoke('navigate_to_url', { tabId, url });
} catch (error) {
console.error('Fehler bei der Navigation:', error);
}
};
const goBack = async (tabId: string | null) => {
try {
//await invoke('go_back', { tabId });
} catch (error) {
console.error('Fehler beim Zurückgehen:', error);
}
};
const goForward = async (tabId: string | null) => {
try {
//await invoke('go_forward', { tabId });
} catch (error) {
console.error('Fehler beim Vorwärtsgehen:', error);
}
};
</script>

View File

@ -0,0 +1,13 @@
<template>
<div>
hier kommt die erweiterung
{{ useRouter().currentRoute.value.params.extensionId }}
<iframe></iframe>
</div>
</template>
<script setup lang="ts">
definePageMeta({
name: 'haexExtension',
});
</script>

View File

@ -0,0 +1,9 @@
<template>
<div>ad extension</div>
</template>
<script setup lang="ts">
definePageMeta({
name: 'extensionAdd',
});
</script>

View File

@ -0,0 +1,9 @@
<template>
<div>vault</div>
</template>
<script setup lang="ts">
definePageMeta({
name: 'vaultOverview',
});
</script>

View File

@ -0,0 +1,13 @@
import 'flyonui/flyonui';
import { type IStaticMethods } from 'flyonui/flyonui';
declare global {
interface Window {
HSStaticMethods: IStaticMethods;
}
}
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:finish', () => {
window.HSStaticMethods.autoInit();
});
});

BIN
src/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

48
src/public/itemis.svg Normal file
View File

@ -0,0 +1,48 @@
<svg id="logo" class="fill-current w-[160px]" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 286.3 85" xml:space="preserve">
<switch>
<g>
<g class="logo-image">
<circle fill="white" cx="42.5" cy="42.5" r="40"></circle>
<path d="M42.3,83.4c-22.6,0-40.9-18.4-40.9-40.9c0-22.6,18.4-40.9,40.9-40.9c22.6,0,40.9,18.4,40.9,40.9
C83.3,65.1,64.9,83.4,42.3,83.4z M42.3,5.8C22.1,5.8,5.7,22.3,5.7,42.5s16.5,36.7,36.7,36.7S79,62.7,79,42.5S62.6,5.8,42.3,5.8z
"></path>
<g>
<g>
<polygon points="38.8,69.8 38.8,31.7 22.3,31.7 22.3,38.5 29.8,38.5 29.8,69.8 "></polygon>
<path d="M34.1,13.2c-3.3,0-6,2.6-6,5.9c0,3.3,2.6,6,5.9,6c3.3,0,6-2.6,6-6
C39.9,15.9,37.3,13.2,34.1,13.2z"></path>
</g>
<g>
<polygon points="45.9,69.8 45.9,31.7 62.4,31.7 62.4,38.5 54.9,38.5 54.9,69.8 "></polygon>
<path d="M50.6,13.2c3.3,0,6,2.6,6,5.9c0,3.3-2.6,6-5.9,6c-3.3,0-6-2.6-6-6
C44.8,15.9,47.4,13.2,50.6,13.2z"></path>
</g>
</g>
</g>
<g class="logo-text">
<path d="M136.1,63.6c-4,0-5.3-2.6-5.3-6V38.5h10.6v-6.7h-10.6v-6.7h-9c0,7,0,29.1,0,32.7
c0,4.2,1.6,7.5,3.8,9.7c2.3,2.2,5.6,3.3,9.8,3.3c5.1,0,8.4-1.8,10.6-4.2l-4.7-6C140.2,62.1,138.5,63.6,136.1,63.6z"></path>
<path d="M217.7,30.7c-4.9,0-8.2,1.6-10.4,3.8c-2.2-2.2-5.5-3.8-10.4-3.8c-15,0-14.9,12.1-14.9,15
s0,24.1,0,24.1h9V45.7c0-8.5,4.9-8.3,5.9-8.3c1,0,5.9-0.3,5.9,8.3v24.1h0h9h0V45.7c0-8.5,4.9-8.3,5.9-8.3c1,0,5.9-0.3,5.9,8.3
v24.1h9c0,0,0-21.2,0-24.1C232.6,42.8,232.7,30.7,217.7,30.7z"></path>
<path d="M273.2,46.4c-4.3-1.4-6-2.5-6-5.2c0-2,1.1-3.8,4.3-3.8c3.2,0,4.5,3.3,5.1,4.8
c2.7-1.5,5.3-2.9,6.6-3.6c-2.5-6-6.3-7.9-12-7.9c-8,0-11.7,5.5-11.7,10.6c0,6.5,2.9,9.8,11.2,12.2c6,1.8,6.5,4.7,6.2,6.2
c-0.3,1.7-1.6,3.6-5.3,3.6c-3.6,0-5.8-3.8-6.8-5.4c-1.8,1.1-3.4,2.1-6.4,3.8c2.1,5,6.8,9.1,13.5,9.1c7.9,0,12.9-5.1,12.9-12.1
C284.9,51,279.6,48.5,273.2,46.4z"></path>
<g>
<polygon points="239.7,69.8 239.7,31.7 256.2,31.7 256.2,38.5 248.7,38.5 248.7,69.8 "></polygon>
<path d="M244.4,13.2c3.3,0,6,2.6,6,5.9c0,3.3-2.6,6-5.9,6c-3.3,0-6-2.6-6-6
C238.6,15.9,241.2,13.2,244.4,13.2z"></path>
</g>
<g>
<polygon points="114.7,69.8 114.7,31.7 98.1,31.7 98.1,38.5 105.7,38.5 105.7,69.8 "></polygon>
<path d="M110,13.2c-3.3,0-6,2.6-6,5.9c0,3.3,2.6,6,5.9,6c3.3,0,6-2.6,6-6C115.8,15.9,113.2,13.2,110,13.2
z"></path>
</g>
<path d="M176.4,52.4v-3.7c0-12.3-4.7-18-14.8-18c-9.3,0-14.7,6.6-14.7,18v4c0,11.5,5.8,18.2,15.8,18.2
c6.6,0,10.8-3.7,12.7-7.9c-2.2-1.4-4.6-2.8-6.1-3.8c-1,1.7-2.9,4.4-6.7,4.4c-5.8,0-7-5.9-7-10.9v-0.2H176.4z M155.7,45.7
c0.2-7.1,3.3-8.2,6-8.2c2.6,0,5.9,1,6,8.2H155.7z"></path>
</g>
</g>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

207
src/public/logo.svg Normal file
View File

@ -0,0 +1,207 @@
<svg viewBox="122 107 263 292" xmlns="http://www.w3.org/2000/svg" style="max-height: 500px" width="263" height="292">
<g stroke-width="0.3" stroke-opacity="0.00" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 0.00 500.00 &#xA;L 500.00 500.00&#xA;L 500.00 0.00&#xA;L 0.00 0.00&#xA;L 0.00 500.00&#xA;M 224.00 111.00 &#xA;C 231.64 114.34 231.15 125.27 233.78 133.22 C 236.40 141.18 233.32 153.32 229.08 160.08 C 224.84 166.83 229.06 176.15 231.33 183.67 C 233.59 191.20 237.83 198.83 244.00 204.00&#xA;C 266.37 217.28 288.30 227.00 309.00 244.00&#xA;C 302.67 236.14 297.53 229.03 290.75 221.25 C 283.96 213.48 279.34 206.78 272.70 198.30 C 266.05 189.82 261.91 183.96 256.69 173.31 C 251.48 162.65 249.83 154.72 248.00 141.00 C 246.17 127.28 259.55 133.29 268.08 139.92 C 276.61 146.55 285.22 149.49 293.75 155.25 C 302.27 161.02 311.02 165.51 319.00 172.00&#xA;C 333.96 180.10 351.42 199.09 360.00 215.00&#xA;C 364.03 222.47 368.67 227.83 371.77 236.23 C 374.87 244.63 375.48 254.80 378.33 263.67 C 381.18 272.54 380.34 286.05 379.22 295.22 C 378.11 304.40 376.21 314.80 373.02 323.02 C 369.84 331.25 366.25 338.84 362.23 346.23 C 358.20 353.62 353.47 359.98 348.25 366.25 C 343.03 372.51 336.37 377.44 331.08 379.86&#xA;C 327.43 381.21 324.03 383.93 320.00 385.00&#xA;C 320.86 388.48 313.78 392.73 306.78 393.78 C 299.78 394.82 288.01 393.70 280.00 394.00 C 271.99 394.30 261.37 393.91 253.00 394.00 C 244.63 394.09 235.43 394.10 227.00 394.00 C 218.57 393.90 208.23 394.32 200.00 394.00 C 191.77 393.68 182.87 396.59 178.00 389.00&#xA;C 175.90 386.88 176.08 388.00 175.00 385.00&#xA;C 173.90 381.94 174.40 379.91 175.00 377.00&#xA;C 175.83 372.99 176.48 370.39 179.00 367.00&#xA;C 181.54 363.59 184.21 361.67 188.00 360.00&#xA;C 194.80 357.00 202.48 358.16 210.00 358.00&#xA;C 204.18 349.77 197.87 341.27 197.00 331.00&#xA;C 196.59 329.08 195.21 326.36 195.00 324.00&#xA;C 194.72 320.78 194.25 315.36 196.00 313.00&#xA;C 196.00 312.50 196.00 312.00 196.00 312.00&#xA;C 196.30 310.37 198.29 306.24 198.00 307.00&#xA;C 198.19 306.12 198.11 304.33 199.00 303.00&#xA;C 191.11 300.89 179.04 304.79 170.00 303.00 C 160.96 301.21 153.07 308.94 145.00 309.00 C 136.93 309.06 130.06 302.11 126.00 296.00&#xA;C 123.16 291.73 121.53 286.73 123.00 281.00&#xA;C 123.82 277.81 125.91 276.29 128.00 274.00&#xA;C 131.09 269.45 136.40 267.32 142.00 266.00&#xA;C 144.65 265.37 147.06 264.79 150.00 265.00&#xA;C 150.50 265.03 151.50 265.00 152.00 265.00&#xA;C 154.50 263.94 157.04 264.47 160.00 264.00&#xA;C 169.80 261.15 164.14 257.96 165.00 250.00&#xA;C 165.05 249.51 165.00 249.00 165.00 249.00&#xA;C 163.47 246.93 163.50 243.03 165.00 241.00&#xA;C 165.00 240.50 165.00 240.00 165.00 240.00&#xA;C 164.66 236.86 165.54 233.27 166.00 231.00&#xA;C 166.97 226.20 168.52 218.81 172.00 215.00&#xA;C 163.08 216.93 154.33 208.76 146.92 206.08 C 139.50 203.40 129.72 198.14 129.00 189.00&#xA;C 128.94 188.24 129.32 186.68 129.00 186.00&#xA;C 126.69 186.39 128.17 187.06 127.00 185.00&#xA;C 125.33 182.05 124.95 177.75 125.00 174.00&#xA;C 127.20 174.74 124.69 178.33 127.00 179.00&#xA;C 126.92 177.05 125.64 173.65 126.00 172.00&#xA;C 126.57 169.37 130.73 167.21 133.00 167.00&#xA;C 133.50 166.95 134.00 167.00 134.00 167.00&#xA;C 134.67 165.13 137.08 162.88 137.00 163.00&#xA;C 138.55 160.15 138.62 158.02 141.00 155.00&#xA;C 143.80 151.45 148.11 148.46 150.00 147.00&#xA;C 157.03 139.76 167.00 138.77 177.01 136.01 C 187.01 133.25 192.68 124.37 201.00 119.00&#xA;C 204.06 116.44 206.52 113.70 211.00 112.00&#xA;C 216.35 109.98 220.25 109.36 224.00 111.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.97" stroke="#1F1F1F" fill-opacity="0.0" fill="None"><path d="M 211.00 112.00 &#xA;C 207.73 113.57 204.34 116.85 201.00 119.00&#xA;C 192.68 124.37 187.01 133.25 177.01 136.01 C 167.00 138.77 157.03 139.76 150.00 147.00&#xA;C 147.22 149.86 143.35 152.60 141.00 155.00&#xA;C 138.62 158.02 138.55 160.15 137.00 163.00&#xA;C 136.21 164.44 135.13 166.05 134.00 167.00&#xA;C 134.00 167.00 133.50 166.95 133.00 167.00&#xA;C 130.91 168.68 128.16 170.13 126.00 172.00&#xA;C 125.64 173.65 126.92 177.05 127.00 179.00&#xA;C 127.08 180.85 126.54 183.21 127.00 185.00&#xA;C 128.17 187.06 126.69 186.39 129.00 186.00&#xA;C 139.58 184.19 139.28 173.57 145.30 166.30 C 151.33 159.04 159.11 154.07 168.00 152.00&#xA;C 171.54 151.18 174.52 151.23 178.00 152.00&#xA;C 198.43 156.53 210.55 180.87 193.25 196.25 C 175.95 211.63 151.55 202.15 136.00 191.00&#xA;C 134.75 191.30 134.29 192.83 133.00 193.00&#xA;C 141.03 202.59 157.50 209.93 171.00 209.00&#xA;C 165.13 212.19 180.28 209.95 174.00 214.00&#xA;C 171.29 219.69 168.04 225.37 166.00 231.00&#xA;C 165.54 233.27 164.66 236.86 165.00 240.00&#xA;C 167.63 242.52 165.14 247.56 165.00 250.00&#xA;C 164.14 257.96 169.80 261.15 160.00 264.00&#xA;C 157.59 264.70 155.01 265.00 152.00 265.00&#xA;C 151.50 265.00 150.50 265.03 150.00 265.00&#xA;C 147.41 265.74 144.01 265.77 142.00 266.00&#xA;C 136.40 267.32 131.09 269.45 128.00 274.00&#xA;C 126.55 276.13 123.72 279.04 123.00 281.00&#xA;C 121.53 286.73 123.16 291.73 126.00 296.00&#xA;C 129.31 299.51 133.40 300.99 138.00 305.00&#xA;C 139.13 305.57 141.66 305.69 143.00 306.00&#xA;C 147.25 306.00 149.12 302.05 151.77 301.42 C 154.42 300.80 158.84 299.47 163.00 299.00&#xA;C 167.21 298.53 171.76 299.00 176.00 299.00&#xA;C 178.68 299.00 182.08 299.89 184.00 300.00&#xA;C 191.28 299.72 196.47 297.98 203.00 296.00&#xA;C 203.30 297.57 202.75 299.61 201.00 300.00&#xA;C 200.53 300.72 200.61 301.25 200.00 302.00&#xA;C 199.77 302.28 199.18 302.73 199.00 303.00&#xA;C 198.11 304.33 198.19 306.12 198.00 307.00&#xA;C 197.52 309.20 198.55 310.92 196.00 312.00&#xA;C 196.00 312.00 196.00 312.50 196.00 313.00&#xA;C 196.00 313.50 196.00 314.50 196.00 315.00&#xA;C 197.34 318.15 197.00 322.19 197.00 326.00&#xA;C 197.00 327.66 196.94 329.34 197.00 331.00&#xA;C 197.87 341.27 204.18 349.77 210.00 358.00&#xA;C 202.48 358.16 194.80 357.00 188.00 360.00&#xA;C 186.82 360.87 186.62 362.45 185.00 363.00&#xA;C 185.65 362.60 182.90 364.43 184.00 363.00&#xA;C 182.50 363.73 180.03 365.82 179.00 367.00&#xA;C 176.48 370.39 175.83 372.99 175.00 377.00&#xA;C 174.79 379.31 174.51 382.75 175.00 385.00&#xA;C 176.08 388.00 175.90 386.88 178.00 389.00&#xA;C 179.28 389.54 182.52 389.85 184.00 390.00&#xA;C 183.44 380.93 188.33 375.54 195.08 370.08 C 201.83 364.62 214.17 366.00 222.00 367.00 C 229.83 367.99 239.80 375.93 244.00 369.00&#xA;C 233.64 367.84 224.41 364.16 217.25 355.75 C 210.08 347.35 207.42 335.10 208.00 324.00 C 208.58 312.90 214.05 304.64 223.23 298.23 C 232.41 291.82 242.58 289.26 254.01 288.01 C 265.44 286.76 278.78 290.03 288.69 294.31 C 298.61 298.58 302.42 309.65 311.00 311.00&#xA;C 292.98 277.80 244.73 276.83 217.00 297.00&#xA;C 209.30 289.11 224.66 284.69 227.75 277.75 C 230.85 270.82 239.46 258.34 233.00 253.00&#xA;C 230.18 263.89 227.65 272.58 218.75 280.75 C 209.85 288.92 200.91 290.73 188.93 293.93 C 176.95 297.12 160.44 288.18 148.93 296.93 C 137.41 305.67 132.86 287.36 144.08 281.08 C 155.30 274.80 164.62 276.35 175.25 269.25 C 185.88 262.14 188.73 250.71 187.00 238.00&#xA;C 178.32 241.41 187.54 262.01 173.00 263.00&#xA;C 169.98 252.46 170.62 238.53 173.32 228.32 C 176.03 218.12 181.89 210.83 192.22 208.22 C 202.56 205.61 207.52 199.40 214.25 191.25 C 220.99 183.11 213.85 167.29 220.00 162.00&#xA;C 234.12 146.99 229.05 129.74 225.00 114.00&#xA;C 224.85 113.42 224.66 111.92 224.00 111.00&#xA;C 220.25 109.36 216.35 109.98 211.00 112.00&#xA;M 152.00 273.00 &#xA;C 142.20 277.14 131.12 280.81 131.00 294.00&#xA;C 120.27 284.76 135.80 269.65 147.00 272.00&#xA;C 149.02 271.71 152.29 270.15 155.00 271.00&#xA;C 154.45 272.01 153.02 272.44 152.00 273.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.19" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 225.00 114.00 &#xA;C 229.89 122.33 229.91 132.23 232.00 142.00 C 234.08 151.77 221.37 159.93 223.93 168.07 C 226.48 176.22 228.75 187.50 232.00 194.00&#xA;C 235.40 198.53 239.35 201.24 244.00 204.00&#xA;C 237.83 198.83 233.59 191.20 231.33 183.67 C 229.06 176.15 224.84 166.83 229.08 160.08 C 233.32 153.32 236.40 141.18 233.78 133.22 C 231.15 125.27 231.64 114.34 224.00 111.00&#xA;C 224.66 111.92 224.85 113.42 225.00 114.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.09" stroke="#B0B0B0" fill-opacity="0.0" fill="None"><path d="M 201.00 119.00 &#xA;C 204.34 116.85 207.73 113.57 211.00 112.00&#xA;C 206.52 113.70 204.06 116.44 201.00 119.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.48" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 220.00 162.00 &#xA;C 219.66 166.74 225.00 173.64 225.32 178.68 C 225.64 183.72 229.13 190.18 232.00 194.00&#xA;C 228.75 187.50 226.48 176.22 223.93 168.07 C 221.37 159.93 234.08 151.77 232.00 142.00 C 229.91 132.23 229.89 122.33 225.00 114.00&#xA;C 229.05 129.74 234.12 146.99 220.00 162.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.99" stroke="#BEBEBE" fill-opacity="0.0" fill="None"><path d="M 309.00 244.00 &#xA;C 319.62 252.72 326.67 266.01 332.31 278.69 C 337.94 291.38 343.27 312.99 343.00 327.00&#xA;C 348.86 307.69 357.88 289.27 376.00 278.00&#xA;C 375.67 274.36 376.25 270.64 376.00 267.00&#xA;C 374.20 240.59 358.93 215.59 343.00 195.00&#xA;C 335.15 187.46 327.36 178.80 319.00 172.00&#xA;C 311.02 165.51 302.27 161.02 293.75 155.25 C 285.22 149.49 276.61 146.55 268.08 139.92 C 259.55 133.29 246.17 127.28 248.00 141.00 C 249.83 154.72 251.48 162.65 256.69 173.31 C 261.91 183.96 266.05 189.82 272.70 198.30 C 279.34 206.78 283.96 213.48 290.75 221.25 C 297.53 229.03 302.67 236.14 309.00 244.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.13" stroke="#858585" fill-opacity="0.0" fill="None"><path d="M 141.00 155.00 &#xA;C 143.35 152.60 147.22 149.86 150.00 147.00&#xA;C 148.11 148.46 143.80 151.45 141.00 155.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#868686" fill-opacity="0.0" fill="None"><path d="M 168.00 152.00 &#xA;C 171.08 151.66 174.91 151.68 178.00 152.00&#xA;C 174.52 151.23 171.54 151.18 168.00 152.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#F6F6F6" fill-opacity="0.0" fill="None"><path d="M 129.00 186.00 &#xA;C 129.32 186.68 128.94 188.24 129.00 189.00&#xA;C 129.45 190.21 132.14 191.97 133.00 193.00&#xA;C 134.29 192.83 134.75 191.30 136.00 191.00&#xA;C 151.55 202.15 175.95 211.63 193.25 196.25 C 210.55 180.87 198.43 156.53 178.00 152.00&#xA;C 174.91 151.68 171.08 151.66 168.00 152.00&#xA;C 159.11 154.07 151.33 159.04 145.30 166.30 C 139.28 173.57 139.58 184.19 129.00 186.00&#xA;M 175.00 161.00 &#xA;C 186.50 162.02 186.34 180.76 173.98 179.98 C 161.61 179.20 162.30 159.88 175.00 161.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#232323" fill-opacity="0.0" fill="None"><path d="M 175.00 161.00 &#xA;C 162.30 159.88 161.61 179.20 173.98 179.98 C 186.34 180.76 186.50 162.02 175.00 161.00&#xA;M 168.00 171.00 &#xA;C 167.10 158.05 181.72 171.06 168.00 171.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.16" stroke="#A4A4A4" fill-opacity="0.0" fill="None"><path d="M 134.00 167.00 &#xA;C 135.13 166.05 136.21 164.44 137.00 163.00&#xA;C 137.08 162.88 134.67 165.13 134.00 167.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#F8F8F8" fill-opacity="0.0" fill="None"><path d="M 184.00 390.00 &#xA;C 200.03 391.64 215.88 388.64 232.00 390.00 C 248.12 391.37 264.82 388.01 281.00 390.00 C 297.18 391.99 307.70 387.80 321.00 381.00&#xA;C 334.96 366.76 337.54 345.00 343.00 327.00&#xA;C 343.27 312.99 337.94 291.38 332.31 278.69 C 326.67 266.01 319.62 252.72 309.00 244.00&#xA;C 288.30 227.00 266.37 217.28 244.00 204.00&#xA;C 239.35 201.24 235.40 198.53 232.00 194.00&#xA;C 229.13 190.18 225.64 183.72 225.32 178.68 C 225.00 173.64 219.66 166.74 220.00 162.00&#xA;C 213.85 167.29 220.99 183.11 214.25 191.25 C 207.52 199.40 202.56 205.61 192.22 208.22 C 181.89 210.83 176.03 218.12 173.32 228.32 C 170.62 238.53 169.98 252.46 173.00 263.00&#xA;C 187.54 262.01 178.32 241.41 187.00 238.00&#xA;C 188.73 250.71 185.88 262.14 175.25 269.25 C 164.62 276.35 155.30 274.80 144.08 281.08 C 132.86 287.36 137.41 305.67 148.93 296.93 C 160.44 288.18 176.95 297.12 188.93 293.93 C 200.91 290.73 209.85 288.92 218.75 280.75 C 227.65 272.58 230.18 263.89 233.00 253.00&#xA;C 239.46 258.34 230.85 270.82 227.75 277.75 C 224.66 284.69 209.30 289.11 217.00 297.00&#xA;C 244.73 276.83 292.98 277.80 311.00 311.00&#xA;C 302.42 309.65 298.61 298.58 288.69 294.31 C 278.78 290.03 265.44 286.76 254.01 288.01 C 242.58 289.26 232.41 291.82 223.23 298.23 C 214.05 304.64 208.58 312.90 208.00 324.00 C 207.42 335.10 210.08 347.35 217.25 355.75 C 224.41 364.16 233.64 367.84 244.00 369.00&#xA;C 239.80 375.93 229.83 367.99 222.00 367.00 C 214.17 366.00 201.83 364.62 195.08 370.08 C 188.33 375.54 183.44 380.93 184.00 390.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#E7E7E7" fill-opacity="0.0" fill="None"><path d="M 168.00 171.00 &#xA;C 181.72 171.06 167.10 158.05 168.00 171.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.06" stroke="#D5D6D5" fill-opacity="0.0" fill="None"><path d="M 126.00 172.00 &#xA;C 128.16 170.13 130.91 168.68 133.00 167.00&#xA;C 130.73 167.21 126.57 169.37 126.00 172.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.17" stroke="#010101" fill-opacity="0.0" fill="None"><path d="M 319.00 172.00 &#xA;C 327.36 178.80 335.15 187.46 343.00 195.00&#xA;C 349.36 201.12 355.23 207.97 360.00 215.00&#xA;C 351.42 199.09 333.96 180.10 319.00 172.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.19" stroke="#6A6A6A" fill-opacity="0.0" fill="None"><path d="M 127.00 185.00 &#xA;C 126.54 183.21 127.08 180.85 127.00 179.00&#xA;C 124.69 178.33 127.20 174.74 125.00 174.00&#xA;C 124.95 177.75 125.33 182.05 127.00 185.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.26" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 172.00 215.00 &#xA;C 172.45 214.90 173.63 214.23 174.00 214.00&#xA;C 180.28 209.95 165.13 212.19 171.00 209.00&#xA;C 157.50 209.93 141.03 202.59 133.00 193.00&#xA;C 132.14 191.97 129.45 190.21 129.00 189.00&#xA;C 129.72 198.14 139.50 203.40 146.92 206.08 C 154.33 208.76 163.08 216.93 172.00 215.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.33" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 376.00 267.00 &#xA;C 376.19 267.61 376.87 267.94 377.00 269.00&#xA;C 382.28 281.94 376.22 302.91 373.67 315.67 C 371.13 328.44 363.16 341.06 357.08 352.08 C 351.00 363.10 341.62 372.42 331.00 379.00&#xA;C 336.37 377.44 343.03 372.51 348.25 366.25 C 353.47 359.98 358.20 353.62 362.23 346.23 C 366.25 338.84 369.84 331.25 373.02 323.02 C 376.21 314.80 378.11 304.40 379.22 295.22 C 380.34 286.05 381.18 272.54 378.33 263.67 C 375.48 254.80 374.87 244.63 371.77 236.23 C 368.67 227.83 364.03 222.47 360.00 215.00&#xA;C 355.23 207.97 349.36 201.12 343.00 195.00&#xA;C 358.93 215.59 374.20 240.59 376.00 267.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.17" stroke="#8A8A8A" fill-opacity="0.0" fill="None"><path d="M 172.00 215.00 &#xA;C 168.52 218.81 166.97 226.20 166.00 231.00&#xA;C 168.04 225.37 171.29 219.69 174.00 214.00&#xA;C 173.63 214.23 172.45 214.90 172.00 215.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.60" stroke="#101010" fill-opacity="0.0" fill="None"><path d="M 165.00 241.00 &#xA;C 165.00 243.67 165.00 246.33 165.00 249.00&#xA;C 165.00 249.00 165.05 249.51 165.00 250.00&#xA;C 165.14 247.56 167.63 242.52 165.00 240.00&#xA;C 165.00 240.00 165.00 240.50 165.00 241.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.03" stroke="#7E7E7E" fill-opacity="0.0" fill="None"><path d="M 165.00 249.00 &#xA;C 165.00 246.33 165.00 243.67 165.00 241.00&#xA;C 163.50 243.03 163.47 246.93 165.00 249.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.04" stroke="#777777" fill-opacity="0.0" fill="None"><path d="M 152.00 265.00 &#xA;C 155.01 265.00 157.59 264.70 160.00 264.00&#xA;C 157.04 264.47 154.50 263.94 152.00 265.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.29" stroke="#7B7B7B" fill-opacity="0.0" fill="None"><path d="M 142.00 266.00 &#xA;C 144.01 265.77 147.41 265.74 150.00 265.00&#xA;C 147.06 264.79 144.65 265.37 142.00 266.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.68" stroke="#4F4F4F" fill-opacity="0.0" fill="None"><path d="M 376.00 278.00 &#xA;C 376.36 277.78 377.00 278.00 377.00 278.00&#xA;C 377.06 275.10 377.35 271.88 377.00 269.00&#xA;C 376.87 267.94 376.19 267.61 376.00 267.00&#xA;C 376.25 270.64 375.67 274.36 376.00 278.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.46" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 377.00 278.00 &#xA;C 376.24 316.06 358.69 361.73 321.00 381.00&#xA;C 307.70 387.80 297.18 391.99 281.00 390.00 C 264.82 388.01 248.12 391.37 232.00 390.00 C 215.88 388.64 200.03 391.64 184.00 390.00&#xA;C 182.52 389.85 179.28 389.54 178.00 389.00&#xA;C 182.87 396.59 191.77 393.68 200.00 394.00 C 208.23 394.32 218.57 393.90 227.00 394.00 C 235.43 394.10 244.63 394.09 253.00 394.00 C 261.37 393.91 271.99 394.30 280.00 394.00 C 288.01 393.70 299.78 394.82 306.78 393.78 C 313.78 392.73 320.86 388.48 320.00 385.00&#xA;C 324.03 383.93 327.43 381.21 331.00 379.00&#xA;C 341.62 372.42 351.00 363.10 357.08 352.08 C 363.16 341.06 371.13 328.44 373.67 315.67 C 376.22 302.91 382.28 281.94 377.00 269.00&#xA;C 377.35 271.88 377.06 275.10 377.00 278.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#767676" fill-opacity="0.0" fill="None"><path d="M 147.00 272.00 &#xA;C 148.46 272.02 151.35 273.02 152.00 273.00&#xA;C 153.02 272.44 154.45 272.01 155.00 271.00&#xA;C 152.29 270.15 149.02 271.71 147.00 272.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#E3E3E3" fill-opacity="0.0" fill="None"><path d="M 152.00 273.00 &#xA;C 151.35 273.02 148.46 272.02 147.00 272.00&#xA;C 135.80 269.65 120.27 284.76 131.00 294.00&#xA;C 131.12 280.81 142.20 277.14 152.00 273.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.20" stroke="#8E8E8E" fill-opacity="0.0" fill="None"><path d="M 123.00 281.00 &#xA;C 123.72 279.04 126.55 276.13 128.00 274.00&#xA;C 125.91 276.29 123.82 277.81 123.00 281.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.99" stroke="#1D1D1D" fill-opacity="0.0" fill="None"><path d="M 343.00 327.00 &#xA;C 337.54 345.00 334.96 366.76 321.00 381.00&#xA;C 358.69 361.73 376.24 316.06 377.00 278.00&#xA;C 377.00 278.00 376.36 277.78 376.00 278.00&#xA;C 357.88 289.27 348.86 307.69 343.00 327.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.32" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 126.00 296.00 &#xA;C 130.06 302.11 136.93 309.06 145.00 309.00 C 153.07 308.94 160.96 301.21 170.00 303.00 C 179.04 304.79 191.11 300.89 199.00 303.00&#xA;C 199.18 302.73 199.77 302.28 200.00 302.00&#xA;C 197.55 298.03 190.28 303.63 184.00 302.00 C 177.72 300.37 175.48 302.79 166.00 302.00 C 156.52 301.21 146.75 312.62 138.00 305.00&#xA;C 133.40 300.99 129.31 299.51 126.00 296.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.59" stroke="#010101" fill-opacity="0.0" fill="None"><path d="M 184.00 300.00 &#xA;C 181.34 300.10 178.66 300.00 176.00 300.00&#xA;C 171.88 300.00 166.28 298.95 163.00 299.00&#xA;C 158.84 299.47 154.42 300.80 151.77 301.42 C 149.12 302.05 147.25 306.00 143.00 306.00&#xA;C 147.64 307.07 150.96 305.59 155.08 303.08 C 159.19 300.56 165.50 300.79 170.00 301.00 C 174.50 301.21 183.31 300.15 187.00 301.00 C 190.69 301.85 200.07 297.39 201.00 300.00&#xA;C 202.75 299.61 203.30 297.57 203.00 296.00&#xA;C 196.47 297.98 191.28 299.72 184.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.75" stroke="#474747" fill-opacity="0.0" fill="None"><path d="M 176.00 300.00 &#xA;C 175.96 300.00 176.00 299.00 176.00 299.00&#xA;C 171.76 299.00 167.21 298.53 163.00 299.00&#xA;C 166.28 298.95 171.88 300.00 176.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.77" stroke="#090909" fill-opacity="0.0" fill="None"><path d="M 176.00 300.00 &#xA;C 178.66 300.00 181.34 300.10 184.00 300.00&#xA;C 182.08 299.89 178.68 299.00 176.00 299.00&#xA;C 176.00 299.00 175.96 300.00 176.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.44" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 143.00 306.00 &#xA;C 141.66 305.69 139.13 305.57 138.00 305.00&#xA;C 146.75 312.62 156.52 301.21 166.00 302.00 C 175.48 302.79 177.72 300.37 184.00 302.00 C 190.28 303.63 197.55 298.03 200.00 302.00&#xA;C 200.61 301.25 200.53 300.72 201.00 300.00&#xA;C 200.07 297.39 190.69 301.85 187.00 301.00 C 183.31 300.15 174.50 301.21 170.00 301.00 C 165.50 300.79 159.19 300.56 155.08 303.08 C 150.96 305.59 147.64 307.07 143.00 306.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.29" stroke="#757575" fill-opacity="0.0" fill="None"><path d="M 196.00 312.00 &#xA;C 198.55 310.92 197.52 309.20 198.00 307.00&#xA;C 198.29 306.24 196.30 310.37 196.00 312.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.03" stroke="#AEAEAE" fill-opacity="0.0" fill="None"><path d="M 195.00 324.00 &#xA;C 195.00 324.05 196.00 324.00 196.00 324.00&#xA;C 195.64 321.10 196.00 317.92 196.00 315.00&#xA;C 196.00 314.50 196.00 313.50 196.00 313.00&#xA;C 194.25 315.36 194.72 320.78 195.00 324.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.66" stroke="#111111" fill-opacity="0.0" fill="None"><path d="M 196.00 324.00 &#xA;C 196.15 325.26 196.76 325.23 197.00 326.00&#xA;C 197.00 322.19 197.34 318.15 196.00 315.00&#xA;C 196.00 317.92 195.64 321.10 196.00 324.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.26" stroke="#484848" fill-opacity="0.0" fill="None"><path d="M 197.00 331.00 &#xA;C 196.94 329.34 197.00 327.66 197.00 326.00&#xA;C 196.76 325.23 196.15 325.26 196.00 324.00&#xA;C 196.00 324.00 195.00 324.05 195.00 324.00&#xA;C 195.21 326.36 196.59 329.08 197.00 331.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.11" stroke="#B4B4B4" fill-opacity="0.0" fill="None"><path d="M 179.00 367.00 &#xA;C 180.03 365.82 182.50 363.73 184.00 363.00&#xA;C 184.40 362.80 185.00 363.00 185.00 363.00&#xA;C 186.62 362.45 186.82 360.87 188.00 360.00&#xA;C 184.21 361.67 181.54 363.59 179.00 367.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.78" stroke="#0E0E0E" fill-opacity="0.0" fill="None"><path d="M 185.00 363.00 &#xA;C 185.00 363.00 184.40 362.80 184.00 363.00&#xA;C 182.90 364.43 185.65 362.60 185.00 363.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.20" stroke="#868686" fill-opacity="0.0" fill="None"><path d="M 175.00 385.00 &#xA;C 174.51 382.75 174.79 379.31 175.00 377.00&#xA;C 174.40 379.91 173.90 381.94 175.00 385.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.00" fill="#000000">
<path d="M 0.00 500.00 &#xA;L 500.00 500.00&#xA;L 500.00 0.00&#xA;L 0.00 0.00&#xA;L 0.00 500.00&#xA;M 224.00 111.00 &#xA;C 231.64 114.34 231.15 125.27 233.78 133.22 C 236.40 141.18 233.32 153.32 229.08 160.08 C 224.84 166.83 229.06 176.15 231.33 183.67 C 233.59 191.20 237.83 198.83 244.00 204.00&#xA;C 266.37 217.28 288.30 227.00 309.00 244.00&#xA;C 302.67 236.14 297.53 229.03 290.75 221.25 C 283.96 213.48 279.34 206.78 272.70 198.30 C 266.05 189.82 261.91 183.96 256.69 173.31 C 251.48 162.65 249.83 154.72 248.00 141.00 C 246.17 127.28 259.55 133.29 268.08 139.92 C 276.61 146.55 285.22 149.49 293.75 155.25 C 302.27 161.02 311.02 165.51 319.00 172.00&#xA;C 333.96 180.10 351.42 199.09 360.00 215.00&#xA;C 364.03 222.47 368.67 227.83 371.77 236.23 C 374.87 244.63 375.48 254.80 378.33 263.67 C 381.18 272.54 380.34 286.05 379.22 295.22 C 378.11 304.40 376.21 314.80 373.02 323.02 C 369.84 331.25 366.25 338.84 362.23 346.23 C 358.20 353.62 353.47 359.98 348.25 366.25 C 343.03 372.51 336.37 377.44 331.08 379.86&#xA;C 327.43 381.21 324.03 383.93 320.00 385.00&#xA;C 320.86 388.48 313.78 392.73 306.78 393.78 C 299.78 394.82 288.01 393.70 280.00 394.00 C 271.99 394.30 261.37 393.91 253.00 394.00 C 244.63 394.09 235.43 394.10 227.00 394.00 C 218.57 393.90 208.23 394.32 200.00 394.00 C 191.77 393.68 182.87 396.59 178.00 389.00&#xA;C 175.90 386.88 176.08 388.00 175.00 385.00&#xA;C 173.90 381.94 174.40 379.91 175.00 377.00&#xA;C 175.83 372.99 176.48 370.39 179.00 367.00&#xA;C 181.54 363.59 184.21 361.67 188.00 360.00&#xA;C 194.80 357.00 202.48 358.16 210.00 358.00&#xA;C 204.18 349.77 197.87 341.27 197.00 331.00&#xA;C 196.59 329.08 195.21 326.36 195.00 324.00&#xA;C 194.72 320.78 194.25 315.36 196.00 313.00&#xA;C 196.00 312.50 196.00 312.00 196.00 312.00&#xA;C 196.30 310.37 198.29 306.24 198.00 307.00&#xA;C 198.19 306.12 198.11 304.33 199.00 303.00&#xA;C 191.11 300.89 179.04 304.79 170.00 303.00 C 160.96 301.21 153.07 308.94 145.00 309.00 C 136.93 309.06 130.06 302.11 126.00 296.00&#xA;C 123.16 291.73 121.53 286.73 123.00 281.00&#xA;C 123.82 277.81 125.91 276.29 128.00 274.00&#xA;C 131.09 269.45 136.40 267.32 142.00 266.00&#xA;C 144.65 265.37 147.06 264.79 150.00 265.00&#xA;C 150.50 265.03 151.50 265.00 152.00 265.00&#xA;C 154.50 263.94 157.04 264.47 160.00 264.00&#xA;C 169.80 261.15 164.14 257.96 165.00 250.00&#xA;C 165.05 249.51 165.00 249.00 165.00 249.00&#xA;C 163.47 246.93 163.50 243.03 165.00 241.00&#xA;C 165.00 240.50 165.00 240.00 165.00 240.00&#xA;C 164.66 236.86 165.54 233.27 166.00 231.00&#xA;C 166.97 226.20 168.52 218.81 172.00 215.00&#xA;C 163.08 216.93 154.33 208.76 146.92 206.08 C 139.50 203.40 129.72 198.14 129.00 189.00&#xA;C 128.94 188.24 129.32 186.68 129.00 186.00&#xA;C 126.69 186.39 128.17 187.06 127.00 185.00&#xA;C 125.33 182.05 124.95 177.75 125.00 174.00&#xA;C 127.20 174.74 124.69 178.33 127.00 179.00&#xA;C 126.92 177.05 125.64 173.65 126.00 172.00&#xA;C 126.57 169.37 130.73 167.21 133.00 167.00&#xA;C 133.50 166.95 134.00 167.00 134.00 167.00&#xA;C 134.67 165.13 137.08 162.88 137.00 163.00&#xA;C 138.55 160.15 138.62 158.02 141.00 155.00&#xA;C 143.80 151.45 148.11 148.46 150.00 147.00&#xA;C 157.03 139.76 167.00 138.77 177.01 136.01 C 187.01 133.25 192.68 124.37 201.00 119.00&#xA;C 204.06 116.44 206.52 113.70 211.00 112.00&#xA;C 216.35 109.98 220.25 109.36 224.00 111.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.97" fill="#1F1F1F">
<path d="M 211.00 112.00 &#xA;C 207.73 113.57 204.34 116.85 201.00 119.00&#xA;C 192.68 124.37 187.01 133.25 177.01 136.01 C 167.00 138.77 157.03 139.76 150.00 147.00&#xA;C 147.22 149.86 143.35 152.60 141.00 155.00&#xA;C 138.62 158.02 138.55 160.15 137.00 163.00&#xA;C 136.21 164.44 135.13 166.05 134.00 167.00&#xA;C 134.00 167.00 133.50 166.95 133.00 167.00&#xA;C 130.91 168.68 128.16 170.13 126.00 172.00&#xA;C 125.64 173.65 126.92 177.05 127.00 179.00&#xA;C 127.08 180.85 126.54 183.21 127.00 185.00&#xA;C 128.17 187.06 126.69 186.39 129.00 186.00&#xA;C 139.58 184.19 139.28 173.57 145.30 166.30 C 151.33 159.04 159.11 154.07 168.00 152.00&#xA;C 171.54 151.18 174.52 151.23 178.00 152.00&#xA;C 198.43 156.53 210.55 180.87 193.25 196.25 C 175.95 211.63 151.55 202.15 136.00 191.00&#xA;C 134.75 191.30 134.29 192.83 133.00 193.00&#xA;C 141.03 202.59 157.50 209.93 171.00 209.00&#xA;C 165.13 212.19 180.28 209.95 174.00 214.00&#xA;C 171.29 219.69 168.04 225.37 166.00 231.00&#xA;C 165.54 233.27 164.66 236.86 165.00 240.00&#xA;C 167.63 242.52 165.14 247.56 165.00 250.00&#xA;C 164.14 257.96 169.80 261.15 160.00 264.00&#xA;C 157.59 264.70 155.01 265.00 152.00 265.00&#xA;C 151.50 265.00 150.50 265.03 150.00 265.00&#xA;C 147.41 265.74 144.01 265.77 142.00 266.00&#xA;C 136.40 267.32 131.09 269.45 128.00 274.00&#xA;C 126.55 276.13 123.72 279.04 123.00 281.00&#xA;C 121.53 286.73 123.16 291.73 126.00 296.00&#xA;C 129.31 299.51 133.40 300.99 138.00 305.00&#xA;C 139.13 305.57 141.66 305.69 143.00 306.00&#xA;C 147.25 306.00 149.12 302.05 151.77 301.42 C 154.42 300.80 158.84 299.47 163.00 299.00&#xA;C 167.21 298.53 171.76 299.00 176.00 299.00&#xA;C 178.68 299.00 182.08 299.89 184.00 300.00&#xA;C 191.28 299.72 196.47 297.98 203.00 296.00&#xA;C 203.30 297.57 202.75 299.61 201.00 300.00&#xA;C 200.53 300.72 200.61 301.25 200.00 302.00&#xA;C 199.77 302.28 199.18 302.73 199.00 303.00&#xA;C 198.11 304.33 198.19 306.12 198.00 307.00&#xA;C 197.52 309.20 198.55 310.92 196.00 312.00&#xA;C 196.00 312.00 196.00 312.50 196.00 313.00&#xA;C 196.00 313.50 196.00 314.50 196.00 315.00&#xA;C 197.34 318.15 197.00 322.19 197.00 326.00&#xA;C 197.00 327.66 196.94 329.34 197.00 331.00&#xA;C 197.87 341.27 204.18 349.77 210.00 358.00&#xA;C 202.48 358.16 194.80 357.00 188.00 360.00&#xA;C 186.82 360.87 186.62 362.45 185.00 363.00&#xA;C 185.65 362.60 182.90 364.43 184.00 363.00&#xA;C 182.50 363.73 180.03 365.82 179.00 367.00&#xA;C 176.48 370.39 175.83 372.99 175.00 377.00&#xA;C 174.79 379.31 174.51 382.75 175.00 385.00&#xA;C 176.08 388.00 175.90 386.88 178.00 389.00&#xA;C 179.28 389.54 182.52 389.85 184.00 390.00&#xA;C 183.44 380.93 188.33 375.54 195.08 370.08 C 201.83 364.62 214.17 366.00 222.00 367.00 C 229.83 367.99 239.80 375.93 244.00 369.00&#xA;C 233.64 367.84 224.41 364.16 217.25 355.75 C 210.08 347.35 207.42 335.10 208.00 324.00 C 208.58 312.90 214.05 304.64 223.23 298.23 C 232.41 291.82 242.58 289.26 254.01 288.01 C 265.44 286.76 278.78 290.03 288.69 294.31 C 298.61 298.58 302.42 309.65 311.00 311.00&#xA;C 292.98 277.80 244.73 276.83 217.00 297.00&#xA;C 209.30 289.11 224.66 284.69 227.75 277.75 C 230.85 270.82 239.46 258.34 233.00 253.00&#xA;C 230.18 263.89 227.65 272.58 218.75 280.75 C 209.85 288.92 200.91 290.73 188.93 293.93 C 176.95 297.12 160.44 288.18 148.93 296.93 C 137.41 305.67 132.86 287.36 144.08 281.08 C 155.30 274.80 164.62 276.35 175.25 269.25 C 185.88 262.14 188.73 250.71 187.00 238.00&#xA;C 178.32 241.41 187.54 262.01 173.00 263.00&#xA;C 169.98 252.46 170.62 238.53 173.32 228.32 C 176.03 218.12 181.89 210.83 192.22 208.22 C 202.56 205.61 207.52 199.40 214.25 191.25 C 220.99 183.11 213.85 167.29 220.00 162.00&#xA;C 234.12 146.99 229.05 129.74 225.00 114.00&#xA;C 224.85 113.42 224.66 111.92 224.00 111.00&#xA;C 220.25 109.36 216.35 109.98 211.00 112.00&#xA;M 152.00 273.00 &#xA;C 142.20 277.14 131.12 280.81 131.00 294.00&#xA;C 120.27 284.76 135.80 269.65 147.00 272.00&#xA;C 149.02 271.71 152.29 270.15 155.00 271.00&#xA;C 154.45 272.01 153.02 272.44 152.00 273.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.19" fill="#000000">
<path d="M 225.00 114.00 &#xA;C 229.89 122.33 229.91 132.23 232.00 142.00 C 234.08 151.77 221.37 159.93 223.93 168.07 C 226.48 176.22 228.75 187.50 232.00 194.00&#xA;C 235.40 198.53 239.35 201.24 244.00 204.00&#xA;C 237.83 198.83 233.59 191.20 231.33 183.67 C 229.06 176.15 224.84 166.83 229.08 160.08 C 233.32 153.32 236.40 141.18 233.78 133.22 C 231.15 125.27 231.64 114.34 224.00 111.00&#xA;C 224.66 111.92 224.85 113.42 225.00 114.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.09" fill="#B0B0B0">
<path d="M 201.00 119.00 &#xA;C 204.34 116.85 207.73 113.57 211.00 112.00&#xA;C 206.52 113.70 204.06 116.44 201.00 119.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.48" fill="#000000">
<path d="M 220.00 162.00 &#xA;C 219.66 166.74 225.00 173.64 225.32 178.68 C 225.64 183.72 229.13 190.18 232.00 194.00&#xA;C 228.75 187.50 226.48 176.22 223.93 168.07 C 221.37 159.93 234.08 151.77 232.00 142.00 C 229.91 132.23 229.89 122.33 225.00 114.00&#xA;C 229.05 129.74 234.12 146.99 220.00 162.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.99" fill="#BEBEBE">
<path d="M 309.00 244.00 &#xA;C 319.62 252.72 326.67 266.01 332.31 278.69 C 337.94 291.38 343.27 312.99 343.00 327.00&#xA;C 348.86 307.69 357.88 289.27 376.00 278.00&#xA;C 375.67 274.36 376.25 270.64 376.00 267.00&#xA;C 374.20 240.59 358.93 215.59 343.00 195.00&#xA;C 335.15 187.46 327.36 178.80 319.00 172.00&#xA;C 311.02 165.51 302.27 161.02 293.75 155.25 C 285.22 149.49 276.61 146.55 268.08 139.92 C 259.55 133.29 246.17 127.28 248.00 141.00 C 249.83 154.72 251.48 162.65 256.69 173.31 C 261.91 183.96 266.05 189.82 272.70 198.30 C 279.34 206.78 283.96 213.48 290.75 221.25 C 297.53 229.03 302.67 236.14 309.00 244.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.13" fill="#858585">
<path d="M 141.00 155.00 &#xA;C 143.35 152.60 147.22 149.86 150.00 147.00&#xA;C 148.11 148.46 143.80 151.45 141.00 155.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#868686">
<path d="M 168.00 152.00 &#xA;C 171.08 151.66 174.91 151.68 178.00 152.00&#xA;C 174.52 151.23 171.54 151.18 168.00 152.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#F6F6F6">
<path d="M 129.00 186.00 &#xA;C 129.32 186.68 128.94 188.24 129.00 189.00&#xA;C 129.45 190.21 132.14 191.97 133.00 193.00&#xA;C 134.29 192.83 134.75 191.30 136.00 191.00&#xA;C 151.55 202.15 175.95 211.63 193.25 196.25 C 210.55 180.87 198.43 156.53 178.00 152.00&#xA;C 174.91 151.68 171.08 151.66 168.00 152.00&#xA;C 159.11 154.07 151.33 159.04 145.30 166.30 C 139.28 173.57 139.58 184.19 129.00 186.00&#xA;M 175.00 161.00 &#xA;C 186.50 162.02 186.34 180.76 173.98 179.98 C 161.61 179.20 162.30 159.88 175.00 161.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#232323">
<path d="M 175.00 161.00 &#xA;C 162.30 159.88 161.61 179.20 173.98 179.98 C 186.34 180.76 186.50 162.02 175.00 161.00&#xA;M 168.00 171.00 &#xA;C 167.10 158.05 181.72 171.06 168.00 171.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.16" fill="#A4A4A4">
<path d="M 134.00 167.00 &#xA;C 135.13 166.05 136.21 164.44 137.00 163.00&#xA;C 137.08 162.88 134.67 165.13 134.00 167.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#F8F8F8">
<path d="M 184.00 390.00 &#xA;C 200.03 391.64 215.88 388.64 232.00 390.00 C 248.12 391.37 264.82 388.01 281.00 390.00 C 297.18 391.99 307.70 387.80 321.00 381.00&#xA;C 334.96 366.76 337.54 345.00 343.00 327.00&#xA;C 343.27 312.99 337.94 291.38 332.31 278.69 C 326.67 266.01 319.62 252.72 309.00 244.00&#xA;C 288.30 227.00 266.37 217.28 244.00 204.00&#xA;C 239.35 201.24 235.40 198.53 232.00 194.00&#xA;C 229.13 190.18 225.64 183.72 225.32 178.68 C 225.00 173.64 219.66 166.74 220.00 162.00&#xA;C 213.85 167.29 220.99 183.11 214.25 191.25 C 207.52 199.40 202.56 205.61 192.22 208.22 C 181.89 210.83 176.03 218.12 173.32 228.32 C 170.62 238.53 169.98 252.46 173.00 263.00&#xA;C 187.54 262.01 178.32 241.41 187.00 238.00&#xA;C 188.73 250.71 185.88 262.14 175.25 269.25 C 164.62 276.35 155.30 274.80 144.08 281.08 C 132.86 287.36 137.41 305.67 148.93 296.93 C 160.44 288.18 176.95 297.12 188.93 293.93 C 200.91 290.73 209.85 288.92 218.75 280.75 C 227.65 272.58 230.18 263.89 233.00 253.00&#xA;C 239.46 258.34 230.85 270.82 227.75 277.75 C 224.66 284.69 209.30 289.11 217.00 297.00&#xA;C 244.73 276.83 292.98 277.80 311.00 311.00&#xA;C 302.42 309.65 298.61 298.58 288.69 294.31 C 278.78 290.03 265.44 286.76 254.01 288.01 C 242.58 289.26 232.41 291.82 223.23 298.23 C 214.05 304.64 208.58 312.90 208.00 324.00 C 207.42 335.10 210.08 347.35 217.25 355.75 C 224.41 364.16 233.64 367.84 244.00 369.00&#xA;C 239.80 375.93 229.83 367.99 222.00 367.00 C 214.17 366.00 201.83 364.62 195.08 370.08 C 188.33 375.54 183.44 380.93 184.00 390.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#E7E7E7">
<path d="M 168.00 171.00 &#xA;C 181.72 171.06 167.10 158.05 168.00 171.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.06" fill="#D5D6D5">
<path d="M 126.00 172.00 &#xA;C 128.16 170.13 130.91 168.68 133.00 167.00&#xA;C 130.73 167.21 126.57 169.37 126.00 172.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.17" fill="#010101">
<path d="M 319.00 172.00 &#xA;C 327.36 178.80 335.15 187.46 343.00 195.00&#xA;C 349.36 201.12 355.23 207.97 360.00 215.00&#xA;C 351.42 199.09 333.96 180.10 319.00 172.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.19" fill="#6A6A6A">
<path d="M 127.00 185.00 &#xA;C 126.54 183.21 127.08 180.85 127.00 179.00&#xA;C 124.69 178.33 127.20 174.74 125.00 174.00&#xA;C 124.95 177.75 125.33 182.05 127.00 185.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.26" fill="#000000">
<path d="M 172.00 215.00 &#xA;C 172.45 214.90 173.63 214.23 174.00 214.00&#xA;C 180.28 209.95 165.13 212.19 171.00 209.00&#xA;C 157.50 209.93 141.03 202.59 133.00 193.00&#xA;C 132.14 191.97 129.45 190.21 129.00 189.00&#xA;C 129.72 198.14 139.50 203.40 146.92 206.08 C 154.33 208.76 163.08 216.93 172.00 215.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.33" fill="#000000">
<path d="M 376.00 267.00 &#xA;C 376.19 267.61 376.87 267.94 377.00 269.00&#xA;C 382.28 281.94 376.22 302.91 373.67 315.67 C 371.13 328.44 363.16 341.06 357.08 352.08 C 351.00 363.10 341.62 372.42 331.00 379.00&#xA;C 336.37 377.44 343.03 372.51 348.25 366.25 C 353.47 359.98 358.20 353.62 362.23 346.23 C 366.25 338.84 369.84 331.25 373.02 323.02 C 376.21 314.80 378.11 304.40 379.22 295.22 C 380.34 286.05 381.18 272.54 378.33 263.67 C 375.48 254.80 374.87 244.63 371.77 236.23 C 368.67 227.83 364.03 222.47 360.00 215.00&#xA;C 355.23 207.97 349.36 201.12 343.00 195.00&#xA;C 358.93 215.59 374.20 240.59 376.00 267.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.17" fill="#8A8A8A">
<path d="M 172.00 215.00 &#xA;C 168.52 218.81 166.97 226.20 166.00 231.00&#xA;C 168.04 225.37 171.29 219.69 174.00 214.00&#xA;C 173.63 214.23 172.45 214.90 172.00 215.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.60" fill="#101010">
<path d="M 165.00 241.00 &#xA;C 165.00 243.67 165.00 246.33 165.00 249.00&#xA;C 165.00 249.00 165.05 249.51 165.00 250.00&#xA;C 165.14 247.56 167.63 242.52 165.00 240.00&#xA;C 165.00 240.00 165.00 240.50 165.00 241.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.03" fill="#7E7E7E">
<path d="M 165.00 249.00 &#xA;C 165.00 246.33 165.00 243.67 165.00 241.00&#xA;C 163.50 243.03 163.47 246.93 165.00 249.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.04" fill="#777777">
<path d="M 152.00 265.00 &#xA;C 155.01 265.00 157.59 264.70 160.00 264.00&#xA;C 157.04 264.47 154.50 263.94 152.00 265.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.29" fill="#7B7B7B">
<path d="M 142.00 266.00 &#xA;C 144.01 265.77 147.41 265.74 150.00 265.00&#xA;C 147.06 264.79 144.65 265.37 142.00 266.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.68" fill="#4F4F4F">
<path d="M 376.00 278.00 &#xA;C 376.36 277.78 377.00 278.00 377.00 278.00&#xA;C 377.06 275.10 377.35 271.88 377.00 269.00&#xA;C 376.87 267.94 376.19 267.61 376.00 267.00&#xA;C 376.25 270.64 375.67 274.36 376.00 278.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.46" fill="#000000">
<path d="M 377.00 278.00 &#xA;C 376.24 316.06 358.69 361.73 321.00 381.00&#xA;C 307.70 387.80 297.18 391.99 281.00 390.00 C 264.82 388.01 248.12 391.37 232.00 390.00 C 215.88 388.64 200.03 391.64 184.00 390.00&#xA;C 182.52 389.85 179.28 389.54 178.00 389.00&#xA;C 182.87 396.59 191.77 393.68 200.00 394.00 C 208.23 394.32 218.57 393.90 227.00 394.00 C 235.43 394.10 244.63 394.09 253.00 394.00 C 261.37 393.91 271.99 394.30 280.00 394.00 C 288.01 393.70 299.78 394.82 306.78 393.78 C 313.78 392.73 320.86 388.48 320.00 385.00&#xA;C 324.03 383.93 327.43 381.21 331.00 379.00&#xA;C 341.62 372.42 351.00 363.10 357.08 352.08 C 363.16 341.06 371.13 328.44 373.67 315.67 C 376.22 302.91 382.28 281.94 377.00 269.00&#xA;C 377.35 271.88 377.06 275.10 377.00 278.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#767676">
<path d="M 147.00 272.00 &#xA;C 148.46 272.02 151.35 273.02 152.00 273.00&#xA;C 153.02 272.44 154.45 272.01 155.00 271.00&#xA;C 152.29 270.15 149.02 271.71 147.00 272.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#E3E3E3">
<path d="M 152.00 273.00 &#xA;C 151.35 273.02 148.46 272.02 147.00 272.00&#xA;C 135.80 269.65 120.27 284.76 131.00 294.00&#xA;C 131.12 280.81 142.20 277.14 152.00 273.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.20" fill="#8E8E8E">
<path d="M 123.00 281.00 &#xA;C 123.72 279.04 126.55 276.13 128.00 274.00&#xA;C 125.91 276.29 123.82 277.81 123.00 281.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.99" fill="#1D1D1D">
<path d="M 343.00 327.00 &#xA;C 337.54 345.00 334.96 366.76 321.00 381.00&#xA;C 358.69 361.73 376.24 316.06 377.00 278.00&#xA;C 377.00 278.00 376.36 277.78 376.00 278.00&#xA;C 357.88 289.27 348.86 307.69 343.00 327.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.32" fill="#000000">
<path d="M 126.00 296.00 &#xA;C 130.06 302.11 136.93 309.06 145.00 309.00 C 153.07 308.94 160.96 301.21 170.00 303.00 C 179.04 304.79 191.11 300.89 199.00 303.00&#xA;C 199.18 302.73 199.77 302.28 200.00 302.00&#xA;C 197.55 298.03 190.28 303.63 184.00 302.00 C 177.72 300.37 175.48 302.79 166.00 302.00 C 156.52 301.21 146.75 312.62 138.00 305.00&#xA;C 133.40 300.99 129.31 299.51 126.00 296.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.59" fill="#010101">
<path d="M 184.00 300.00 &#xA;C 181.34 300.10 178.66 300.00 176.00 300.00&#xA;C 171.88 300.00 166.28 298.95 163.00 299.00&#xA;C 158.84 299.47 154.42 300.80 151.77 301.42 C 149.12 302.05 147.25 306.00 143.00 306.00&#xA;C 147.64 307.07 150.96 305.59 155.08 303.08 C 159.19 300.56 165.50 300.79 170.00 301.00 C 174.50 301.21 183.31 300.15 187.00 301.00 C 190.69 301.85 200.07 297.39 201.00 300.00&#xA;C 202.75 299.61 203.30 297.57 203.00 296.00&#xA;C 196.47 297.98 191.28 299.72 184.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.75" fill="#474747">
<path d="M 176.00 300.00 &#xA;C 175.96 300.00 176.00 299.00 176.00 299.00&#xA;C 171.76 299.00 167.21 298.53 163.00 299.00&#xA;C 166.28 298.95 171.88 300.00 176.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.77" fill="#090909">
<path d="M 176.00 300.00 &#xA;C 178.66 300.00 181.34 300.10 184.00 300.00&#xA;C 182.08 299.89 178.68 299.00 176.00 299.00&#xA;C 176.00 299.00 175.96 300.00 176.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.44" fill="#000000">
<path d="M 143.00 306.00 &#xA;C 141.66 305.69 139.13 305.57 138.00 305.00&#xA;C 146.75 312.62 156.52 301.21 166.00 302.00 C 175.48 302.79 177.72 300.37 184.00 302.00 C 190.28 303.63 197.55 298.03 200.00 302.00&#xA;C 200.61 301.25 200.53 300.72 201.00 300.00&#xA;C 200.07 297.39 190.69 301.85 187.00 301.00 C 183.31 300.15 174.50 301.21 170.00 301.00 C 165.50 300.79 159.19 300.56 155.08 303.08 C 150.96 305.59 147.64 307.07 143.00 306.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.29" fill="#757575">
<path d="M 196.00 312.00 &#xA;C 198.55 310.92 197.52 309.20 198.00 307.00&#xA;C 198.29 306.24 196.30 310.37 196.00 312.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.03" fill="#AEAEAE">
<path d="M 195.00 324.00 &#xA;C 195.00 324.05 196.00 324.00 196.00 324.00&#xA;C 195.64 321.10 196.00 317.92 196.00 315.00&#xA;C 196.00 314.50 196.00 313.50 196.00 313.00&#xA;C 194.25 315.36 194.72 320.78 195.00 324.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.66" fill="#111111">
<path d="M 196.00 324.00 &#xA;C 196.15 325.26 196.76 325.23 197.00 326.00&#xA;C 197.00 322.19 197.34 318.15 196.00 315.00&#xA;C 196.00 317.92 195.64 321.10 196.00 324.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.26" fill="#484848">
<path d="M 197.00 331.00 &#xA;C 196.94 329.34 197.00 327.66 197.00 326.00&#xA;C 196.76 325.23 196.15 325.26 196.00 324.00&#xA;C 196.00 324.00 195.00 324.05 195.00 324.00&#xA;C 195.21 326.36 196.59 329.08 197.00 331.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.11" fill="#B4B4B4">
<path d="M 179.00 367.00 &#xA;C 180.03 365.82 182.50 363.73 184.00 363.00&#xA;C 184.40 362.80 185.00 363.00 185.00 363.00&#xA;C 186.62 362.45 186.82 360.87 188.00 360.00&#xA;C 184.21 361.67 181.54 363.59 179.00 367.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.78" fill="#0E0E0E">
<path d="M 185.00 363.00 &#xA;C 185.00 363.00 184.40 362.80 184.00 363.00&#xA;C 182.90 364.43 185.65 362.60 185.00 363.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.20" fill="#868686">
<path d="M 175.00 385.00 &#xA;C 174.51 382.75 174.79 379.31 175.00 377.00&#xA;C 174.40 379.91 173.90 381.94 175.00 385.00 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 42 KiB

207
src/public/logo_square.svg Normal file
View File

@ -0,0 +1,207 @@
<svg viewBox="122 107 263 292" xmlns="http://www.w3.org/2000/svg" style="max-height: 500px" width="295" height="295">
<g stroke-width="0.3" stroke-opacity="0.00" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 0.00 500.00 &#xA;L 500.00 500.00&#xA;L 500.00 0.00&#xA;L 0.00 0.00&#xA;L 0.00 500.00&#xA;M 224.00 111.00 &#xA;C 231.64 114.34 231.15 125.27 233.78 133.22 C 236.40 141.18 233.32 153.32 229.08 160.08 C 224.84 166.83 229.06 176.15 231.33 183.67 C 233.59 191.20 237.83 198.83 244.00 204.00&#xA;C 266.37 217.28 288.30 227.00 309.00 244.00&#xA;C 302.67 236.14 297.53 229.03 290.75 221.25 C 283.96 213.48 279.34 206.78 272.70 198.30 C 266.05 189.82 261.91 183.96 256.69 173.31 C 251.48 162.65 249.83 154.72 248.00 141.00 C 246.17 127.28 259.55 133.29 268.08 139.92 C 276.61 146.55 285.22 149.49 293.75 155.25 C 302.27 161.02 311.02 165.51 319.00 172.00&#xA;C 333.96 180.10 351.42 199.09 360.00 215.00&#xA;C 364.03 222.47 368.67 227.83 371.77 236.23 C 374.87 244.63 375.48 254.80 378.33 263.67 C 381.18 272.54 380.34 286.05 379.22 295.22 C 378.11 304.40 376.21 314.80 373.02 323.02 C 369.84 331.25 366.25 338.84 362.23 346.23 C 358.20 353.62 353.47 359.98 348.25 366.25 C 343.03 372.51 336.37 377.44 331.08 379.86&#xA;C 327.43 381.21 324.03 383.93 320.00 385.00&#xA;C 320.86 388.48 313.78 392.73 306.78 393.78 C 299.78 394.82 288.01 393.70 280.00 394.00 C 271.99 394.30 261.37 393.91 253.00 394.00 C 244.63 394.09 235.43 394.10 227.00 394.00 C 218.57 393.90 208.23 394.32 200.00 394.00 C 191.77 393.68 182.87 396.59 178.00 389.00&#xA;C 175.90 386.88 176.08 388.00 175.00 385.00&#xA;C 173.90 381.94 174.40 379.91 175.00 377.00&#xA;C 175.83 372.99 176.48 370.39 179.00 367.00&#xA;C 181.54 363.59 184.21 361.67 188.00 360.00&#xA;C 194.80 357.00 202.48 358.16 210.00 358.00&#xA;C 204.18 349.77 197.87 341.27 197.00 331.00&#xA;C 196.59 329.08 195.21 326.36 195.00 324.00&#xA;C 194.72 320.78 194.25 315.36 196.00 313.00&#xA;C 196.00 312.50 196.00 312.00 196.00 312.00&#xA;C 196.30 310.37 198.29 306.24 198.00 307.00&#xA;C 198.19 306.12 198.11 304.33 199.00 303.00&#xA;C 191.11 300.89 179.04 304.79 170.00 303.00 C 160.96 301.21 153.07 308.94 145.00 309.00 C 136.93 309.06 130.06 302.11 126.00 296.00&#xA;C 123.16 291.73 121.53 286.73 123.00 281.00&#xA;C 123.82 277.81 125.91 276.29 128.00 274.00&#xA;C 131.09 269.45 136.40 267.32 142.00 266.00&#xA;C 144.65 265.37 147.06 264.79 150.00 265.00&#xA;C 150.50 265.03 151.50 265.00 152.00 265.00&#xA;C 154.50 263.94 157.04 264.47 160.00 264.00&#xA;C 169.80 261.15 164.14 257.96 165.00 250.00&#xA;C 165.05 249.51 165.00 249.00 165.00 249.00&#xA;C 163.47 246.93 163.50 243.03 165.00 241.00&#xA;C 165.00 240.50 165.00 240.00 165.00 240.00&#xA;C 164.66 236.86 165.54 233.27 166.00 231.00&#xA;C 166.97 226.20 168.52 218.81 172.00 215.00&#xA;C 163.08 216.93 154.33 208.76 146.92 206.08 C 139.50 203.40 129.72 198.14 129.00 189.00&#xA;C 128.94 188.24 129.32 186.68 129.00 186.00&#xA;C 126.69 186.39 128.17 187.06 127.00 185.00&#xA;C 125.33 182.05 124.95 177.75 125.00 174.00&#xA;C 127.20 174.74 124.69 178.33 127.00 179.00&#xA;C 126.92 177.05 125.64 173.65 126.00 172.00&#xA;C 126.57 169.37 130.73 167.21 133.00 167.00&#xA;C 133.50 166.95 134.00 167.00 134.00 167.00&#xA;C 134.67 165.13 137.08 162.88 137.00 163.00&#xA;C 138.55 160.15 138.62 158.02 141.00 155.00&#xA;C 143.80 151.45 148.11 148.46 150.00 147.00&#xA;C 157.03 139.76 167.00 138.77 177.01 136.01 C 187.01 133.25 192.68 124.37 201.00 119.00&#xA;C 204.06 116.44 206.52 113.70 211.00 112.00&#xA;C 216.35 109.98 220.25 109.36 224.00 111.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.97" stroke="#1F1F1F" fill-opacity="0.0" fill="None"><path d="M 211.00 112.00 &#xA;C 207.73 113.57 204.34 116.85 201.00 119.00&#xA;C 192.68 124.37 187.01 133.25 177.01 136.01 C 167.00 138.77 157.03 139.76 150.00 147.00&#xA;C 147.22 149.86 143.35 152.60 141.00 155.00&#xA;C 138.62 158.02 138.55 160.15 137.00 163.00&#xA;C 136.21 164.44 135.13 166.05 134.00 167.00&#xA;C 134.00 167.00 133.50 166.95 133.00 167.00&#xA;C 130.91 168.68 128.16 170.13 126.00 172.00&#xA;C 125.64 173.65 126.92 177.05 127.00 179.00&#xA;C 127.08 180.85 126.54 183.21 127.00 185.00&#xA;C 128.17 187.06 126.69 186.39 129.00 186.00&#xA;C 139.58 184.19 139.28 173.57 145.30 166.30 C 151.33 159.04 159.11 154.07 168.00 152.00&#xA;C 171.54 151.18 174.52 151.23 178.00 152.00&#xA;C 198.43 156.53 210.55 180.87 193.25 196.25 C 175.95 211.63 151.55 202.15 136.00 191.00&#xA;C 134.75 191.30 134.29 192.83 133.00 193.00&#xA;C 141.03 202.59 157.50 209.93 171.00 209.00&#xA;C 165.13 212.19 180.28 209.95 174.00 214.00&#xA;C 171.29 219.69 168.04 225.37 166.00 231.00&#xA;C 165.54 233.27 164.66 236.86 165.00 240.00&#xA;C 167.63 242.52 165.14 247.56 165.00 250.00&#xA;C 164.14 257.96 169.80 261.15 160.00 264.00&#xA;C 157.59 264.70 155.01 265.00 152.00 265.00&#xA;C 151.50 265.00 150.50 265.03 150.00 265.00&#xA;C 147.41 265.74 144.01 265.77 142.00 266.00&#xA;C 136.40 267.32 131.09 269.45 128.00 274.00&#xA;C 126.55 276.13 123.72 279.04 123.00 281.00&#xA;C 121.53 286.73 123.16 291.73 126.00 296.00&#xA;C 129.31 299.51 133.40 300.99 138.00 305.00&#xA;C 139.13 305.57 141.66 305.69 143.00 306.00&#xA;C 147.25 306.00 149.12 302.05 151.77 301.42 C 154.42 300.80 158.84 299.47 163.00 299.00&#xA;C 167.21 298.53 171.76 299.00 176.00 299.00&#xA;C 178.68 299.00 182.08 299.89 184.00 300.00&#xA;C 191.28 299.72 196.47 297.98 203.00 296.00&#xA;C 203.30 297.57 202.75 299.61 201.00 300.00&#xA;C 200.53 300.72 200.61 301.25 200.00 302.00&#xA;C 199.77 302.28 199.18 302.73 199.00 303.00&#xA;C 198.11 304.33 198.19 306.12 198.00 307.00&#xA;C 197.52 309.20 198.55 310.92 196.00 312.00&#xA;C 196.00 312.00 196.00 312.50 196.00 313.00&#xA;C 196.00 313.50 196.00 314.50 196.00 315.00&#xA;C 197.34 318.15 197.00 322.19 197.00 326.00&#xA;C 197.00 327.66 196.94 329.34 197.00 331.00&#xA;C 197.87 341.27 204.18 349.77 210.00 358.00&#xA;C 202.48 358.16 194.80 357.00 188.00 360.00&#xA;C 186.82 360.87 186.62 362.45 185.00 363.00&#xA;C 185.65 362.60 182.90 364.43 184.00 363.00&#xA;C 182.50 363.73 180.03 365.82 179.00 367.00&#xA;C 176.48 370.39 175.83 372.99 175.00 377.00&#xA;C 174.79 379.31 174.51 382.75 175.00 385.00&#xA;C 176.08 388.00 175.90 386.88 178.00 389.00&#xA;C 179.28 389.54 182.52 389.85 184.00 390.00&#xA;C 183.44 380.93 188.33 375.54 195.08 370.08 C 201.83 364.62 214.17 366.00 222.00 367.00 C 229.83 367.99 239.80 375.93 244.00 369.00&#xA;C 233.64 367.84 224.41 364.16 217.25 355.75 C 210.08 347.35 207.42 335.10 208.00 324.00 C 208.58 312.90 214.05 304.64 223.23 298.23 C 232.41 291.82 242.58 289.26 254.01 288.01 C 265.44 286.76 278.78 290.03 288.69 294.31 C 298.61 298.58 302.42 309.65 311.00 311.00&#xA;C 292.98 277.80 244.73 276.83 217.00 297.00&#xA;C 209.30 289.11 224.66 284.69 227.75 277.75 C 230.85 270.82 239.46 258.34 233.00 253.00&#xA;C 230.18 263.89 227.65 272.58 218.75 280.75 C 209.85 288.92 200.91 290.73 188.93 293.93 C 176.95 297.12 160.44 288.18 148.93 296.93 C 137.41 305.67 132.86 287.36 144.08 281.08 C 155.30 274.80 164.62 276.35 175.25 269.25 C 185.88 262.14 188.73 250.71 187.00 238.00&#xA;C 178.32 241.41 187.54 262.01 173.00 263.00&#xA;C 169.98 252.46 170.62 238.53 173.32 228.32 C 176.03 218.12 181.89 210.83 192.22 208.22 C 202.56 205.61 207.52 199.40 214.25 191.25 C 220.99 183.11 213.85 167.29 220.00 162.00&#xA;C 234.12 146.99 229.05 129.74 225.00 114.00&#xA;C 224.85 113.42 224.66 111.92 224.00 111.00&#xA;C 220.25 109.36 216.35 109.98 211.00 112.00&#xA;M 152.00 273.00 &#xA;C 142.20 277.14 131.12 280.81 131.00 294.00&#xA;C 120.27 284.76 135.80 269.65 147.00 272.00&#xA;C 149.02 271.71 152.29 270.15 155.00 271.00&#xA;C 154.45 272.01 153.02 272.44 152.00 273.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.19" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 225.00 114.00 &#xA;C 229.89 122.33 229.91 132.23 232.00 142.00 C 234.08 151.77 221.37 159.93 223.93 168.07 C 226.48 176.22 228.75 187.50 232.00 194.00&#xA;C 235.40 198.53 239.35 201.24 244.00 204.00&#xA;C 237.83 198.83 233.59 191.20 231.33 183.67 C 229.06 176.15 224.84 166.83 229.08 160.08 C 233.32 153.32 236.40 141.18 233.78 133.22 C 231.15 125.27 231.64 114.34 224.00 111.00&#xA;C 224.66 111.92 224.85 113.42 225.00 114.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.09" stroke="#B0B0B0" fill-opacity="0.0" fill="None"><path d="M 201.00 119.00 &#xA;C 204.34 116.85 207.73 113.57 211.00 112.00&#xA;C 206.52 113.70 204.06 116.44 201.00 119.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.48" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 220.00 162.00 &#xA;C 219.66 166.74 225.00 173.64 225.32 178.68 C 225.64 183.72 229.13 190.18 232.00 194.00&#xA;C 228.75 187.50 226.48 176.22 223.93 168.07 C 221.37 159.93 234.08 151.77 232.00 142.00 C 229.91 132.23 229.89 122.33 225.00 114.00&#xA;C 229.05 129.74 234.12 146.99 220.00 162.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.99" stroke="#BEBEBE" fill-opacity="0.0" fill="None"><path d="M 309.00 244.00 &#xA;C 319.62 252.72 326.67 266.01 332.31 278.69 C 337.94 291.38 343.27 312.99 343.00 327.00&#xA;C 348.86 307.69 357.88 289.27 376.00 278.00&#xA;C 375.67 274.36 376.25 270.64 376.00 267.00&#xA;C 374.20 240.59 358.93 215.59 343.00 195.00&#xA;C 335.15 187.46 327.36 178.80 319.00 172.00&#xA;C 311.02 165.51 302.27 161.02 293.75 155.25 C 285.22 149.49 276.61 146.55 268.08 139.92 C 259.55 133.29 246.17 127.28 248.00 141.00 C 249.83 154.72 251.48 162.65 256.69 173.31 C 261.91 183.96 266.05 189.82 272.70 198.30 C 279.34 206.78 283.96 213.48 290.75 221.25 C 297.53 229.03 302.67 236.14 309.00 244.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.13" stroke="#858585" fill-opacity="0.0" fill="None"><path d="M 141.00 155.00 &#xA;C 143.35 152.60 147.22 149.86 150.00 147.00&#xA;C 148.11 148.46 143.80 151.45 141.00 155.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#868686" fill-opacity="0.0" fill="None"><path d="M 168.00 152.00 &#xA;C 171.08 151.66 174.91 151.68 178.00 152.00&#xA;C 174.52 151.23 171.54 151.18 168.00 152.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#F6F6F6" fill-opacity="0.0" fill="None"><path d="M 129.00 186.00 &#xA;C 129.32 186.68 128.94 188.24 129.00 189.00&#xA;C 129.45 190.21 132.14 191.97 133.00 193.00&#xA;C 134.29 192.83 134.75 191.30 136.00 191.00&#xA;C 151.55 202.15 175.95 211.63 193.25 196.25 C 210.55 180.87 198.43 156.53 178.00 152.00&#xA;C 174.91 151.68 171.08 151.66 168.00 152.00&#xA;C 159.11 154.07 151.33 159.04 145.30 166.30 C 139.28 173.57 139.58 184.19 129.00 186.00&#xA;M 175.00 161.00 &#xA;C 186.50 162.02 186.34 180.76 173.98 179.98 C 161.61 179.20 162.30 159.88 175.00 161.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#232323" fill-opacity="0.0" fill="None"><path d="M 175.00 161.00 &#xA;C 162.30 159.88 161.61 179.20 173.98 179.98 C 186.34 180.76 186.50 162.02 175.00 161.00&#xA;M 168.00 171.00 &#xA;C 167.10 158.05 181.72 171.06 168.00 171.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.16" stroke="#A4A4A4" fill-opacity="0.0" fill="None"><path d="M 134.00 167.00 &#xA;C 135.13 166.05 136.21 164.44 137.00 163.00&#xA;C 137.08 162.88 134.67 165.13 134.00 167.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#F8F8F8" fill-opacity="0.0" fill="None"><path d="M 184.00 390.00 &#xA;C 200.03 391.64 215.88 388.64 232.00 390.00 C 248.12 391.37 264.82 388.01 281.00 390.00 C 297.18 391.99 307.70 387.80 321.00 381.00&#xA;C 334.96 366.76 337.54 345.00 343.00 327.00&#xA;C 343.27 312.99 337.94 291.38 332.31 278.69 C 326.67 266.01 319.62 252.72 309.00 244.00&#xA;C 288.30 227.00 266.37 217.28 244.00 204.00&#xA;C 239.35 201.24 235.40 198.53 232.00 194.00&#xA;C 229.13 190.18 225.64 183.72 225.32 178.68 C 225.00 173.64 219.66 166.74 220.00 162.00&#xA;C 213.85 167.29 220.99 183.11 214.25 191.25 C 207.52 199.40 202.56 205.61 192.22 208.22 C 181.89 210.83 176.03 218.12 173.32 228.32 C 170.62 238.53 169.98 252.46 173.00 263.00&#xA;C 187.54 262.01 178.32 241.41 187.00 238.00&#xA;C 188.73 250.71 185.88 262.14 175.25 269.25 C 164.62 276.35 155.30 274.80 144.08 281.08 C 132.86 287.36 137.41 305.67 148.93 296.93 C 160.44 288.18 176.95 297.12 188.93 293.93 C 200.91 290.73 209.85 288.92 218.75 280.75 C 227.65 272.58 230.18 263.89 233.00 253.00&#xA;C 239.46 258.34 230.85 270.82 227.75 277.75 C 224.66 284.69 209.30 289.11 217.00 297.00&#xA;C 244.73 276.83 292.98 277.80 311.00 311.00&#xA;C 302.42 309.65 298.61 298.58 288.69 294.31 C 278.78 290.03 265.44 286.76 254.01 288.01 C 242.58 289.26 232.41 291.82 223.23 298.23 C 214.05 304.64 208.58 312.90 208.00 324.00 C 207.42 335.10 210.08 347.35 217.25 355.75 C 224.41 364.16 233.64 367.84 244.00 369.00&#xA;C 239.80 375.93 229.83 367.99 222.00 367.00 C 214.17 366.00 201.83 364.62 195.08 370.08 C 188.33 375.54 183.44 380.93 184.00 390.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#E7E7E7" fill-opacity="0.0" fill="None"><path d="M 168.00 171.00 &#xA;C 181.72 171.06 167.10 158.05 168.00 171.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.06" stroke="#D5D6D5" fill-opacity="0.0" fill="None"><path d="M 126.00 172.00 &#xA;C 128.16 170.13 130.91 168.68 133.00 167.00&#xA;C 130.73 167.21 126.57 169.37 126.00 172.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.17" stroke="#010101" fill-opacity="0.0" fill="None"><path d="M 319.00 172.00 &#xA;C 327.36 178.80 335.15 187.46 343.00 195.00&#xA;C 349.36 201.12 355.23 207.97 360.00 215.00&#xA;C 351.42 199.09 333.96 180.10 319.00 172.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.19" stroke="#6A6A6A" fill-opacity="0.0" fill="None"><path d="M 127.00 185.00 &#xA;C 126.54 183.21 127.08 180.85 127.00 179.00&#xA;C 124.69 178.33 127.20 174.74 125.00 174.00&#xA;C 124.95 177.75 125.33 182.05 127.00 185.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.26" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 172.00 215.00 &#xA;C 172.45 214.90 173.63 214.23 174.00 214.00&#xA;C 180.28 209.95 165.13 212.19 171.00 209.00&#xA;C 157.50 209.93 141.03 202.59 133.00 193.00&#xA;C 132.14 191.97 129.45 190.21 129.00 189.00&#xA;C 129.72 198.14 139.50 203.40 146.92 206.08 C 154.33 208.76 163.08 216.93 172.00 215.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.33" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 376.00 267.00 &#xA;C 376.19 267.61 376.87 267.94 377.00 269.00&#xA;C 382.28 281.94 376.22 302.91 373.67 315.67 C 371.13 328.44 363.16 341.06 357.08 352.08 C 351.00 363.10 341.62 372.42 331.00 379.00&#xA;C 336.37 377.44 343.03 372.51 348.25 366.25 C 353.47 359.98 358.20 353.62 362.23 346.23 C 366.25 338.84 369.84 331.25 373.02 323.02 C 376.21 314.80 378.11 304.40 379.22 295.22 C 380.34 286.05 381.18 272.54 378.33 263.67 C 375.48 254.80 374.87 244.63 371.77 236.23 C 368.67 227.83 364.03 222.47 360.00 215.00&#xA;C 355.23 207.97 349.36 201.12 343.00 195.00&#xA;C 358.93 215.59 374.20 240.59 376.00 267.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.17" stroke="#8A8A8A" fill-opacity="0.0" fill="None"><path d="M 172.00 215.00 &#xA;C 168.52 218.81 166.97 226.20 166.00 231.00&#xA;C 168.04 225.37 171.29 219.69 174.00 214.00&#xA;C 173.63 214.23 172.45 214.90 172.00 215.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.60" stroke="#101010" fill-opacity="0.0" fill="None"><path d="M 165.00 241.00 &#xA;C 165.00 243.67 165.00 246.33 165.00 249.00&#xA;C 165.00 249.00 165.05 249.51 165.00 250.00&#xA;C 165.14 247.56 167.63 242.52 165.00 240.00&#xA;C 165.00 240.00 165.00 240.50 165.00 241.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.03" stroke="#7E7E7E" fill-opacity="0.0" fill="None"><path d="M 165.00 249.00 &#xA;C 165.00 246.33 165.00 243.67 165.00 241.00&#xA;C 163.50 243.03 163.47 246.93 165.00 249.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.04" stroke="#777777" fill-opacity="0.0" fill="None"><path d="M 152.00 265.00 &#xA;C 155.01 265.00 157.59 264.70 160.00 264.00&#xA;C 157.04 264.47 154.50 263.94 152.00 265.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.29" stroke="#7B7B7B" fill-opacity="0.0" fill="None"><path d="M 142.00 266.00 &#xA;C 144.01 265.77 147.41 265.74 150.00 265.00&#xA;C 147.06 264.79 144.65 265.37 142.00 266.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.68" stroke="#4F4F4F" fill-opacity="0.0" fill="None"><path d="M 376.00 278.00 &#xA;C 376.36 277.78 377.00 278.00 377.00 278.00&#xA;C 377.06 275.10 377.35 271.88 377.00 269.00&#xA;C 376.87 267.94 376.19 267.61 376.00 267.00&#xA;C 376.25 270.64 375.67 274.36 376.00 278.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.46" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 377.00 278.00 &#xA;C 376.24 316.06 358.69 361.73 321.00 381.00&#xA;C 307.70 387.80 297.18 391.99 281.00 390.00 C 264.82 388.01 248.12 391.37 232.00 390.00 C 215.88 388.64 200.03 391.64 184.00 390.00&#xA;C 182.52 389.85 179.28 389.54 178.00 389.00&#xA;C 182.87 396.59 191.77 393.68 200.00 394.00 C 208.23 394.32 218.57 393.90 227.00 394.00 C 235.43 394.10 244.63 394.09 253.00 394.00 C 261.37 393.91 271.99 394.30 280.00 394.00 C 288.01 393.70 299.78 394.82 306.78 393.78 C 313.78 392.73 320.86 388.48 320.00 385.00&#xA;C 324.03 383.93 327.43 381.21 331.00 379.00&#xA;C 341.62 372.42 351.00 363.10 357.08 352.08 C 363.16 341.06 371.13 328.44 373.67 315.67 C 376.22 302.91 382.28 281.94 377.00 269.00&#xA;C 377.35 271.88 377.06 275.10 377.00 278.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#767676" fill-opacity="0.0" fill="None"><path d="M 147.00 272.00 &#xA;C 148.46 272.02 151.35 273.02 152.00 273.00&#xA;C 153.02 272.44 154.45 272.01 155.00 271.00&#xA;C 152.29 270.15 149.02 271.71 147.00 272.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="1.00" stroke="#E3E3E3" fill-opacity="0.0" fill="None"><path d="M 152.00 273.00 &#xA;C 151.35 273.02 148.46 272.02 147.00 272.00&#xA;C 135.80 269.65 120.27 284.76 131.00 294.00&#xA;C 131.12 280.81 142.20 277.14 152.00 273.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.20" stroke="#8E8E8E" fill-opacity="0.0" fill="None"><path d="M 123.00 281.00 &#xA;C 123.72 279.04 126.55 276.13 128.00 274.00&#xA;C 125.91 276.29 123.82 277.81 123.00 281.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.99" stroke="#1D1D1D" fill-opacity="0.0" fill="None"><path d="M 343.00 327.00 &#xA;C 337.54 345.00 334.96 366.76 321.00 381.00&#xA;C 358.69 361.73 376.24 316.06 377.00 278.00&#xA;C 377.00 278.00 376.36 277.78 376.00 278.00&#xA;C 357.88 289.27 348.86 307.69 343.00 327.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.32" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 126.00 296.00 &#xA;C 130.06 302.11 136.93 309.06 145.00 309.00 C 153.07 308.94 160.96 301.21 170.00 303.00 C 179.04 304.79 191.11 300.89 199.00 303.00&#xA;C 199.18 302.73 199.77 302.28 200.00 302.00&#xA;C 197.55 298.03 190.28 303.63 184.00 302.00 C 177.72 300.37 175.48 302.79 166.00 302.00 C 156.52 301.21 146.75 312.62 138.00 305.00&#xA;C 133.40 300.99 129.31 299.51 126.00 296.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.59" stroke="#010101" fill-opacity="0.0" fill="None"><path d="M 184.00 300.00 &#xA;C 181.34 300.10 178.66 300.00 176.00 300.00&#xA;C 171.88 300.00 166.28 298.95 163.00 299.00&#xA;C 158.84 299.47 154.42 300.80 151.77 301.42 C 149.12 302.05 147.25 306.00 143.00 306.00&#xA;C 147.64 307.07 150.96 305.59 155.08 303.08 C 159.19 300.56 165.50 300.79 170.00 301.00 C 174.50 301.21 183.31 300.15 187.00 301.00 C 190.69 301.85 200.07 297.39 201.00 300.00&#xA;C 202.75 299.61 203.30 297.57 203.00 296.00&#xA;C 196.47 297.98 191.28 299.72 184.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.75" stroke="#474747" fill-opacity="0.0" fill="None"><path d="M 176.00 300.00 &#xA;C 175.96 300.00 176.00 299.00 176.00 299.00&#xA;C 171.76 299.00 167.21 298.53 163.00 299.00&#xA;C 166.28 298.95 171.88 300.00 176.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.77" stroke="#090909" fill-opacity="0.0" fill="None"><path d="M 176.00 300.00 &#xA;C 178.66 300.00 181.34 300.10 184.00 300.00&#xA;C 182.08 299.89 178.68 299.00 176.00 299.00&#xA;C 176.00 299.00 175.96 300.00 176.00 300.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.44" stroke="#000000" fill-opacity="0.0" fill="None"><path d="M 143.00 306.00 &#xA;C 141.66 305.69 139.13 305.57 138.00 305.00&#xA;C 146.75 312.62 156.52 301.21 166.00 302.00 C 175.48 302.79 177.72 300.37 184.00 302.00 C 190.28 303.63 197.55 298.03 200.00 302.00&#xA;C 200.61 301.25 200.53 300.72 201.00 300.00&#xA;C 200.07 297.39 190.69 301.85 187.00 301.00 C 183.31 300.15 174.50 301.21 170.00 301.00 C 165.50 300.79 159.19 300.56 155.08 303.08 C 150.96 305.59 147.64 307.07 143.00 306.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.29" stroke="#757575" fill-opacity="0.0" fill="None"><path d="M 196.00 312.00 &#xA;C 198.55 310.92 197.52 309.20 198.00 307.00&#xA;C 198.29 306.24 196.30 310.37 196.00 312.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.03" stroke="#AEAEAE" fill-opacity="0.0" fill="None"><path d="M 195.00 324.00 &#xA;C 195.00 324.05 196.00 324.00 196.00 324.00&#xA;C 195.64 321.10 196.00 317.92 196.00 315.00&#xA;C 196.00 314.50 196.00 313.50 196.00 313.00&#xA;C 194.25 315.36 194.72 320.78 195.00 324.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.66" stroke="#111111" fill-opacity="0.0" fill="None"><path d="M 196.00 324.00 &#xA;C 196.15 325.26 196.76 325.23 197.00 326.00&#xA;C 197.00 322.19 197.34 318.15 196.00 315.00&#xA;C 196.00 317.92 195.64 321.10 196.00 324.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.26" stroke="#484848" fill-opacity="0.0" fill="None"><path d="M 197.00 331.00 &#xA;C 196.94 329.34 197.00 327.66 197.00 326.00&#xA;C 196.76 325.23 196.15 325.26 196.00 324.00&#xA;C 196.00 324.00 195.00 324.05 195.00 324.00&#xA;C 195.21 326.36 196.59 329.08 197.00 331.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.11" stroke="#B4B4B4" fill-opacity="0.0" fill="None"><path d="M 179.00 367.00 &#xA;C 180.03 365.82 182.50 363.73 184.00 363.00&#xA;C 184.40 362.80 185.00 363.00 185.00 363.00&#xA;C 186.62 362.45 186.82 360.87 188.00 360.00&#xA;C 184.21 361.67 181.54 363.59 179.00 367.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.78" stroke="#0E0E0E" fill-opacity="0.0" fill="None"><path d="M 185.00 363.00 &#xA;C 185.00 363.00 184.40 362.80 184.00 363.00&#xA;C 182.90 364.43 185.65 362.60 185.00 363.00 Z"/>
</g>
<g stroke-width="0.3" stroke-opacity="0.20" stroke="#868686" fill-opacity="0.0" fill="None"><path d="M 175.00 385.00 &#xA;C 174.51 382.75 174.79 379.31 175.00 377.00&#xA;C 174.40 379.91 173.90 381.94 175.00 385.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.00" fill="#000000">
<path d="M 0.00 500.00 &#xA;L 500.00 500.00&#xA;L 500.00 0.00&#xA;L 0.00 0.00&#xA;L 0.00 500.00&#xA;M 224.00 111.00 &#xA;C 231.64 114.34 231.15 125.27 233.78 133.22 C 236.40 141.18 233.32 153.32 229.08 160.08 C 224.84 166.83 229.06 176.15 231.33 183.67 C 233.59 191.20 237.83 198.83 244.00 204.00&#xA;C 266.37 217.28 288.30 227.00 309.00 244.00&#xA;C 302.67 236.14 297.53 229.03 290.75 221.25 C 283.96 213.48 279.34 206.78 272.70 198.30 C 266.05 189.82 261.91 183.96 256.69 173.31 C 251.48 162.65 249.83 154.72 248.00 141.00 C 246.17 127.28 259.55 133.29 268.08 139.92 C 276.61 146.55 285.22 149.49 293.75 155.25 C 302.27 161.02 311.02 165.51 319.00 172.00&#xA;C 333.96 180.10 351.42 199.09 360.00 215.00&#xA;C 364.03 222.47 368.67 227.83 371.77 236.23 C 374.87 244.63 375.48 254.80 378.33 263.67 C 381.18 272.54 380.34 286.05 379.22 295.22 C 378.11 304.40 376.21 314.80 373.02 323.02 C 369.84 331.25 366.25 338.84 362.23 346.23 C 358.20 353.62 353.47 359.98 348.25 366.25 C 343.03 372.51 336.37 377.44 331.08 379.86&#xA;C 327.43 381.21 324.03 383.93 320.00 385.00&#xA;C 320.86 388.48 313.78 392.73 306.78 393.78 C 299.78 394.82 288.01 393.70 280.00 394.00 C 271.99 394.30 261.37 393.91 253.00 394.00 C 244.63 394.09 235.43 394.10 227.00 394.00 C 218.57 393.90 208.23 394.32 200.00 394.00 C 191.77 393.68 182.87 396.59 178.00 389.00&#xA;C 175.90 386.88 176.08 388.00 175.00 385.00&#xA;C 173.90 381.94 174.40 379.91 175.00 377.00&#xA;C 175.83 372.99 176.48 370.39 179.00 367.00&#xA;C 181.54 363.59 184.21 361.67 188.00 360.00&#xA;C 194.80 357.00 202.48 358.16 210.00 358.00&#xA;C 204.18 349.77 197.87 341.27 197.00 331.00&#xA;C 196.59 329.08 195.21 326.36 195.00 324.00&#xA;C 194.72 320.78 194.25 315.36 196.00 313.00&#xA;C 196.00 312.50 196.00 312.00 196.00 312.00&#xA;C 196.30 310.37 198.29 306.24 198.00 307.00&#xA;C 198.19 306.12 198.11 304.33 199.00 303.00&#xA;C 191.11 300.89 179.04 304.79 170.00 303.00 C 160.96 301.21 153.07 308.94 145.00 309.00 C 136.93 309.06 130.06 302.11 126.00 296.00&#xA;C 123.16 291.73 121.53 286.73 123.00 281.00&#xA;C 123.82 277.81 125.91 276.29 128.00 274.00&#xA;C 131.09 269.45 136.40 267.32 142.00 266.00&#xA;C 144.65 265.37 147.06 264.79 150.00 265.00&#xA;C 150.50 265.03 151.50 265.00 152.00 265.00&#xA;C 154.50 263.94 157.04 264.47 160.00 264.00&#xA;C 169.80 261.15 164.14 257.96 165.00 250.00&#xA;C 165.05 249.51 165.00 249.00 165.00 249.00&#xA;C 163.47 246.93 163.50 243.03 165.00 241.00&#xA;C 165.00 240.50 165.00 240.00 165.00 240.00&#xA;C 164.66 236.86 165.54 233.27 166.00 231.00&#xA;C 166.97 226.20 168.52 218.81 172.00 215.00&#xA;C 163.08 216.93 154.33 208.76 146.92 206.08 C 139.50 203.40 129.72 198.14 129.00 189.00&#xA;C 128.94 188.24 129.32 186.68 129.00 186.00&#xA;C 126.69 186.39 128.17 187.06 127.00 185.00&#xA;C 125.33 182.05 124.95 177.75 125.00 174.00&#xA;C 127.20 174.74 124.69 178.33 127.00 179.00&#xA;C 126.92 177.05 125.64 173.65 126.00 172.00&#xA;C 126.57 169.37 130.73 167.21 133.00 167.00&#xA;C 133.50 166.95 134.00 167.00 134.00 167.00&#xA;C 134.67 165.13 137.08 162.88 137.00 163.00&#xA;C 138.55 160.15 138.62 158.02 141.00 155.00&#xA;C 143.80 151.45 148.11 148.46 150.00 147.00&#xA;C 157.03 139.76 167.00 138.77 177.01 136.01 C 187.01 133.25 192.68 124.37 201.00 119.00&#xA;C 204.06 116.44 206.52 113.70 211.00 112.00&#xA;C 216.35 109.98 220.25 109.36 224.00 111.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.97" fill="#1F1F1F">
<path d="M 211.00 112.00 &#xA;C 207.73 113.57 204.34 116.85 201.00 119.00&#xA;C 192.68 124.37 187.01 133.25 177.01 136.01 C 167.00 138.77 157.03 139.76 150.00 147.00&#xA;C 147.22 149.86 143.35 152.60 141.00 155.00&#xA;C 138.62 158.02 138.55 160.15 137.00 163.00&#xA;C 136.21 164.44 135.13 166.05 134.00 167.00&#xA;C 134.00 167.00 133.50 166.95 133.00 167.00&#xA;C 130.91 168.68 128.16 170.13 126.00 172.00&#xA;C 125.64 173.65 126.92 177.05 127.00 179.00&#xA;C 127.08 180.85 126.54 183.21 127.00 185.00&#xA;C 128.17 187.06 126.69 186.39 129.00 186.00&#xA;C 139.58 184.19 139.28 173.57 145.30 166.30 C 151.33 159.04 159.11 154.07 168.00 152.00&#xA;C 171.54 151.18 174.52 151.23 178.00 152.00&#xA;C 198.43 156.53 210.55 180.87 193.25 196.25 C 175.95 211.63 151.55 202.15 136.00 191.00&#xA;C 134.75 191.30 134.29 192.83 133.00 193.00&#xA;C 141.03 202.59 157.50 209.93 171.00 209.00&#xA;C 165.13 212.19 180.28 209.95 174.00 214.00&#xA;C 171.29 219.69 168.04 225.37 166.00 231.00&#xA;C 165.54 233.27 164.66 236.86 165.00 240.00&#xA;C 167.63 242.52 165.14 247.56 165.00 250.00&#xA;C 164.14 257.96 169.80 261.15 160.00 264.00&#xA;C 157.59 264.70 155.01 265.00 152.00 265.00&#xA;C 151.50 265.00 150.50 265.03 150.00 265.00&#xA;C 147.41 265.74 144.01 265.77 142.00 266.00&#xA;C 136.40 267.32 131.09 269.45 128.00 274.00&#xA;C 126.55 276.13 123.72 279.04 123.00 281.00&#xA;C 121.53 286.73 123.16 291.73 126.00 296.00&#xA;C 129.31 299.51 133.40 300.99 138.00 305.00&#xA;C 139.13 305.57 141.66 305.69 143.00 306.00&#xA;C 147.25 306.00 149.12 302.05 151.77 301.42 C 154.42 300.80 158.84 299.47 163.00 299.00&#xA;C 167.21 298.53 171.76 299.00 176.00 299.00&#xA;C 178.68 299.00 182.08 299.89 184.00 300.00&#xA;C 191.28 299.72 196.47 297.98 203.00 296.00&#xA;C 203.30 297.57 202.75 299.61 201.00 300.00&#xA;C 200.53 300.72 200.61 301.25 200.00 302.00&#xA;C 199.77 302.28 199.18 302.73 199.00 303.00&#xA;C 198.11 304.33 198.19 306.12 198.00 307.00&#xA;C 197.52 309.20 198.55 310.92 196.00 312.00&#xA;C 196.00 312.00 196.00 312.50 196.00 313.00&#xA;C 196.00 313.50 196.00 314.50 196.00 315.00&#xA;C 197.34 318.15 197.00 322.19 197.00 326.00&#xA;C 197.00 327.66 196.94 329.34 197.00 331.00&#xA;C 197.87 341.27 204.18 349.77 210.00 358.00&#xA;C 202.48 358.16 194.80 357.00 188.00 360.00&#xA;C 186.82 360.87 186.62 362.45 185.00 363.00&#xA;C 185.65 362.60 182.90 364.43 184.00 363.00&#xA;C 182.50 363.73 180.03 365.82 179.00 367.00&#xA;C 176.48 370.39 175.83 372.99 175.00 377.00&#xA;C 174.79 379.31 174.51 382.75 175.00 385.00&#xA;C 176.08 388.00 175.90 386.88 178.00 389.00&#xA;C 179.28 389.54 182.52 389.85 184.00 390.00&#xA;C 183.44 380.93 188.33 375.54 195.08 370.08 C 201.83 364.62 214.17 366.00 222.00 367.00 C 229.83 367.99 239.80 375.93 244.00 369.00&#xA;C 233.64 367.84 224.41 364.16 217.25 355.75 C 210.08 347.35 207.42 335.10 208.00 324.00 C 208.58 312.90 214.05 304.64 223.23 298.23 C 232.41 291.82 242.58 289.26 254.01 288.01 C 265.44 286.76 278.78 290.03 288.69 294.31 C 298.61 298.58 302.42 309.65 311.00 311.00&#xA;C 292.98 277.80 244.73 276.83 217.00 297.00&#xA;C 209.30 289.11 224.66 284.69 227.75 277.75 C 230.85 270.82 239.46 258.34 233.00 253.00&#xA;C 230.18 263.89 227.65 272.58 218.75 280.75 C 209.85 288.92 200.91 290.73 188.93 293.93 C 176.95 297.12 160.44 288.18 148.93 296.93 C 137.41 305.67 132.86 287.36 144.08 281.08 C 155.30 274.80 164.62 276.35 175.25 269.25 C 185.88 262.14 188.73 250.71 187.00 238.00&#xA;C 178.32 241.41 187.54 262.01 173.00 263.00&#xA;C 169.98 252.46 170.62 238.53 173.32 228.32 C 176.03 218.12 181.89 210.83 192.22 208.22 C 202.56 205.61 207.52 199.40 214.25 191.25 C 220.99 183.11 213.85 167.29 220.00 162.00&#xA;C 234.12 146.99 229.05 129.74 225.00 114.00&#xA;C 224.85 113.42 224.66 111.92 224.00 111.00&#xA;C 220.25 109.36 216.35 109.98 211.00 112.00&#xA;M 152.00 273.00 &#xA;C 142.20 277.14 131.12 280.81 131.00 294.00&#xA;C 120.27 284.76 135.80 269.65 147.00 272.00&#xA;C 149.02 271.71 152.29 270.15 155.00 271.00&#xA;C 154.45 272.01 153.02 272.44 152.00 273.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.19" fill="#000000">
<path d="M 225.00 114.00 &#xA;C 229.89 122.33 229.91 132.23 232.00 142.00 C 234.08 151.77 221.37 159.93 223.93 168.07 C 226.48 176.22 228.75 187.50 232.00 194.00&#xA;C 235.40 198.53 239.35 201.24 244.00 204.00&#xA;C 237.83 198.83 233.59 191.20 231.33 183.67 C 229.06 176.15 224.84 166.83 229.08 160.08 C 233.32 153.32 236.40 141.18 233.78 133.22 C 231.15 125.27 231.64 114.34 224.00 111.00&#xA;C 224.66 111.92 224.85 113.42 225.00 114.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.09" fill="#B0B0B0">
<path d="M 201.00 119.00 &#xA;C 204.34 116.85 207.73 113.57 211.00 112.00&#xA;C 206.52 113.70 204.06 116.44 201.00 119.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.48" fill="#000000">
<path d="M 220.00 162.00 &#xA;C 219.66 166.74 225.00 173.64 225.32 178.68 C 225.64 183.72 229.13 190.18 232.00 194.00&#xA;C 228.75 187.50 226.48 176.22 223.93 168.07 C 221.37 159.93 234.08 151.77 232.00 142.00 C 229.91 132.23 229.89 122.33 225.00 114.00&#xA;C 229.05 129.74 234.12 146.99 220.00 162.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.99" fill="#BEBEBE">
<path d="M 309.00 244.00 &#xA;C 319.62 252.72 326.67 266.01 332.31 278.69 C 337.94 291.38 343.27 312.99 343.00 327.00&#xA;C 348.86 307.69 357.88 289.27 376.00 278.00&#xA;C 375.67 274.36 376.25 270.64 376.00 267.00&#xA;C 374.20 240.59 358.93 215.59 343.00 195.00&#xA;C 335.15 187.46 327.36 178.80 319.00 172.00&#xA;C 311.02 165.51 302.27 161.02 293.75 155.25 C 285.22 149.49 276.61 146.55 268.08 139.92 C 259.55 133.29 246.17 127.28 248.00 141.00 C 249.83 154.72 251.48 162.65 256.69 173.31 C 261.91 183.96 266.05 189.82 272.70 198.30 C 279.34 206.78 283.96 213.48 290.75 221.25 C 297.53 229.03 302.67 236.14 309.00 244.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.13" fill="#858585">
<path d="M 141.00 155.00 &#xA;C 143.35 152.60 147.22 149.86 150.00 147.00&#xA;C 148.11 148.46 143.80 151.45 141.00 155.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#868686">
<path d="M 168.00 152.00 &#xA;C 171.08 151.66 174.91 151.68 178.00 152.00&#xA;C 174.52 151.23 171.54 151.18 168.00 152.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#F6F6F6">
<path d="M 129.00 186.00 &#xA;C 129.32 186.68 128.94 188.24 129.00 189.00&#xA;C 129.45 190.21 132.14 191.97 133.00 193.00&#xA;C 134.29 192.83 134.75 191.30 136.00 191.00&#xA;C 151.55 202.15 175.95 211.63 193.25 196.25 C 210.55 180.87 198.43 156.53 178.00 152.00&#xA;C 174.91 151.68 171.08 151.66 168.00 152.00&#xA;C 159.11 154.07 151.33 159.04 145.30 166.30 C 139.28 173.57 139.58 184.19 129.00 186.00&#xA;M 175.00 161.00 &#xA;C 186.50 162.02 186.34 180.76 173.98 179.98 C 161.61 179.20 162.30 159.88 175.00 161.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#232323">
<path d="M 175.00 161.00 &#xA;C 162.30 159.88 161.61 179.20 173.98 179.98 C 186.34 180.76 186.50 162.02 175.00 161.00&#xA;M 168.00 171.00 &#xA;C 167.10 158.05 181.72 171.06 168.00 171.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.16" fill="#A4A4A4">
<path d="M 134.00 167.00 &#xA;C 135.13 166.05 136.21 164.44 137.00 163.00&#xA;C 137.08 162.88 134.67 165.13 134.00 167.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#F8F8F8">
<path d="M 184.00 390.00 &#xA;C 200.03 391.64 215.88 388.64 232.00 390.00 C 248.12 391.37 264.82 388.01 281.00 390.00 C 297.18 391.99 307.70 387.80 321.00 381.00&#xA;C 334.96 366.76 337.54 345.00 343.00 327.00&#xA;C 343.27 312.99 337.94 291.38 332.31 278.69 C 326.67 266.01 319.62 252.72 309.00 244.00&#xA;C 288.30 227.00 266.37 217.28 244.00 204.00&#xA;C 239.35 201.24 235.40 198.53 232.00 194.00&#xA;C 229.13 190.18 225.64 183.72 225.32 178.68 C 225.00 173.64 219.66 166.74 220.00 162.00&#xA;C 213.85 167.29 220.99 183.11 214.25 191.25 C 207.52 199.40 202.56 205.61 192.22 208.22 C 181.89 210.83 176.03 218.12 173.32 228.32 C 170.62 238.53 169.98 252.46 173.00 263.00&#xA;C 187.54 262.01 178.32 241.41 187.00 238.00&#xA;C 188.73 250.71 185.88 262.14 175.25 269.25 C 164.62 276.35 155.30 274.80 144.08 281.08 C 132.86 287.36 137.41 305.67 148.93 296.93 C 160.44 288.18 176.95 297.12 188.93 293.93 C 200.91 290.73 209.85 288.92 218.75 280.75 C 227.65 272.58 230.18 263.89 233.00 253.00&#xA;C 239.46 258.34 230.85 270.82 227.75 277.75 C 224.66 284.69 209.30 289.11 217.00 297.00&#xA;C 244.73 276.83 292.98 277.80 311.00 311.00&#xA;C 302.42 309.65 298.61 298.58 288.69 294.31 C 278.78 290.03 265.44 286.76 254.01 288.01 C 242.58 289.26 232.41 291.82 223.23 298.23 C 214.05 304.64 208.58 312.90 208.00 324.00 C 207.42 335.10 210.08 347.35 217.25 355.75 C 224.41 364.16 233.64 367.84 244.00 369.00&#xA;C 239.80 375.93 229.83 367.99 222.00 367.00 C 214.17 366.00 201.83 364.62 195.08 370.08 C 188.33 375.54 183.44 380.93 184.00 390.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#E7E7E7">
<path d="M 168.00 171.00 &#xA;C 181.72 171.06 167.10 158.05 168.00 171.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.06" fill="#D5D6D5">
<path d="M 126.00 172.00 &#xA;C 128.16 170.13 130.91 168.68 133.00 167.00&#xA;C 130.73 167.21 126.57 169.37 126.00 172.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.17" fill="#010101">
<path d="M 319.00 172.00 &#xA;C 327.36 178.80 335.15 187.46 343.00 195.00&#xA;C 349.36 201.12 355.23 207.97 360.00 215.00&#xA;C 351.42 199.09 333.96 180.10 319.00 172.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.19" fill="#6A6A6A">
<path d="M 127.00 185.00 &#xA;C 126.54 183.21 127.08 180.85 127.00 179.00&#xA;C 124.69 178.33 127.20 174.74 125.00 174.00&#xA;C 124.95 177.75 125.33 182.05 127.00 185.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.26" fill="#000000">
<path d="M 172.00 215.00 &#xA;C 172.45 214.90 173.63 214.23 174.00 214.00&#xA;C 180.28 209.95 165.13 212.19 171.00 209.00&#xA;C 157.50 209.93 141.03 202.59 133.00 193.00&#xA;C 132.14 191.97 129.45 190.21 129.00 189.00&#xA;C 129.72 198.14 139.50 203.40 146.92 206.08 C 154.33 208.76 163.08 216.93 172.00 215.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.33" fill="#000000">
<path d="M 376.00 267.00 &#xA;C 376.19 267.61 376.87 267.94 377.00 269.00&#xA;C 382.28 281.94 376.22 302.91 373.67 315.67 C 371.13 328.44 363.16 341.06 357.08 352.08 C 351.00 363.10 341.62 372.42 331.00 379.00&#xA;C 336.37 377.44 343.03 372.51 348.25 366.25 C 353.47 359.98 358.20 353.62 362.23 346.23 C 366.25 338.84 369.84 331.25 373.02 323.02 C 376.21 314.80 378.11 304.40 379.22 295.22 C 380.34 286.05 381.18 272.54 378.33 263.67 C 375.48 254.80 374.87 244.63 371.77 236.23 C 368.67 227.83 364.03 222.47 360.00 215.00&#xA;C 355.23 207.97 349.36 201.12 343.00 195.00&#xA;C 358.93 215.59 374.20 240.59 376.00 267.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.17" fill="#8A8A8A">
<path d="M 172.00 215.00 &#xA;C 168.52 218.81 166.97 226.20 166.00 231.00&#xA;C 168.04 225.37 171.29 219.69 174.00 214.00&#xA;C 173.63 214.23 172.45 214.90 172.00 215.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.60" fill="#101010">
<path d="M 165.00 241.00 &#xA;C 165.00 243.67 165.00 246.33 165.00 249.00&#xA;C 165.00 249.00 165.05 249.51 165.00 250.00&#xA;C 165.14 247.56 167.63 242.52 165.00 240.00&#xA;C 165.00 240.00 165.00 240.50 165.00 241.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.03" fill="#7E7E7E">
<path d="M 165.00 249.00 &#xA;C 165.00 246.33 165.00 243.67 165.00 241.00&#xA;C 163.50 243.03 163.47 246.93 165.00 249.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.04" fill="#777777">
<path d="M 152.00 265.00 &#xA;C 155.01 265.00 157.59 264.70 160.00 264.00&#xA;C 157.04 264.47 154.50 263.94 152.00 265.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.29" fill="#7B7B7B">
<path d="M 142.00 266.00 &#xA;C 144.01 265.77 147.41 265.74 150.00 265.00&#xA;C 147.06 264.79 144.65 265.37 142.00 266.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.68" fill="#4F4F4F">
<path d="M 376.00 278.00 &#xA;C 376.36 277.78 377.00 278.00 377.00 278.00&#xA;C 377.06 275.10 377.35 271.88 377.00 269.00&#xA;C 376.87 267.94 376.19 267.61 376.00 267.00&#xA;C 376.25 270.64 375.67 274.36 376.00 278.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.46" fill="#000000">
<path d="M 377.00 278.00 &#xA;C 376.24 316.06 358.69 361.73 321.00 381.00&#xA;C 307.70 387.80 297.18 391.99 281.00 390.00 C 264.82 388.01 248.12 391.37 232.00 390.00 C 215.88 388.64 200.03 391.64 184.00 390.00&#xA;C 182.52 389.85 179.28 389.54 178.00 389.00&#xA;C 182.87 396.59 191.77 393.68 200.00 394.00 C 208.23 394.32 218.57 393.90 227.00 394.00 C 235.43 394.10 244.63 394.09 253.00 394.00 C 261.37 393.91 271.99 394.30 280.00 394.00 C 288.01 393.70 299.78 394.82 306.78 393.78 C 313.78 392.73 320.86 388.48 320.00 385.00&#xA;C 324.03 383.93 327.43 381.21 331.00 379.00&#xA;C 341.62 372.42 351.00 363.10 357.08 352.08 C 363.16 341.06 371.13 328.44 373.67 315.67 C 376.22 302.91 382.28 281.94 377.00 269.00&#xA;C 377.35 271.88 377.06 275.10 377.00 278.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#767676">
<path d="M 147.00 272.00 &#xA;C 148.46 272.02 151.35 273.02 152.00 273.00&#xA;C 153.02 272.44 154.45 272.01 155.00 271.00&#xA;C 152.29 270.15 149.02 271.71 147.00 272.00 Z"/>
</g>
<g stroke="None" fill-opacity="1.00" fill="#E3E3E3">
<path d="M 152.00 273.00 &#xA;C 151.35 273.02 148.46 272.02 147.00 272.00&#xA;C 135.80 269.65 120.27 284.76 131.00 294.00&#xA;C 131.12 280.81 142.20 277.14 152.00 273.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.20" fill="#8E8E8E">
<path d="M 123.00 281.00 &#xA;C 123.72 279.04 126.55 276.13 128.00 274.00&#xA;C 125.91 276.29 123.82 277.81 123.00 281.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.99" fill="#1D1D1D">
<path d="M 343.00 327.00 &#xA;C 337.54 345.00 334.96 366.76 321.00 381.00&#xA;C 358.69 361.73 376.24 316.06 377.00 278.00&#xA;C 377.00 278.00 376.36 277.78 376.00 278.00&#xA;C 357.88 289.27 348.86 307.69 343.00 327.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.32" fill="#000000">
<path d="M 126.00 296.00 &#xA;C 130.06 302.11 136.93 309.06 145.00 309.00 C 153.07 308.94 160.96 301.21 170.00 303.00 C 179.04 304.79 191.11 300.89 199.00 303.00&#xA;C 199.18 302.73 199.77 302.28 200.00 302.00&#xA;C 197.55 298.03 190.28 303.63 184.00 302.00 C 177.72 300.37 175.48 302.79 166.00 302.00 C 156.52 301.21 146.75 312.62 138.00 305.00&#xA;C 133.40 300.99 129.31 299.51 126.00 296.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.59" fill="#010101">
<path d="M 184.00 300.00 &#xA;C 181.34 300.10 178.66 300.00 176.00 300.00&#xA;C 171.88 300.00 166.28 298.95 163.00 299.00&#xA;C 158.84 299.47 154.42 300.80 151.77 301.42 C 149.12 302.05 147.25 306.00 143.00 306.00&#xA;C 147.64 307.07 150.96 305.59 155.08 303.08 C 159.19 300.56 165.50 300.79 170.00 301.00 C 174.50 301.21 183.31 300.15 187.00 301.00 C 190.69 301.85 200.07 297.39 201.00 300.00&#xA;C 202.75 299.61 203.30 297.57 203.00 296.00&#xA;C 196.47 297.98 191.28 299.72 184.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.75" fill="#474747">
<path d="M 176.00 300.00 &#xA;C 175.96 300.00 176.00 299.00 176.00 299.00&#xA;C 171.76 299.00 167.21 298.53 163.00 299.00&#xA;C 166.28 298.95 171.88 300.00 176.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.77" fill="#090909">
<path d="M 176.00 300.00 &#xA;C 178.66 300.00 181.34 300.10 184.00 300.00&#xA;C 182.08 299.89 178.68 299.00 176.00 299.00&#xA;C 176.00 299.00 175.96 300.00 176.00 300.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.44" fill="#000000">
<path d="M 143.00 306.00 &#xA;C 141.66 305.69 139.13 305.57 138.00 305.00&#xA;C 146.75 312.62 156.52 301.21 166.00 302.00 C 175.48 302.79 177.72 300.37 184.00 302.00 C 190.28 303.63 197.55 298.03 200.00 302.00&#xA;C 200.61 301.25 200.53 300.72 201.00 300.00&#xA;C 200.07 297.39 190.69 301.85 187.00 301.00 C 183.31 300.15 174.50 301.21 170.00 301.00 C 165.50 300.79 159.19 300.56 155.08 303.08 C 150.96 305.59 147.64 307.07 143.00 306.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.29" fill="#757575">
<path d="M 196.00 312.00 &#xA;C 198.55 310.92 197.52 309.20 198.00 307.00&#xA;C 198.29 306.24 196.30 310.37 196.00 312.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.03" fill="#AEAEAE">
<path d="M 195.00 324.00 &#xA;C 195.00 324.05 196.00 324.00 196.00 324.00&#xA;C 195.64 321.10 196.00 317.92 196.00 315.00&#xA;C 196.00 314.50 196.00 313.50 196.00 313.00&#xA;C 194.25 315.36 194.72 320.78 195.00 324.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.66" fill="#111111">
<path d="M 196.00 324.00 &#xA;C 196.15 325.26 196.76 325.23 197.00 326.00&#xA;C 197.00 322.19 197.34 318.15 196.00 315.00&#xA;C 196.00 317.92 195.64 321.10 196.00 324.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.26" fill="#484848">
<path d="M 197.00 331.00 &#xA;C 196.94 329.34 197.00 327.66 197.00 326.00&#xA;C 196.76 325.23 196.15 325.26 196.00 324.00&#xA;C 196.00 324.00 195.00 324.05 195.00 324.00&#xA;C 195.21 326.36 196.59 329.08 197.00 331.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.11" fill="#B4B4B4">
<path d="M 179.00 367.00 &#xA;C 180.03 365.82 182.50 363.73 184.00 363.00&#xA;C 184.40 362.80 185.00 363.00 185.00 363.00&#xA;C 186.62 362.45 186.82 360.87 188.00 360.00&#xA;C 184.21 361.67 181.54 363.59 179.00 367.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.78" fill="#0E0E0E">
<path d="M 185.00 363.00 &#xA;C 185.00 363.00 184.40 362.80 184.00 363.00&#xA;C 182.90 364.43 185.65 362.60 185.00 363.00 Z"/>
</g>
<g stroke="None" fill-opacity="0.20" fill="#868686">
<path d="M 175.00 385.00 &#xA;C 174.51 382.75 174.79 379.31 175.00 377.00&#xA;C 174.40 379.91 173.90 381.94 175.00 385.00 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 42 KiB

1
src/public/robots.txt Normal file
View File

@ -0,0 +1 @@

View File

@ -0,0 +1,90 @@
export interface ResourceRequestDetails {
url: string;
resourceType: string;
tabId?: string;
frameId?: number;
}
export interface ResourceRequestResult {
cancel: boolean;
redirectUrl?: string;
}
export interface ContentScript {
code: string;
matches?: string[];
runAt?: 'document_start' | 'document_end' | 'document_idle';
}
export interface Extension {
id: string;
name: string;
version: string;
description?: string;
processNavigation?: (url: string) => boolean;
processResourceRequest?: (
details: ResourceRequestDetails
) => ResourceRequestResult;
contentScripts?: ContentScript[];
}
export const useBrowserExtensionStore = defineStore(
'useBrowserExtensionStore',
() => {
const extensions = ref<Extension[]>([]);
const isInitialized = ref<boolean>(false);
return {
extensions,
isInitialized,
initializeAsync,
processNavigation,
injectContentScripts,
};
}
);
const initializeAsync = async () => {
const { isInitialized } = storeToRefs(useBrowserExtensionStore());
if (isInitialized.value) return;
// Lade Erweiterungen aus dem Erweiterungsverzeichnis
try {
const extensions = await loadExtensionsAsync();
for (const extension of extensions) {
registerExtension(extension);
}
isInitialized.value = true;
console.log(`${extensions.length} Erweiterungen geladen`);
} catch (error) {
console.error('Fehler beim Laden der Erweiterungen:', error);
}
};
const loadExtensionsAsync = async (): Promise<Extension[]> => {
// In einer realen Implementierung würden Sie hier Erweiterungen aus einem Verzeichnis laden
// Für dieses Beispiel verwenden wir hartcodierte Erweiterungen
/* const adBlocker = (await import('./ad-blocker')).default;
const trackerBlocker = (await import('./tracker-blocker')).default; */
return [];
};
const registerExtension = (extension: Extension): boolean => {
const { extensions } = storeToRefs(useBrowserExtensionStore());
if (!extension.id || !extension.name) {
console.error('Ungültige Erweiterung:', extension);
return false;
}
console.log(`Erweiterung registriert: ${extension.name}`);
extensions.value.push(extension);
return true;
};
const processNavigation = (url: string) => {
return true;
};
const injectContentScripts = (t: string) => {};

View File

View File

@ -0,0 +1,57 @@
import { getSingleRouteParam } from '~/composables/helper';
import type { RouteLocationRaw } from 'vue-router';
export interface IExtensionLink {
name: string;
icon: string;
tooltip?: string;
id: string;
}
export const useExtensionsStore = defineStore('extensionsStore', () => {
const extensions = ref<IExtensionLink[]>([
{
id: 'haex-browser',
name: 'Haex Browser',
icon: 'solar:global-outline',
},
{
id: 'extensions',
name: 'sidebar.extensions',
icon: 'gg:extension',
},
{
id: 'settings',
name: 'sidebar.settings',
icon: 'ph:gear-six',
},
]);
const currentRoute = useRouter().currentRoute.value;
const isActive = (id: string) =>
computed(
() =>
currentRoute.name === 'extension' &&
currentRoute.params.extensionId === id
);
const loadAsync = async (id: string) => {
extensions.value.some(async (extension) => {
if (extension.id === id) {
await navigateTo(
useLocalePath()({ name: 'extension', params: { extensionId: id } })
);
} else {
}
});
};
return {
extensions,
loadAsync,
isActive,
};
});

5
src/stores/ui/de.json Normal file
View File

@ -0,0 +1,5 @@
{
"light": "Hell",
"dark": "Dunkel",
"soft": "Soft"
}

5
src/stores/ui/en.json Normal file
View File

@ -0,0 +1,5 @@
{
"light": "Light",
"dark": "Dark",
"soft": "Soft"
}

41
src/stores/ui/index.ts Normal file
View File

@ -0,0 +1,41 @@
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
import de from './de.json';
import en from './en.json';
export const useUiStore = defineStore('uiStore', () => {
const breakpoints = useBreakpoints(breakpointsTailwind);
const currentScreenSize = computed(() =>
breakpoints.active().value.length > 0 ? breakpoints.active().value : 'xs'
);
const { t } = useI18n({
messages: {
de: { ui: de },
en: { ui: en },
},
});
const availableThemes = ref([
{
value: 'dark',
name: t('ui.dark'),
icon: 'line-md:moon-rising-alt-loop',
},
{
value: 'light',
name: t('ui.light'),
icon: 'line-md:moon-to-sunny-outline-loop-transition',
},
{ value: 'soft', name: t('ui.soft'), icon: 'line-md:paint-drop' },
]);
const currentTheme = ref(availableThemes.value[0].value);
return {
breakpoints,
currentScreenSize,
currentTheme,
availableThemes,
};
});

View File

@ -0,0 +1,22 @@
export interface IHaexNotication {
title: string;
description?: string;
icon?: string;
image?: string;
alt?: string;
}
export const useNotificationStore = defineStore('notificationStore', () => {
const notifications = ref<IHaexNotication[]>([
{
title: 'huhu',
alt: 'test',
description: 'Ganz was tolles',
image: 'https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png',
},
]);
return {
notifications,
};
});

44
src/stores/ui/sidebar.ts Normal file
View File

@ -0,0 +1,44 @@
import { getSingleRouteParam } from '~/composables/helper';
import type { RouteLocationRaw } from 'vue-router';
export interface ISidebarItem {
name: string;
icon: string;
tooltip?: string;
id: string;
type: 'browser' | 'extension';
}
export const useSidebarStore = defineStore('sidebarStore', () => {
const menu = ref<ISidebarItem[]>([
{
id: 'haex-browser',
name: 'Haex Browser',
icon: 'solar:global-outline',
type: 'browser',
},
{
id: 'haex-vault',
name: 'Haex Vault',
icon: 'gg:extension',
type: 'extension',
},
]);
/* const loadAsync = async (id: string) => {
extensions.value.some(async (extension) => {
if (extension.id === id) {
await navigateTo(
useLocalePath()({ name: 'extension', params: { extensionId: id } })
);
} else {
}
});
}; */
return {
menu,
//loadAsync,
};
});

231
src/stores/vault/index.ts Normal file
View File

@ -0,0 +1,231 @@
//import Database from '@tauri-apps/plugin-sql';
import { drizzle, SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
//import Database from "tauri-plugin-sql-api";
import * as schema from '@/../src-tauri/database/schemas/vault';
import { invoke } from '@tauri-apps/api/core';
import { count } from 'drizzle-orm';
import { platform } from '@tauri-apps/plugin-os';
interface IVault {
//database: Database;
path: string;
password: string;
name: string;
drizzle: SqliteRemoteDatabase<typeof schema>;
}
interface IOpenVaults {
[vaultPath: string]: IVault;
}
export const useVaultStore = defineStore('vaultStore', () => {
const currentVaultId = computed<string | undefined>({
get: () =>
getSingleRouteParam(useRouter().currentRoute.value.params.vaultId),
set: (newVaultId) => {
useRouter().currentRoute.value.params.vaultId = newVaultId ?? '';
},
});
const read_only = computed<boolean>({
get: () => {
console.log(
'query showSidebar',
useRouter().currentRoute.value.query.readonly
);
return JSON.parse(
getSingleRouteParam(useRouter().currentRoute.value.query.readonly) ||
'false'
);
},
set: (readonly) => {
const router = useRouter();
router.replace({
query: {
...router.currentRoute.value.query,
readonly: JSON.stringify(readonly ? true : false),
},
});
},
});
const openVaults = ref<IOpenVaults | undefined>();
const currentVault = ref<IVault | undefined>();
/* computed(() => {
console.log('compute currentVault', currentVaultId.value, openVaults.value);
return openVaults.value?.[currentVaultId.value ?? ''];
}); */
watch(
currentVaultId,
async () => {
/* if (!openVaults.value?.[currentVaultId.value ?? '']) {
console.log(
'no vaultId',
currentVault.value,
openVaults.value?.[currentVaultId.value ?? '']
);
return await navigateTo(useLocalePath()({ name: 'vaultOpen' }));
} else */
currentVault.value = openVaults.value?.[currentVaultId.value ?? ''];
},
{ immediate: true }
);
const openAsync = async ({
path = '',
password,
}: {
path: string;
password: string;
}) => {
//const sqlitePath = path?.startsWith('sqlite:') ? path : `sqlite:${path}`;
console.log('try to open db', path, password);
const result = await invoke<string>('open_encrypted_database', {
path,
key: password,
});
console.log('open vault from store', result);
if (!(await testDatabaseReadAsync())) throw new Error('Passwort falsch');
//const db = await Database.load(sqlitePath);
const vaultId = await getVaultIdAsync(path);
const seperator = platform() === 'windows' ? '\\' : '/';
const fileName = path.split(seperator).pop();
console.log('opened db fileName', fileName, vaultId);
openVaults.value = {
...openVaults.value,
[vaultId]: {
//database: db,
path,
password,
name: fileName ?? path,
drizzle: drizzle<typeof schema>(
async (sql, params, method) => {
let rows: any = [];
let results = [];
// If the query is a SELECT, use the select method
if (isSelectQuery(sql)) {
rows = await invoke('db_select', { sql, params }).catch((e) => {
console.error('SQL Error:', e);
return [];
});
} else {
// Otherwise, use the execute method
rows = await invoke('db_execute', { sql, params }).catch((e) => {
console.error('SQL Error:', e);
return [];
});
return { rows: [] };
}
rows = rows.map((row: any) => {
return Object.values(row);
});
// If the method is "all", return all rows
results = method === 'all' ? rows : rows[0];
return { rows: results };
},
// Pass the schema to the drizzle instance
{ schema: schema, logger: true }
),
},
};
const { addVaultAsync } = useLastVaultStore();
await addVaultAsync({ path });
return vaultId;
};
const testDatabaseReadAsync = async () => {
try {
currentVault.value?.drizzle
.select({ count: count() })
.from(schema.haexExtensions);
return true;
} catch (error) {
return false;
}
};
const refreshDatabaseAsync = async () => {
console.log('refreshDatabaseAsync');
/* if (!currentVault.value?.database.close) {
return navigateTo(useLocaleRoute()({ name: 'vaultOpen' }));
} */
};
const createAsync = async ({
path,
password,
}: {
path: string;
password: string;
}) => {
/* const existDb = await exists('default.db', {
baseDir: BaseDirectory.Resource,
}); */
/* const existDb = await resolveResource('resources/default.db');
if (!existDb) throw new Error('Keine Datenbank da');
await copyFile(existDb, path); */
const result = await invoke('create_encrypted_database', {
path,
key: password,
});
console.log('create_encrypted_database', result);
return 'aaaaa'; //await openAsync({ path, password });
};
const closeAsync = async () => {
if (!currentVaultId.value) return;
/* if (
typeof openVaults.value?.[currentVaultId.value]?.database?.close ===
'function'
) {
console.log('close db', openVaults.value?.[currentVaultId.value]);
return openVaults.value?.[currentVaultId.value]?.database?.close();
} */
delete openVaults.value?.[currentVaultId.value];
};
return {
closeAsync,
createAsync,
currentVault,
currentVaultId,
openAsync,
openVaults,
refreshDatabaseAsync,
read_only,
};
});
const getVaultIdAsync = async (path: string) => {
const encoder = new TextEncoder();
const data = encoder.encode(path);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
const hashHex = hashArray
.map((b) => b.toString(16).padStart(2, '0'))
.join(''); // convert bytes to hex string
console.log('vaultId', hashHex);
return hashHex;
};
function isSelectQuery(sql: string): boolean {
const selectRegex = /^\s*SELECT\b/i;
return selectRegex.test(sql);
}

View File

@ -0,0 +1,80 @@
import { load, Store } from '@tauri-apps/plugin-store';
interface ILastVault {
lastUsed: Date;
name: string;
path: string;
}
export const useLastVaultStore = defineStore('lastVaultStore', () => {
const {
public: { haexVault },
} = useRuntimeConfig();
const lastVaults = ref<ILastVault[]>([]);
const keyName = 'lastVaults';
const getStoreAsync = async () => {
return await load(haexVault.lastVaultFileName);
};
const syncLastVaultsAsync = async () => {
const store = await getStoreAsync();
lastVaults.value =
(await store.get<ILastVault[]>(keyName))?.sort(
(a, b) => +new Date(b.lastUsed) - +new Date(a.lastUsed)
) ?? [];
return lastVaults.value;
};
const addVaultAsync = async ({
name,
path,
}: {
name?: string;
path: string;
}) => {
if (!lastVaults.value) await syncLastVaultsAsync();
const saveName = name || getFileNameFromPath(path);
lastVaults.value = lastVaults.value.filter((vault) => vault.path !== path);
lastVaults.value.push({ lastUsed: new Date(), name: saveName, path });
await saveLastVaultsAsync();
};
const removeVaultAsync = async (vaultPath: string) => {
console.log('remove', vaultPath, lastVaults.value);
lastVaults.value = lastVaults.value.filter(
(vault) => vault.path !== vaultPath
);
await saveLastVaultsAsync();
};
const saveLastVaultsAsync = async () => {
const store = await getStoreAsync();
console.log('save lastVaults', keyName, lastVaults.value);
await store.set(keyName, lastVaults.value);
await syncLastVaultsAsync();
};
return {
addVaultAsync,
syncLastVaultsAsync,
lastVaults,
removeVaultAsync,
saveLastVaultsAsync,
};
});
const getFileNameFromPath = (path: string) => {
const lastBackslashIndex = path.lastIndexOf('\\');
const lastSlashIndex = path.lastIndexOf('/');
const lastIndex = Math.max(lastBackslashIndex, lastSlashIndex);
const fileName = path.substring(lastIndex + 1);
return fileName;
};

View File

@ -0,0 +1,60 @@
(function () {
// Überwache das Erstellen von Elementen, die Ressourcen laden
const originalCreateElement = document.createElement;
document.createElement = function (tagName) {
const element = originalCreateElement.call(document, tagName);
if (
tagName.toLowerCase() === 'img' ||
tagName.toLowerCase() === 'script' ||
tagName.toLowerCase() === 'iframe'
) {
// Überwache das Setzen des src-Attributs
const originalSetAttribute = element.setAttribute;
element.setAttribute = function (name, value) {
if (name === 'src') {
// Prüfe, ob die Ressource blockiert werden soll
window.__TAURI__
.invoke('block_resource_request', {
url: value,
resourceType: tagName.toLowerCase(),
})
.then((shouldBlock) => {
if (shouldBlock) {
console.log(`Ressourcenanfrage blockiert: ${value}`);
return;
}
originalSetAttribute.call(element, name, value);
});
} else {
originalSetAttribute.call(element, name, value);
}
};
}
return element;
};
// Wenn die Tauri HTTP API verwendet wird, können wir sie hier überwachen
if (window.__TAURI__ && window.__TAURI__.http) {
const originalFetch = window.__TAURI__.http.fetch;
window.__TAURI__.http.fetch = async function (options) {
// Prüfe, ob die Ressource blockiert werden soll
const shouldBlock = await window.__TAURI__.invoke(
'block_resource_request',
{
url: options.url,
resourceType: 'tauri-fetch',
}
);
if (shouldBlock) {
throw new Error(`Ressourcenanfrage blockiert: ${options.url}`);
}
return originalFetch.call(this, options);
};
}
console.log('Webview-Bridge geladen');
})();