chore: ags configs removed

This commit is contained in:
hesam-init 2024-09-07 18:56:18 +03:30
parent 4d06a17726
commit 32fe68d02a
125 changed files with 1 additions and 8105 deletions

View file

@ -1,130 +0,0 @@
env:
es2022: true
extends:
- "eslint:recommended"
- "plugin:@typescript-eslint/recommended"
parser: "@typescript-eslint/parser"
parserOptions:
ecmaVersion: 2022
sourceType: "module"
project: "./tsconfig.json"
warnOnUnsupportedTypeScriptVersion: false
root: true
ignorePatterns:
- types/
plugins:
- "@typescript-eslint"
rules:
"@typescript-eslint/ban-ts-comment":
- "off"
"@typescript-eslint/no-non-null-assertion":
- "off"
# "@typescript-eslint/no-explicit-any":
# - "off"
"@typescript-eslint/no-unused-vars":
- error
- varsIgnorePattern: (^unused|_$)
argsIgnorePattern: ^(unused|_)
"@typescript-eslint/no-empty-interface":
- "off"
arrow-parens:
- error
- as-needed
comma-dangle:
- error
- always-multiline
comma-spacing:
- error
- before: false
after: true
comma-style:
- error
- last
curly:
- error
- multi-or-nest
- consistent
dot-location:
- error
- property
eol-last:
- error
eqeqeq:
- error
- always
indent:
- error
- 4
- SwitchCase: 1
keyword-spacing:
- error
- before: true
lines-between-class-members:
- error
- always
- exceptAfterSingleLine: true
padded-blocks:
- error
- never
- allowSingleLineBlocks: false
prefer-const:
- error
quotes:
- error
- double
- avoidEscape: true
semi:
- error
- never
nonblock-statement-body-position:
- error
- below
no-trailing-spaces:
- error
no-useless-escape:
- off
max-len:
- error
- code: 100
func-call-spacing:
- error
array-bracket-spacing:
- error
space-before-function-paren:
- error
- anonymous: never
named: never
asyncArrow: ignore
space-before-blocks:
- error
key-spacing:
- error
object-curly-spacing:
- error
- always
globals:
Widget: readonly
Utils: readonly
App: readonly
Variable: readonly
Service: readonly
pkg: readonly
ARGV: readonly
Debugger: readonly
GIRepositoryGType: readonly
globalThis: readonly
imports: readonly
Intl: readonly
log: readonly
logError: readonly
print: readonly
printerr: readonly
window: readonly
TextEncoder: readonly
TextDecoder: readonly
console: readonly
setTimeout: readonly
setInterval: readonly
clearTimeout: readonly
clearInterval: readonly

View file

@ -1,6 +0,0 @@
node_modules
types
package-lock.json
bun.lockb
flake.lock
.weather

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 8.96875 0 c -0.332031 0.0117188 -0.640625 0.1875 -0.816406 0.46875 l -5 8 c -0.105469 0.171875 -0.152344 0.355469 -0.152344 0.53125 v 1 h 3 v 5 c 0 1.003906 1.316406 1.378906 1.847656 0.53125 l 5 -8 c 0.105469 -0.171875 0.152344 -0.355469 0.152344 -0.53125 v -1 h -3 v -5 c 0 -0.5625 -0.464844 -1.015625 -1.03125 -1 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 476 B

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 14 3.175781 v 3.824219 c 0 2.179688 -1.820312 4 -4 4 h -3.585938 l -2 2 h 5.585938 l 3 3 v -3 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.292969 -0.839844 -2.40625 -2 -2.824219 z m 0 0" fill-opacity="0.34902"/>
<path d="m 3 0 c -1.644531 0 -3 1.355469 -3 3 v 4 c 0 1.644531 1.355469 3 3 3 v 3 l 3 -3 h 4 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 534 B

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 3.785156 2.03125 c -0.242187 0 -0.523437 0.066406 -0.804687 0.21875 c -1.039063 0.546875 -1.992188 2.335938 -2.511719 4.65625 c -0.4414062 1.972656 -0.605469 4.664062 -0.339844 5.75 c 0.226563 0.933594 0.625 1.34375 1.332032 1.34375 c 1.042968 -0.019531 2.359374 -1.183594 3.191406 -2.75 c 0.601562 -0.867188 2 -1.261719 3.347656 -1.21875 c 1.347656 -0.046875 2.746094 0.351562 3.347656 1.21875 c 0.832032 1.566406 2.148438 2.730469 3.191406 2.75 c 0.707032 0 1.105469 -0.410156 1.332032 -1.34375 c 0.265625 -1.085938 0.101562 -3.777344 -0.339844 -5.75 c -0.519531 -2.320312 -1.472656 -4.109375 -2.511719 -4.65625 c -0.566406 -0.304688 -1.039062 -0.296875 -1.453125 0 c -0.527344 0.375 -1.628906 0.78125 -3.566406 0.78125 c -1.9375 0.003906 -3.039062 -0.40625 -3.566406 -0.78125 c -0.207032 -0.148438 -0.40625 -0.21875 -0.648438 -0.21875 z m 0.246094 3 h 0.992188 v 1 h 0.992187 v 1 h -0.992187 v 1 h -0.992188 v -1 h -0.992188 v -1 h 0.992188 z m 7.441406 0 c 0.273438 0 0.496094 0.222656 0.496094 0.5 s -0.222656 0.5 -0.496094 0.5 c -0.273437 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222657 -0.5 0.496094 -0.5 z m -0.992187 1 c 0.273437 0 0.496093 0.222656 0.496093 0.5 s -0.222656 0.5 -0.496093 0.5 c -0.273438 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222656 -0.5 0.496094 -0.5 z m 1.984375 0 c 0.273437 0 0.496094 0.222656 0.496094 0.5 s -0.222657 0.5 -0.496094 0.5 c -0.273438 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222656 -0.5 0.496094 -0.5 z m -0.992188 1 c 0.273438 0 0.496094 0.222656 0.496094 0.5 s -0.222656 0.5 -0.496094 0.5 c -0.273437 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222657 -0.5 0.496094 -0.5 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 4.550781 1 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 7 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0"/>
<path d="m 4.550781 9 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 0 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0" fill-opacity="0.34902"/>
</svg>

Before

Width:  |  Height:  |  Size: 777 B

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 0.917969 8.003906 c 0 3.914063 3.164062 7.078125 7.078125 7.078125 c 3.605468 -0.007812 6.617187 -2.703125 7.023437 -6.285156 c 0.042969 -0.378906 -0.136719 -0.75 -0.457031 -0.957031 c -0.324219 -0.203125 -0.738281 -0.207032 -1.0625 -0.003906 c -0.609375 0.375 -1.316406 0.578124 -2.03125 0.578124 c -2.140625 0 -3.882812 -1.742187 -3.882812 -3.882812 c 0 -0.714844 0.203124 -1.421875 0.578124 -2.03125 c 0.203126 -0.324219 0.199219 -0.738281 -0.003906 -1.0625 c -0.207031 -0.320312 -0.578125 -0.5 -0.957031 -0.457031 c -3.582031 0.40625 -6.277344 3.417969 -6.285156 7.023437 z m 4.667969 -3.472656 c 0 3.253906 2.628906 5.882812 5.886718 5.882812 c 1.085938 0 2.152344 -0.304687 3.078125 -0.878906 l -1.519531 -0.960937 c -0.289062 2.554687 -2.464844 4.503906 -5.035156 4.507812 c -2.796875 0 -5.078125 -2.28125 -5.078125 -5.078125 c 0.003906 -2.570312 1.953125 -4.746094 4.507812 -5.035156 l -0.960937 -1.519531 c -0.574219 0.925781 -0.875 1.992187 -0.878906 3.082031 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 5 0 c -0.96875 0 -2 1.050781 -2 2 v 2.988281 c 0 0.429688 0.222656 0.675781 0.554688 1.007813 l 2.023437 2.003906 l -2.007813 1.992188 c -0.367187 0.363281 -0.570312 0.6875 -0.570312 1 v 3.007812 c 0 1.011719 0.988281 2 2 2 h 6 c 1.007812 0 2 -1.011719 2 -2.003906 v -3.003906 c 0 -0.3125 -0.222656 -0.628907 -0.570312 -0.976563 l -2.015626 -2.015625 l 1.988282 -1.988281 c 0.261718 -0.261719 0.585937 -0.6875 0.597656 -1.015625 v -2.996094 c 0 -1.003906 -1.007812 -2 -2 -2 z m 6 4 h -6 v -2 h 6 m -3.589844 7 h 1.175782 l 2.414062 2.414062 v 1.585938 h -6 v -1.613281 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 729 B

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 8 0 c -0.554688 0 -1 0.445312 -1 1 v 1 c 0 0.554688 0.445312 1 1 1 s 1 -0.445312 1 -1 v -1 c 0 -0.554688 -0.445312 -1 -1 -1 z m -4.996094 2.003906 c -0.253906 0 -0.507812 0.097656 -0.707031 0.296875 c -0.390625 0.390625 -0.390625 1.019531 0 1.414063 l 0.707031 0.707031 c 0.394532 0.390625 1.023438 0.390625 1.414063 0 c 0.394531 -0.394531 0.394531 -1.023437 0 -1.414063 l -0.707031 -0.707031 c -0.195313 -0.199219 -0.449219 -0.296875 -0.707032 -0.296875 z m 9.988282 0 c -0.253907 0 -0.507813 0.097656 -0.707032 0.296875 l -0.707031 0.707031 c -0.390625 0.390626 -0.390625 1.019532 0 1.414063 c 0.394531 0.390625 1.023437 0.390625 1.414063 0 l 0.707031 -0.707031 c 0.394531 -0.394532 0.394531 -1.023438 0 -1.414063 c -0.195313 -0.199219 -0.449219 -0.296875 -0.707031 -0.296875 z m -4.992188 1.996094 c -2.210938 0 -4 1.789062 -4 4 s 1.789062 4 4 4 s 4 -1.789062 4 -4 s -1.789062 -4 -4 -4 z m 0 2 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 -2 2 s -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m -7 1 c -0.554688 0 -1 0.445312 -1 1 s 0.445312 1 1 1 h 1 c 0.554688 0 1 -0.445312 1 -1 s -0.445312 -1 -1 -1 z m 13 0 c -0.554688 0 -1 0.445312 -1 1 s 0.445312 1 1 1 h 1 c 0.554688 0 1 -0.445312 1 -1 s -0.445312 -1 -1 -1 z m -10.335938 4.289062 c -0.238281 0.007813 -0.472656 0.105469 -0.660156 0.292969 l -0.707031 0.707031 c -0.390625 0.390626 -0.390625 1.019532 0 1.414063 c 0.394531 0.390625 1.023437 0.390625 1.414063 0 l 0.707031 -0.707031 c 0.394531 -0.394532 0.394531 -1.023438 0 -1.414063 c -0.207031 -0.210937 -0.484375 -0.308593 -0.753907 -0.292969 z m 8.574219 0 c -0.238281 0.007813 -0.472656 0.105469 -0.660156 0.292969 c -0.390625 0.390625 -0.390625 1.019531 0 1.414063 l 0.707031 0.707031 c 0.394532 0.390625 1.023438 0.390625 1.414063 0 c 0.394531 -0.394531 0.394531 -1.023437 0 -1.414063 l -0.707031 -0.707031 c -0.207032 -0.210937 -0.484376 -0.308593 -0.753907 -0.292969 z m -4.292969 1.710938 c -0.527343 0.027344 -0.945312 0.464844 -0.945312 1 v 1 c 0 0.554688 0.445312 1 1 1 s 1 -0.445312 1 -1 v -1 c 0 -0.554688 -0.445312 -1 -1 -1 c -0.015625 0 -0.035156 0 -0.050781 0 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 11.5 1 c -1.921875 0 -3.5 1.578125 -3.5 3.5 s 1.578125 3.5 3.5 3.5 s 3.5 -1.578125 3.5 -3.5 s -1.578125 -3.5 -3.5 -3.5 z m 0 2 c 0.839844 0 1.5 0.660156 1.5 1.5 s -0.660156 1.5 -1.5 1.5 s -1.5 -0.660156 -1.5 -1.5 s 0.660156 -1.5 1.5 -1.5 z m 0 0"/>
<path d="m 4.5 8 c -1.921875 0 -3.5 1.578125 -3.5 3.5 s 1.578125 3.5 3.5 3.5 c 1.386719 0 2.59375 -0.820312 3.15625 -2 h 5.84375 c 0.832031 0 1.5 -0.667969 1.5 -1.5 s -0.667969 -1.5 -1.5 -1.5 h -5.84375 c -0.5625 -1.179688 -1.769531 -2 -3.15625 -2 z m 0 2 c 0.839844 0 1.5 0.660156 1.5 1.5 s -0.660156 1.5 -1.5 1.5 s -1.5 -0.660156 -1.5 -1.5 s 0.660156 -1.5 1.5 -1.5 z m 0 0"/>
<path d="m 2.5 3 c -0.832031 0 -1.5 0.667969 -1.5 1.5 s 0.667969 1.5 1.5 1.5 h 4.769531 c -0.175781 -0.480469 -0.265625 -0.988281 -0.269531 -1.5 c 0 -0.511719 0.09375 -1.019531 0.269531 -1.5 z m 0 0" fill-opacity="0.34902"/>
</svg>

Before

Width:  |  Height:  |  Size: 1,009 B

View file

@ -1,155 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="496"
height="496"
version="1"
id="svg6"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<g
id="g946"
transform="matrix(0.97173996,0,0,0.97173996,4.043873,36.112138)">
<g
id="layer7"
style="display:none"
transform="translate(-23.75651,-24.84972)">
<rect
transform="translate(-132.5822,958.04022)"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5389"
width="1543.4283"
height="483.7439"
x="132.5822"
y="-957.77832" />
</g>
<g
id="layer6"
style="display:none"
transform="translate(-156.33871,933.1905)">
<rect
y="-958.02759"
x="132.65129"
height="484.30399"
width="550.41602"
id="rect5379"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5c201e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c24a46;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5372"
width="501.94415"
height="434.30405"
x="156.12303"
y="-933.02759" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d98d8a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5381"
width="24.939611"
height="24.939611"
x="658.02826"
y="-958.04022" />
</g>
<g
id="layer3"
style="display:inline;opacity:1"
transform="translate(37.235605,912.8581)">
<g
id="g2072"
transform="matrix(0.99894325,0,0,0.99894325,-36.551621,-913.90743)"
style="fill:#cccccc;fill-opacity:1">
<g
style="display:none;fill:#cccccc;fill-opacity:1"
transform="matrix(0.09048806,0,0,0.09048806,-14.15991,84.454917)"
id="layer1-3">
<rect
y="-2102.4253"
x="-1045.6049"
height="7145.4614"
width="7947.0356"
id="rect995"
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke-width:10.3605" />
</g>
<g
transform="translate(-156.48372,537.56136)"
style="display:inline;opacity:1;fill:#cccccc;fill-opacity:1"
id="layer3-6">
<g
style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1"
transform="matrix(0.09048806,0,0,0.09048806,142.32381,-453.10644)"
id="g955">
<g
transform="matrix(11.047619,0,0,11.047619,-1572.2888,9377.7107)"
id="g869"
style="fill:#cccccc;fill-opacity:1">
<g
transform="rotate(-60,226.35754,-449.37199)"
id="g932"
style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1">
<path
id="path3336-6-7"
d="m 449.71876,-420.51322 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.27523 -22.15297,-38.55047 -33.22946,-57.8257 9.35083,-16.29387 18.70167,-32.58775 28.0525,-48.88162 z"
style="opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<path
id="path4260-0-5"
d="m 309.54892,-710.38827 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29391 18.70167,-32.58781 28.0525,-48.88172 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<use
x="0"
y="0"
xlink:href="#path3336-6-7"
id="use3439-6-3"
transform="rotate(60,728.23563,-692.24036)"
width="100%"
height="100%"
style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
<use
x="0"
y="0"
xlink:href="#path3336-6-7"
id="use3449-5-5"
transform="rotate(180,477.5036,-570.81898)"
width="100%"
height="100%"
style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
<use
style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
x="0"
y="0"
xlink:href="#path4260-0-5"
id="use4354-5-6"
transform="rotate(120,407.33916,-716.08356)"
width="100%"
height="100%" />
<use
style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
x="0"
y="0"
xlink:href="#path4260-0-5"
id="use4362-2-2"
transform="rotate(-120,407.28823,-715.86995)"
width="100%"
height="100%" />
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -1,321 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="16px"
viewBox="0 0 16 16"
width="16px"
version="1.1"
id="svg3533"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3537" />
<filter
id="a"
height="1"
width="1"
x="0"
y="0">
<feColorMatrix
in="SourceGraphic"
type="matrix"
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
id="feColorMatrix3414" />
</filter>
<mask
id="b">
<g
filter="url(#a)"
id="g3419">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwcB8GZcBWQFEIoq/qy3b9Y8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQdi/bMl/PXorsAAADAA+ffDwAAAAD7CQAAAAAQIAAAAABAgAAAAAAAAQIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dQMXagEYjYWofQAAAABJRU5ErkJggg=="
id="image3417" />
</g>
</mask>
<clipPath
id="c">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3422" />
</clipPath>
<mask
id="d">
<g
filter="url(#a)"
id="g3427">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3425" />
</g>
</mask>
<clipPath
id="e">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3430" />
</clipPath>
<mask
id="f">
<g
filter="url(#a)"
id="g3435">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3433" />
</g>
</mask>
<clipPath
id="g">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3438" />
</clipPath>
<mask
id="h">
<g
filter="url(#a)"
id="g3443">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3441" />
</g>
</mask>
<clipPath
id="i">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3446" />
</clipPath>
<mask
id="j">
<g
filter="url(#a)"
id="g3451">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3449" />
</g>
</mask>
<clipPath
id="k">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3454" />
</clipPath>
<mask
id="l">
<g
filter="url(#a)"
id="g3459">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3457" />
</g>
</mask>
<clipPath
id="m">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3462" />
</clipPath>
<mask
id="n">
<g
filter="url(#a)"
id="g3467">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
id="image3465" />
</g>
</mask>
<clipPath
id="o">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3470" />
</clipPath>
<mask
id="p">
<g
filter="url(#a)"
id="g3475">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwcB8GZcBWQFEIoq/qy3b9Y8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQdi/bMl/PXorsAAADAA+ffDwAAAAD7CQAAAAAQIAAAAABAgAAAAAAAAQIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dQMXagEYjYWofQAAAABJRU5ErkJggg=="
id="image3473" />
</g>
</mask>
<clipPath
id="q">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3478" />
</clipPath>
<mask
id="r">
<g
filter="url(#a)"
id="g3483">
<image
height="800"
width="1024"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMqUlEQVR4nO3YsQ3AMAwEMSeTe/QM4QgujqwF4etbCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIen76s4fvAQAAgAPv7QEAAADAPAEAAAAAAgQAAAAACBAAAAAAIEAAAAAAgAABAAAAAAIEAAAAAAgQAAAAACBAAAAAAIAAAQAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAUx8hKgEYqUBSPgAAAABJRU5ErkJggg=="
id="image3481" />
</g>
</mask>
<clipPath
id="s">
<path
d="m 0 0 h 1024 v 800 h -1024 z"
id="path3486" />
</clipPath>
<path
d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 10 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -0.570312 -0.167969 -1.101562 -0.449219 -1.558594 l -1.550781 1.554688 v 6.003906 c 0 0.570312 -0.429688 1 -1 1 h -10 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 h 5.96875 l 2.007812 -2 z m 0 0"
fill="#2e3436"
id="path3489"
style="fill:#000000" />
<g
clip-path="url(#c)"
mask="url(#b)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3493"
style="fill:#000000">
<path
d="m 439.105469 225.78125 h 7.839843 c -0.890624 0.371094 -0.972656 1.847656 0 2.25 h -7.839843 z m 0 0"
fill="#2e3436"
id="path3491"
style="fill:#000000" />
</g>
<g
clip-path="url(#e)"
mask="url(#d)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3497"
style="fill:#000000">
<path
d="m 29.25 627.75 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3495"
style="fill:#000000" />
</g>
<g
clip-path="url(#g)"
mask="url(#f)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3501"
style="fill:#000000">
<path
d="m 30 627 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3499"
style="fill:#000000" />
</g>
<g
clip-path="url(#i)"
mask="url(#h)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3505"
style="fill:#000000">
<path
d="m 30.75 629.25 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3503"
style="fill:#000000" />
</g>
<g
clip-path="url(#k)"
mask="url(#j)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3509"
style="fill:#000000">
<path
d="m 29.25 629.25 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3507"
style="fill:#000000" />
</g>
<g
clip-path="url(#m)"
mask="url(#l)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3513"
style="fill:#000000">
<path
d="m 30 630 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3511"
style="fill:#000000" />
</g>
<g
clip-path="url(#o)"
mask="url(#n)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3517"
style="fill:#000000">
<path
d="m 31.5 630 h 0.75 v 0.75 h -0.75 z m 0 0"
fill="#2e3436"
fill-rule="evenodd"
id="path3515"
style="fill:#000000" />
</g>
<g
clip-path="url(#q)"
mask="url(#p)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3521"
style="fill:#000000">
<path
d="m 119.253906 648.75 v 5.25 h 5.25 v -5.25 z m 0 0"
fill="#2e3436"
id="path3519"
style="fill:#000000" />
</g>
<path
d="m 11 7 c 0 1.65625 -1.339844 3.007812 -3 3 h -3 v -3 c 0 -1.660156 1.34375 -3 3 -3 c 1.660156 0 3 1.339844 3 3 z m 0 0"
fill="#2e3436"
id="path3523"
style="fill:#000000" />
<path
d="m 13.398438 0 l -3.46875 3.457031 c 0.683593 0.355469 1.234374 0.910157 1.589843 1.589844 l 0.171875 -0.171875 l 0.007813 0.007812 l 4.300781 -4.300781 v -0.582031 z m 0 0"
fill="#2e3436"
id="path3525"
style="fill:#000000" />
<g
clip-path="url(#s)"
mask="url(#r)"
transform="matrix(1 0 0 1 -40 -620)"
id="g3529"
style="fill:#000000">
<path
d="m 181.503906 635.25 h 2.25 v 9 h -2.25 z m 0 0"
fill="#2e3436"
id="path3527"
style="fill:#000000" />
</g>
<path
d="m 5 14 c -1.105469 0 -2 0.894531 -2 2 h 10 c 0 -1.105469 -0.894531 -2 -2 -2 z m 0 0"
fill="#2e3436"
id="path3531"
style="fill:#000000" />
</svg>

Before

Width:  |  Height:  |  Size: 46 KiB

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 5 5 h 6 v 6 h -6 z m 0 0"/>
<path d="m 13 5 h 3 v 1 h -3 z m 0 0"/>
<path d="m 13 7 h 3 v 1 h -3 z m 0 0"/>
<path d="m 13 9 h 3 v 1 h -3 z m 0 0"/>
<path d="m 0 6 h 3 v 1 h -3 z m 0 0"/>
<path d="m 0 8 h 3 v 1 h -3 z m 0 0"/>
<path d="m 0 10 h 3 v 1 h -3 z m 0 0"/>
<path d="m 5 0 h 1 v 3 h -1 z m 0 0"/>
<path d="m 7 0 h 1 v 3 h -1 z m 0 0"/>
<path d="m 9 0 h 1 v 3 h -1 z m 0 0"/>
<path d="m 10 13 h 1 v 3 h -1 z m 0 0"/>
<path d="m 8 13 h 1 v 3 h -1 z m 0 0"/>
<path d="m 6 13 h 1 v 3 h -1 z m 0 0"/>
<path d="m 5 2 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 6 c 0.570312 0 1 0.429688 1 1 v 6 c 0 0.570312 -0.429688 1 -1 1 h -6 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1,014 B

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 2.199219 0 c -1.207031 0 -2.199219 1.007812 -2.199219 2.207031 v 10.585938 c 0 1.199219 0.992188 2.207031 2.199219 2.207031 h 11.601562 c 1.207031 0 2.199219 -1.007812 2.199219 -2.207031 v -10.585938 c 0 -1.199219 -0.992188 -2.207031 -2.199219 -2.207031 z m 0 2 h 11.601562 c 0.121094 0 0.199219 0.070312 0.199219 0.207031 v 10.585938 c 0 0.136719 -0.078125 0.207031 -0.199219 0.207031 h -11.601562 c -0.121094 0 -0.199219 -0.070312 -0.199219 -0.207031 v -10.585938 c 0 -0.136719 0.078125 -0.207031 0.199219 -0.207031 z m 0 0"/>
<path d="m 4.515625 5.898438 c -0.164063 -0.003907 -0.324219 0.0625 -0.441406 0.175781 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 l 1.578125 1.574219 l -1.578125 1.574219 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 c 0.234375 0.230469 0.617187 0.230469 0.851562 0 l 2 -2 c 0.230469 -0.234375 0.230469 -0.617187 0 -0.851562 l -2 -2 c -0.109375 -0.105469 -0.257812 -0.167969 -0.410156 -0.175781 z m 3.484375 4.101562 v 1 h 3 v -1 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 2 0 c -1.214844 0 -2 0.828125 -2 2 v 12 c 0 1 1 2 2 2 h 11.984375 c 1 0 2 -1 2 -2 v -12 c 0 -1.238281 -0.828125 -2 -2 -2 z m 0 2 h 2 v 2 h -2 z m 3 0 h 2 v 2 h -2 z m 3 0 h 2 v 2 h -2 z m -6 4 h 11.984375 v 8 h -11.984375 z m 0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 382 B

View file

@ -1,46 +0,0 @@
import GLib from "gi://GLib"
const main = "/tmp/asztal/main.js"
const entry = `${App.configDir}/main.ts`
const bundler = GLib.getenv("AGS_BUNDLER") || "bun"
const v = {
ags: pkg.version?.split(".").map(Number) || [],
expect: [1, 8, 1],
}
try {
switch (bundler) {
case "bun": await Utils.execAsync([
"bun", "build", entry,
"--outfile", main,
"--external", "resource://*",
"--external", "gi://*",
"--external", "file://*",
]); break
case "esbuild": await Utils.execAsync([
"esbuild", "--bundle", entry,
"--format=esm",
`--outfile=${main}`,
"--external:resource://*",
"--external:gi://*",
"--external:file://*",
]); break
default:
throw `"${bundler}" is not a valid bundler`
}
if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) {
print(`my config needs at least v${v.expect.join(".")}, yours is v${v.ags.join(".")}`)
App.quit()
}
await import(`file://${main}`)
} catch (error) {
console.error(error)
App.quit()
}
export { }

View file

@ -1,103 +0,0 @@
{
inputs,
writeShellScript,
system,
stdenv,
cage,
swww,
esbuild,
dart-sass,
fd,
fzf,
brightnessctl,
accountsservice,
slurp,
wf-recorder,
wl-clipboard,
wayshot,
swappy,
hyprpicker,
pavucontrol,
networkmanager,
gtk3,
which,
}: let
name = "asztal";
ags = inputs.ags.packages.${system}.default.override {
extraPackages = [accountsservice];
};
dependencies = [
which
dart-sass
fd
fzf
brightnessctl
swww
inputs.matugen.packages.${system}.default
slurp
wf-recorder
wl-clipboard
wayshot
swappy
hyprpicker
pavucontrol
networkmanager
gtk3
];
addBins = list: builtins.concatStringsSep ":" (builtins.map (p: "${p}/bin") list);
greeter = writeShellScript "greeter" ''
export PATH=$PATH:${addBins dependencies}
${cage}/bin/cage -ds -m last ${ags}/bin/ags -- -c ${config}/greeter.js
'';
desktop = writeShellScript name ''
export PATH=$PATH:${addBins dependencies}
${ags}/bin/ags -b ${name} -c ${config}/config.js $@
'';
config = stdenv.mkDerivation {
inherit name;
src = ./.;
buildPhase = ''
${esbuild}/bin/esbuild \
--bundle ./main.ts \
--outfile=main.js \
--format=esm \
--external:resource://\* \
--external:gi://\* \
${esbuild}/bin/esbuild \
--bundle ./greeter/greeter.ts \
--outfile=greeter.js \
--format=esm \
--external:resource://\* \
--external:gi://\* \
'';
installPhase = ''
mkdir -p $out
cp -r assets $out
cp -r style $out
cp -r greeter $out
cp -r widget $out
cp -f main.js $out/config.js
cp -f greeter.js $out/greeter.js
'';
};
in
stdenv.mkDerivation {
inherit name;
src = config;
installPhase = ''
mkdir -p $out/bin
cp -r . $out
cp ${desktop} $out/bin/${name}
cp ${greeter} $out/bin/greeter
'';
}

View file

@ -1,18 +0,0 @@
const main = "/tmp/ags/greeter.js"
const entry = `${App.configDir}/greeter/greeter.ts`
try {
await Utils.execAsync([
"bun", "build", entry,
"--outfile", main,
"--external", "resource://*",
"--external", "gi://*",
"--external", "file://*",
])
await import(`file://${main}`)
} catch (error) {
console.error(error)
App.quit()
}
export { }

View file

@ -1,114 +0,0 @@
import GLib from "gi://GLib?version=2.0"
import icons from "lib/icons"
import { bash } from "lib/utils"
const userName = await bash("find /home -maxdepth 1 -printf '%f\n' | tail -n 1")
const iconFile = `/var/lib/AccountsService/icons/${userName}`
// FIXME: AccountsService crashes?
// import AccountsService from "gi://AccountsService?version=1.0"
// const { iconFile, realName, userName } = AccountsService.UserManager
// .get_default().list_users()[0]
const loggingin = Variable(false)
const CMD = GLib.getenv("ASZTAL_DM_CMD")
|| "Hyprland"
const ENV = GLib.getenv("ASZTAL_DM_ENV")
|| "WLR_NO_HARDWARE_CURSORS=1 _JAVA_AWT_WM_NONREPARENTING=1"
async function login(pw: string) {
loggingin.value = true
const greetd = await Service.import("greetd")
return greetd.login(userName, pw, CMD, ENV.split(/\s+/))
.catch(res => {
loggingin.value = false
response.label = res?.description || JSON.stringify(res)
password.text = ""
revealer.reveal_child = true
})
}
const avatar = Widget.Box({
class_name: "avatar",
hpack: "center",
css: `background-image: url('${iconFile}')`,
})
const password = Widget.Entry({
placeholder_text: "Password",
hexpand: true,
visibility: false,
on_accept: ({ text }) => { login(text || "") },
})
const response = Widget.Label({
class_name: "response",
wrap: true,
max_width_chars: 35,
hpack: "center",
hexpand: true,
xalign: .5,
})
const revealer = Widget.Revealer({
transition: "slide_down",
child: response,
})
export default Widget.Box({
class_name: "auth",
attribute: { password },
vertical: true,
children: [
Widget.Overlay({
child: Widget.Box(
{
css: "min-width: 200px; min-height: 200px;",
vertical: true,
},
Widget.Box({
class_name: "wallpaper",
css: `background-image: url('${WALLPAPER}')`,
}),
Widget.Box({
class_name: "wallpaper-contrast",
vexpand: true,
}),
),
overlay: Widget.Box(
{
vpack: "end",
vertical: true,
},
avatar,
Widget.Box({
hpack: "center",
children: [
Widget.Icon(icons.ui.avatar),
Widget.Label(userName),
],
}),
Widget.Box(
{
class_name: "password",
},
Widget.Spinner({
visible: loggingin.bind(),
active: true,
}),
Widget.Icon({
visible: loggingin.bind().as(b => !b),
icon: icons.ui.lock,
}),
password,
),
),
}),
Widget.Box(
{ class_name: "response-box" },
revealer,
),
],
})

View file

@ -1,37 +0,0 @@
import "./session"
import "style/style"
import GLib from "gi://GLib?version=2.0"
import RegularWindow from "widget/RegularWindow"
import statusbar from "./statusbar"
import auth from "./auth"
const win = RegularWindow({
name: "greeter",
setup: self => {
self.set_default_size(500, 500)
self.show_all()
auth.attribute.password.grab_focus()
},
child: Widget.Overlay({
child: Widget.Box({ expand: true }),
overlays: [
Widget.Box({
vpack: "start",
hpack: "fill",
hexpand: true,
child: statusbar,
}),
Widget.Box({
vpack: "center",
hpack: "center",
child: auth,
}),
],
}),
})
App.config({
icons: "./assets",
windows: [win],
cursorTheme: GLib.getenv("XCURSOR_THEME")!,
})

View file

@ -1,23 +0,0 @@
import GLib from "gi://GLib?version=2.0"
import { bash } from "lib/utils"
// import AccountsService from "gi://AccountsService?version=1.0"
// const { userName } = AccountsService.UserManager.get_default().list_users()[0]
const userName = await bash("find /home -maxdepth 1 -printf '%f\n' | tail -n 1")
declare global {
const WALLPAPER: string
}
Object.assign(globalThis, {
TMP: `${GLib.get_tmp_dir()}/greeter`,
OPTIONS: "/var/cache/greeter/options.json",
WALLPAPER: "/var/cache/greeter/background",
// TMP: "/tmp/ags",
// OPTIONS: Utils.CACHE_DIR + "/options.json",
// WALLPAPER: Utils.HOME + "/.config/background",
USER: userName,
})
Utils.ensureDirectory(TMP)

View file

@ -1,46 +0,0 @@
import { clock } from "lib/variables"
import options from "options"
import icons from "lib/icons"
import BatteryBar from "widget/bar/buttons/BatteryBar"
import PanelButton from "widget/bar/PanelButton"
const { scheme } = options.theme
const { monochrome } = options.bar.powermenu
const { format } = options.bar.date
const poweroff = PanelButton({
class_name: "powermenu",
child: Widget.Icon(icons.powermenu.shutdown),
on_clicked: () => Utils.exec("shutdown now"),
setup: self => self.hook(monochrome, () => {
self.toggleClassName("colored", !monochrome.value)
self.toggleClassName("box")
}),
})
const date = PanelButton({
class_name: "date",
child: Widget.Label({
label: clock.bind().as(c => c.format(`${format}`)!),
}),
})
const darkmode = PanelButton({
class_name: "darkmode",
child: Widget.Icon({ icon: scheme.bind().as(s => icons.color[s]) }),
on_clicked: () => scheme.value = scheme.value === "dark" ? "light" : "dark",
})
export default Widget.CenterBox({
class_name: "bar",
hexpand: true,
center_widget: date,
end_widget: Widget.Box({
hpack: "end",
children: [
darkmode,
BatteryBar(),
poweroff,
],
}),
})

View file

@ -1,16 +0,0 @@
import icons from "./icons"
export default async function init() {
const bat = await Service.import("battery")
bat.connect("notify::percent", ({ percent, charging }) => {
const low = 30
if (percent !== low || percent !== low / 2 || !charging)
return
Utils.notify({
summary: `${percent}% Battery Percentage`,
iconName: icons.battery.warning,
urgency: "critical",
})
})
}

View file

@ -1,16 +0,0 @@
import Gio from "gi://Gio"
import options from "options"
const settings = new Gio.Settings({
schema: "org.gnome.desktop.interface",
})
function gtk() {
const scheme = options.theme.scheme.value
settings.set_string("color-scheme", `prefer-${scheme}`)
}
export default function init() {
options.theme.scheme.connect("changed", gtk)
gtk()
}

View file

@ -1,82 +0,0 @@
import options from "options"
const { messageAsync } = await Service.import("hyprland")
const {
hyprland,
theme: {
spacing,
radius,
border: { width },
blur,
shadows,
dark: {
primary: { bg: darkActive },
},
light: {
primary: { bg: lightActive },
},
scheme,
},
} = options
const deps = [
"hyprland",
spacing.id,
radius.id,
blur.id,
width.id,
shadows.id,
darkActive.id,
lightActive.id,
scheme.id,
]
function primary() {
return scheme.value === "dark"
? darkActive.value
: lightActive.value
}
function rgba(color: string) {
return `rgba(${color}ff)`.replace("#", "")
}
function sendBatch(batch: string[]) {
const cmd = batch
.filter(x => !!x)
.map(x => `keyword ${x}`)
.join("; ")
return messageAsync(`[[BATCH]]/${cmd}`)
}
async function setupHyprland() {
const wm_gaps = Math.floor(hyprland.gaps.value * spacing.value)
sendBatch([
`general:border_size ${width}`,
`general:gaps_out ${wm_gaps}`,
`general:gaps_in ${Math.floor(wm_gaps / 2)}`,
`general:col.active_border ${rgba(primary())}`,
`general:col.inactive_border ${rgba(hyprland.inactiveBorder.value)}`,
`decoration:rounding ${radius}`,
`decoration:drop_shadow ${shadows.value ? "yes" : "no"}`,
`dwindle:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`,
`master:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`,
])
await sendBatch(App.windows.map(({ name }) => `layerrule unset, ${name}`))
if (blur.value > 0) {
sendBatch(App.windows.flatMap(({ name }) => [
`layerrule unset, ${name}`,
`layerrule blur, ${name}`,
`layerrule ignorealpha ${/* based on shadow color */.29}, ${name}`,
]))
}
}
export default function init() {
options.handler(deps, setupHyprland)
setupHyprland()
}

View file

@ -1,145 +0,0 @@
export const substitutes = {
"transmission-gtk": "transmission",
"blueberry.py": "blueberry",
"Caprine": "facebook-messenger",
"com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
"org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
"audio-headset-bluetooth": "audio-headphones-symbolic",
"audio-card-analog-usb": "audio-speakers-symbolic",
"audio-card-analog-pci": "audio-card-symbolic",
"preferences-system": "emblem-system-symbolic",
"com.github.Aylur.ags-symbolic": "controls-symbolic",
"com.github.Aylur.ags": "controls-symbolic",
}
export default {
missing: "image-missing-symbolic",
nix: {
nix: "nix-snowflake-symbolic",
},
app: {
terminal: "terminal-symbolic",
},
fallback: {
executable: "application-x-executable",
notification: "dialog-information-symbolic",
video: "video-x-generic-symbolic",
audio: "audio-x-generic-symbolic",
},
ui: {
close: "window-close-symbolic",
colorpicker: "color-select-symbolic",
info: "info-symbolic",
link: "external-link-symbolic",
lock: "system-lock-screen-symbolic",
menu: "open-menu-symbolic",
refresh: "view-refresh-symbolic",
search: "system-search-symbolic",
settings: "emblem-system-symbolic",
themes: "preferences-desktop-theme-symbolic",
tick: "object-select-symbolic",
time: "hourglass-symbolic",
toolbars: "toolbars-symbolic",
warning: "dialog-warning-symbolic",
avatar: "avatar-default-symbolic",
arrow: {
right: "pan-end-symbolic",
left: "pan-start-symbolic",
down: "pan-down-symbolic",
up: "pan-up-symbolic",
},
},
audio: {
mic: {
muted: "microphone-disabled-symbolic",
low: "microphone-sensitivity-low-symbolic",
medium: "microphone-sensitivity-medium-symbolic",
high: "microphone-sensitivity-high-symbolic",
},
volume: {
muted: "audio-volume-muted-symbolic",
low: "audio-volume-low-symbolic",
medium: "audio-volume-medium-symbolic",
high: "audio-volume-high-symbolic",
overamplified: "audio-volume-overamplified-symbolic",
},
type: {
headset: "audio-headphones-symbolic",
speaker: "audio-speakers-symbolic",
card: "audio-card-symbolic",
},
mixer: "mixer-symbolic",
},
powerprofile: {
balanced: "power-profile-balanced-symbolic",
"power-saver": "power-profile-power-saver-symbolic",
performance: "power-profile-performance-symbolic",
},
asusctl: {
profile: {
Balanced: "power-profile-balanced-symbolic",
Quiet: "power-profile-power-saver-symbolic",
Performance: "power-profile-performance-symbolic",
},
mode: {
Integrated: "processor-symbolic",
Hybrid: "controller-symbolic",
},
},
battery: {
charging: "battery-flash-symbolic",
warning: "battery-empty-symbolic",
},
bluetooth: {
enabled: "bluetooth-active-symbolic",
disabled: "bluetooth-disabled-symbolic",
},
brightness: {
indicator: "display-brightness-symbolic",
keyboard: "keyboard-brightness-symbolic",
screen: "display-brightness-symbolic",
},
powermenu: {
sleep: "weather-clear-night-symbolic",
reboot: "system-reboot-symbolic",
logout: "system-log-out-symbolic",
shutdown: "system-shutdown-symbolic",
},
recorder: {
recording: "media-record-symbolic",
},
notifications: {
noisy: "org.gnome.Settings-notifications-symbolic",
silent: "notifications-disabled-symbolic",
message: "chat-bubbles-symbolic",
},
trash: {
full: "user-trash-full-symbolic",
empty: "user-trash-symbolic",
},
mpris: {
shuffle: {
enabled: "media-playlist-shuffle-symbolic",
disabled: "media-playlist-consecutive-symbolic",
},
loop: {
none: "media-playlist-repeat-symbolic",
track: "media-playlist-repeat-song-symbolic",
playlist: "media-playlist-repeat-symbolic",
},
playing: "media-playback-pause-symbolic",
paused: "media-playback-start-symbolic",
stopped: "media-playback-start-symbolic",
prev: "media-skip-backward-symbolic",
next: "media-skip-forward-symbolic",
},
system: {
cpu: "org.gnome.SystemMonitor-symbolic",
ram: "drive-harddisk-solidstate-symbolic",
temp: "temperature-symbolic",
},
color: {
dark: "dark-mode-symbolic",
light: "light-mode-symbolic",
},
}

View file

@ -1,19 +0,0 @@
import matugen from "./matugen"
import hyprland from "./hyprland"
import tmux from "./tmux"
import gtk from "./gtk"
import lowBattery from "./battery"
import notifications from "./notifications"
export default function init() {
try {
gtk()
tmux()
matugen()
lowBattery()
notifications()
hyprland()
} catch (error) {
logError(error)
}
}

View file

@ -1,113 +0,0 @@
import wallpaper from "service/wallpaper"
import options from "options"
import { sh, dependencies } from "./utils"
export default function init() {
wallpaper.connect("changed", () => matugen())
options.autotheme.connect("changed", () => matugen())
}
function animate(...setters: Array<() => void>) {
const delay = options.transition.value / 2
setters.forEach((fn, i) => Utils.timeout(delay * i, fn))
}
export async function matugen(
type: "image" | "color" = "image",
arg = wallpaper.wallpaper,
) {
if (!options.autotheme.value || !dependencies("matugen"))
return
const colors = await sh(`matugen --dry-run -j hex ${type} ${arg}`)
const c = JSON.parse(colors).colors as { light: Colors, dark: Colors }
const { dark, light } = options.theme
animate(
() => {
dark.widget.value = c.dark.on_surface
light.widget.value = c.light.on_surface
},
() => {
dark.border.value = c.dark.outline
light.border.value = c.light.outline
},
() => {
dark.bg.value = c.dark.surface
light.bg.value = c.light.surface
},
() => {
dark.fg.value = c.dark.on_surface
light.fg.value = c.light.on_surface
},
() => {
dark.primary.bg.value = c.dark.primary
light.primary.bg.value = c.light.primary
options.bar.battery.charging.value = options.theme.scheme.value === "dark"
? c.dark.primary : c.light.primary
},
() => {
dark.primary.fg.value = c.dark.on_primary
light.primary.fg.value = c.light.on_primary
},
() => {
dark.error.bg.value = c.dark.error
light.error.bg.value = c.light.error
},
() => {
dark.error.fg.value = c.dark.on_error
light.error.fg.value = c.light.on_error
},
)
}
type Colors = {
background: string
error: string
error_container: string
inverse_on_surface: string
inverse_primary: string
inverse_surface: string
on_background: string
on_error: string
on_error_container: string
on_primary: string
on_primary_container: string
on_primary_fixed: string
on_primary_fixed_variant: string
on_secondary: string
on_secondary_container: string
on_secondary_fixed: string
on_secondary_fixed_variant: string
on_surface: string
on_surface_variant: string
on_tertiary: string
on_tertiary_container: string
on_tertiary_fixed: string
on_tertiary_fixed_variant: string
outline: string
outline_variant: string
primary: string
primary_container: string
primary_fixed: string
primary_fixed_dim: string
scrim: string
secondary: string
secondary_container: string
secondary_fixed: string
secondary_fixed_dim: string
shadow: string
surface: string
surface_bright: string
surface_container: string
surface_container_high: string
surface_container_highest: string
surface_container_low: string
surface_container_lowest: string
surface_dim: string
surface_variant: string
tertiary: string
tertiary_container: string
tertiary_fixed: string
tertiary_fixed_dim: string
}

View file

@ -1,16 +0,0 @@
import options from "options"
const notifs = await Service.import("notifications")
// TODO: consider adding this to upstream
const { blacklist } = options.notifications
export default function init() {
const notify = notifs.constructor.prototype.Notify.bind(notifs)
notifs.constructor.prototype.Notify = function(appName: string, ...rest: unknown[]) {
if (blacklist.value.includes(appName))
return Number.MAX_SAFE_INTEGER
return notify(appName, ...rest)
}
}

View file

@ -1,115 +0,0 @@
import { Variable } from "resource:///com/github/Aylur/ags/variable.js"
type OptProps = {
persistent?: boolean
}
export class Opt<T = unknown> extends Variable<T> {
static { Service.register(this) }
constructor(initial: T, { persistent = false }: OptProps = {}) {
super(initial)
this.initial = initial
this.persistent = persistent
}
initial: T
id = ""
persistent: boolean
toString() { return `${this.value}` }
toJSON() { return `opt:${this.value}` }
getValue = (): T => {
return super.getValue()
}
init(cacheFile: string) {
const cacheV = JSON.parse(Utils.readFile(cacheFile) || "{}")[this.id]
if (cacheV !== undefined)
this.value = cacheV
this.connect("changed", () => {
const cache = JSON.parse(Utils.readFile(cacheFile) || "{}")
cache[this.id] = this.value
Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile)
})
}
reset() {
if (this.persistent)
return
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
this.value = this.initial
return this.id
}
}
}
export const opt = <T>(initial: T, opts?: OptProps) => new Opt(initial, opts)
function getOptions(object: object, path = ""): Opt[] {
return Object.keys(object).flatMap(key => {
const obj: Opt = object[key]
const id = path ? path + "." + key : key
if (obj instanceof Variable) {
obj.id = id
return obj
}
if (typeof obj === "object")
return getOptions(obj, id)
return []
})
}
export function mkOptions<T extends object>(cacheFile: string, object: T) {
for (const opt of getOptions(object))
opt.init(cacheFile)
Utils.ensureDirectory(cacheFile.split("/").slice(0, -1).join("/"))
const configFile = `${TMP}/config.json`
const values = getOptions(object).reduce((obj, { id, value }) => ({ [id]: value, ...obj }), {})
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile)
Utils.monitorFile(configFile, () => {
const cache = JSON.parse(Utils.readFile(configFile) || "{}")
for (const opt of getOptions(object)) {
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value))
opt.value = cache[opt.id]
}
})
function sleep(ms = 0) {
return new Promise(r => setTimeout(r, ms))
}
async function reset(
[opt, ...list] = getOptions(object),
id = opt?.reset(),
): Promise<Array<string>> {
if (!opt)
return sleep().then(() => [])
return id
? [id, ...(await sleep(50).then(() => reset(list)))]
: await sleep().then(() => reset(list))
}
return Object.assign(object, {
configFile,
array: () => getOptions(object),
async reset() {
return (await reset()).join("\n")
},
handler(deps: string[], callback: () => void) {
for (const opt of getOptions(object)) {
if (deps.some(i => opt.id.startsWith(i)))
opt.connect("changed", callback)
}
},
})
}

View file

@ -1,16 +0,0 @@
import GLib from "gi://GLib?version=2.0"
declare global {
const OPTIONS: string
const TMP: string
const USER: string
}
Object.assign(globalThis, {
OPTIONS: `${GLib.get_user_cache_dir()}/ags/options.json`,
TMP: `${GLib.get_tmp_dir()}/asztal`,
USER: GLib.get_user_name(),
})
Utils.ensureDirectory(TMP)
App.addIcons(`${App.configDir}/assets`)

View file

@ -1,14 +0,0 @@
import options from "options"
import { sh } from "./utils"
export async function tmux() {
const { scheme, dark, light } = options.theme
const hex = scheme.value === "dark" ? dark.primary.bg.value : light.primary.bg.value
if (await sh("which tmux").catch(() => false))
sh(`tmux set @main_accent "${hex}"`)
}
export default function init() {
options.theme.dark.primary.bg.connect("changed", tmux)
options.theme.light.primary.bg.connect("changed", tmux)
}

View file

@ -1,113 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { type Application } from "types/service/applications"
import icons, { substitutes } from "./icons"
import Gtk from "gi://Gtk?version=3.0"
import Gdk from "gi://Gdk"
import GLib from "gi://GLib?version=2.0"
export type Binding<T> = import("types/service").Binding<any, any, T>
/**
* @returns substitute icon || name || fallback icon
*/
export function icon(name: string | null, fallback = icons.missing) {
if (!name)
return fallback || ""
if (GLib.file_test(name, GLib.FileTest.EXISTS))
return name
const icon = (substitutes[name] || name)
if (Utils.lookUpIcon(icon))
return icon
print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`)
return fallback
}
/**
* @returns execAsync(["bash", "-c", cmd])
*/
export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]) {
const cmd = typeof strings === "string" ? strings : strings
.flatMap((str, i) => str + `${values[i] ?? ""}`)
.join("")
return Utils.execAsync(["bash", "-c", cmd]).catch(err => {
console.error(cmd, err)
return ""
})
}
/**
* @returns execAsync(cmd)
*/
export async function sh(cmd: string | string[]) {
return Utils.execAsync(cmd).catch(err => {
console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err)
return ""
})
}
export function forMonitors(widget: (monitor: number) => Gtk.Window) {
const n = Gdk.Display.get_default()?.get_n_monitors() || 1
return range(n, 0).flatMap(widget)
}
/**
* @returns [start...length]
*/
export function range(length: number, start = 1) {
return Array.from({ length }, (_, i) => i + start)
}
/**
* @returns true if all of the `bins` are found
*/
export function dependencies(...bins: string[]) {
const missing = bins.filter(bin => Utils.exec({
cmd: `which ${bin}`,
out: () => false,
err: () => true,
}))
if (missing.length > 0) {
console.warn(Error(`missing dependencies: ${missing.join(", ")}`))
Utils.notify(`missing dependencies: ${missing.join(", ")}`)
}
return missing.length === 0
}
/**
* run app detached
*/
export function launchApp(app: Application) {
const exe = app.executable
.split(/\s+/)
.filter(str => !str.startsWith("%") && !str.startsWith("@"))
.join(" ")
bash(`${exe} &`)
app.frequency += 1
}
/**
* to use with drag and drop
*/
export function createSurfaceFromWidget(widget: Gtk.Widget) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cairo = imports.gi.cairo as any
const alloc = widget.get_allocation()
const surface = new cairo.ImageSurface(
cairo.Format.ARGB32,
alloc.width,
alloc.height,
)
const cr = new cairo.Context(surface)
cr.setSourceRGBA(255, 255, 255, 0)
cr.rectangle(0, 0, alloc.width, alloc.height)
cr.fill()
widget.draw(cr)
return surface
}

View file

@ -1,42 +0,0 @@
import GLib from "gi://GLib"
// import options from "options"
//
// const intval = options.system.fetchInterval.value
// const tempPath = options.system.temperature.value
export const clock = Variable(GLib.DateTime.new_now_local(), {
poll: [1000, () => GLib.DateTime.new_now_local()],
})
export const uptime = Variable(0, {
poll: [60_000, "cat /proc/uptime", line =>
Number.parseInt(line.split(".")[0]) / 60,
],
})
export const distro = {
id: GLib.get_os_info("ID"),
logo: GLib.get_os_info("LOGO"),
}
// const divide = ([total, free]: string[]) => Number.parseInt(free) / Number.parseInt(total)
//
// export const cpu = Variable(0, {
// poll: [intval, "top -b -n 1", out => divide(["100", out.split("\n")
// .find(line => line.includes("Cpu(s)"))
// ?.split(/\s+/)[1]
// .replace(",", ".") || "0"])],
// })
//
// export const ram = Variable(0, {
// poll: [intval, "free", out => divide(out.split("\n")
// .find(line => line.includes("Mem:"))
// ?.split(/\s+/)
// .splice(1, 2) || ["1", "1"])],
// })
//
// export const temperature = Variable(0, {
// poll: [intval, `cat ${tempPath}`, n => {
// return Number.parseInt(n) / 100_000
// }],
// })

View file

@ -1,41 +0,0 @@
import "lib/session"
import "style/style"
import init from "lib/init"
import options from "options"
import Bar from "widget/bar/Bar"
import Launcher from "widget/launcher/Launcher"
import NotificationPopups from "widget/notifications/NotificationPopups"
import OSD from "widget/osd/OSD"
import Overview from "widget/overview/Overview"
import PowerMenu from "widget/powermenu/PowerMenu"
import ScreenCorners from "widget/bar/ScreenCorners"
import SettingsDialog from "widget/settings/SettingsDialog"
import Verification from "widget/powermenu/Verification"
import { forMonitors } from "lib/utils"
import { setupQuickSettings } from "widget/quicksettings/QuickSettings"
import { setupDateMenu } from "widget/datemenu/DateMenu"
App.config({
onConfigParsed: () => {
setupQuickSettings()
setupDateMenu()
init()
},
closeWindowDelay: {
"launcher": options.transition.value,
"overview": options.transition.value,
"quicksettings": options.transition.value,
"datemenu": options.transition.value,
},
windows: () => [
...forMonitors(Bar),
...forMonitors(NotificationPopups),
...forMonitors(ScreenCorners),
...forMonitors(OSD),
Launcher(),
Overview(),
PowerMenu(),
SettingsDialog(),
Verification(),
],
})

View file

@ -1,243 +0,0 @@
import { opt, mkOptions } from "lib/option"
import { distro } from "lib/variables"
import { icon } from "lib/utils"
import icons from "lib/icons"
const options = mkOptions(OPTIONS, {
autotheme: opt(false),
wallpaper: {
resolution: opt<import("service/wallpaper").Resolution>(1920),
market: opt<import("service/wallpaper").Market>("random"),
},
theme: {
dark: {
primary: {
bg: opt("#51a4e7"),
fg: opt("#141414"),
},
error: {
bg: opt("#e55f86"),
fg: opt("#141414"),
},
bg: opt("#171717"),
fg: opt("#eeeeee"),
widget: opt("#eeeeee"),
border: opt("#eeeeee"),
},
light: {
primary: {
bg: opt("#426ede"),
fg: opt("#eeeeee"),
},
error: {
bg: opt("#b13558"),
fg: opt("#eeeeee"),
},
bg: opt("#fffffa"),
fg: opt("#080808"),
widget: opt("#080808"),
border: opt("#080808"),
},
blur: opt(0),
scheme: opt<"dark" | "light">("dark"),
widget: { opacity: opt(94) },
border: {
width: opt(1),
opacity: opt(96),
},
shadows: opt(true),
padding: opt(7),
spacing: opt(12),
radius: opt(11),
},
transition: opt(200),
font: {
size: opt(13),
name: opt("Ubuntu Nerd Font"),
},
bar: {
flatButtons: opt(true),
position: opt<"top" | "bottom">("top"),
corners: opt(50),
transparent: opt(false),
layout: {
start: opt<Array<import("widget/bar/Bar").BarWidget>>([
"launcher",
"workspaces",
"taskbar",
"expander",
"messages",
]),
center: opt<Array<import("widget/bar/Bar").BarWidget>>([
"date",
]),
end: opt<Array<import("widget/bar/Bar").BarWidget>>([
"media",
"expander",
"systray",
"colorpicker",
"screenrecord",
"system",
"battery",
"powermenu",
]),
},
launcher: {
icon: {
colored: opt(true),
icon: opt(icon(distro.logo, icons.ui.search)),
},
label: {
colored: opt(false),
label: opt(" Applications"),
},
action: opt(() => App.toggleWindow("launcher")),
},
date: {
format: opt("%H:%M - %A %e."),
action: opt(() => App.toggleWindow("datemenu")),
},
battery: {
bar: opt<"hidden" | "regular" | "whole">("regular"),
charging: opt("#00D787"),
percentage: opt(true),
blocks: opt(7),
width: opt(50),
low: opt(30),
},
workspaces: {
workspaces: opt(7),
},
taskbar: {
iconSize: opt(0),
monochrome: opt(true),
exclusive: opt(false),
},
messages: {
action: opt(() => App.toggleWindow("datemenu")),
},
systray: {
ignore: opt([
"KDE Connect Indicator",
"spotify-client",
]),
},
media: {
monochrome: opt(true),
preferred: opt("spotify"),
direction: opt<"left" | "right">("right"),
format: opt("{artists} - {title}"),
length: opt(40),
},
powermenu: {
monochrome: opt(false),
action: opt(() => App.toggleWindow("powermenu")),
},
},
launcher: {
width: opt(0),
margin: opt(80),
nix: {
pkgs: opt("nixpkgs/nixos-unstable"),
max: opt(8),
},
sh: {
max: opt(16),
},
apps: {
iconSize: opt(62),
max: opt(6),
favorites: opt([
[
"firefox",
"wezterm",
"org.gnome.Nautilus",
"org.gnome.Calendar",
"spotify",
],
]),
},
},
overview: {
scale: opt(9),
workspaces: opt(7),
monochromeIcon: opt(true),
},
powermenu: {
sleep: opt("systemctl suspend"),
reboot: opt("systemctl reboot"),
logout: opt("pkill Hyprland"),
shutdown: opt("shutdown now"),
layout: opt<"line" | "box">("line"),
labels: opt(true),
},
quicksettings: {
avatar: {
image: opt(`/var/lib/AccountsService/icons/${Utils.USER}`),
size: opt(70),
},
width: opt(380),
position: opt<"left" | "center" | "right">("right"),
networkSettings: opt("gtk-launch gnome-control-center"),
media: {
monochromeIcon: opt(true),
coverSize: opt(100),
},
},
datemenu: {
position: opt<"left" | "center" | "right">("center"),
weather: {
interval: opt(60_000),
unit: opt<"metric" | "imperial" | "standard">("metric"),
key: opt<string>(
JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || "{}")?.key || "",
),
cities: opt<Array<number>>(
JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || "{}")?.cities || [],
),
},
},
osd: {
progress: {
vertical: opt(true),
pack: {
h: opt<"start" | "center" | "end">("end"),
v: opt<"start" | "center" | "end">("center"),
},
},
microphone: {
pack: {
h: opt<"start" | "center" | "end">("center"),
v: opt<"start" | "center" | "end">("end"),
},
},
},
notifications: {
position: opt<Array<"top" | "bottom" | "left" | "right">>(["top", "right"]),
blacklist: opt(["Spotify"]),
width: opt(440),
},
hyprland: {
gaps: opt(2.4),
inactiveBorder: opt("#282828"),
gapsWhenOnly: opt(false),
},
})
globalThis["options"] = options
export default options

View file

@ -1,19 +0,0 @@
{
"name": "ags-dotfiles",
"author": "Aylur",
"kofi": "https://ko-fi.com/aylur",
"repository": {
"type": "git",
"url": "git+https://github.com/Aylur/dotfiles.git"
},
"devDependencies": {
"@girs/accountsservice-1.0": "^1.0.0-3.2.7",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"eslint": "^8.56.0",
"eslint-config-standard-with-typescript": "^43.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1",
"typescript": "^5.3.3"
}
}

View file

@ -1,55 +0,0 @@
import { sh } from "lib/utils"
type Profile = "Performance" | "Balanced" | "Quiet"
type Mode = "Hybrid" | "Integrated"
class Asusctl extends Service {
static {
Service.register(this, {}, {
"profile": ["string", "r"],
"mode": ["string", "r"],
})
}
get available() {
return Utils.exec("which asusctl", () => true, () => false)
}
#profile: Profile = "Balanced"
#mode: Mode = "Hybrid"
async nextProfile() {
await sh("asusctl profile -n")
const profile = await sh("asusctl profile -p")
const p = profile.split(" ")[3] as Profile
this.#profile = p
this.changed("profile")
}
async setProfile(prof: Profile) {
await sh(`asusctl profile --profile-set ${prof}`)
this.#profile = prof
this.changed("profile")
}
async nextMode() {
await sh(`supergfxctl -m ${this.#mode === "Hybrid" ? "Integrated" : "Hybrid"}`)
this.#mode = await sh("supergfxctl -g") as Mode
this.changed("profile")
}
constructor() {
super()
if (this.available) {
sh("asusctl profile -p").then(p => this.#profile = p.split(" ")[3] as Profile)
sh("supergfxctl -g").then(m => this.#mode = m as Mode)
}
}
get profiles(): Profile[] { return ["Performance", "Balanced", "Quiet"] }
get profile() { return this.#profile }
get mode() { return this.#mode }
}
export default new Asusctl

View file

@ -1,69 +0,0 @@
import { bash, dependencies, sh } from "lib/utils"
if (!dependencies("brightnessctl"))
App.quit()
const get = (args: string) => Number(Utils.exec(`brightnessctl ${args}`))
const screen = await bash`ls -w1 /sys/class/backlight | head -1`
const kbd = await bash`ls -w1 /sys/class/leds | head -1`
class Brightness extends Service {
static {
Service.register(this, {}, {
"screen": ["float", "rw"],
"kbd": ["int", "rw"],
})
}
#kbdMax = get(`--device ${kbd} max`)
#kbd = get(`--device ${kbd} get`)
#screenMax = get("max")
#screen = get("get") / (get("max") || 1)
get kbd() { return this.#kbd }
get screen() { return this.#screen }
set kbd(value) {
if (value < 0 || value > this.#kbdMax)
return
sh(`brightnessctl -d ${kbd} s ${value} -q`).then(() => {
this.#kbd = value
this.changed("kbd")
})
}
set screen(percent) {
if (percent < 0)
percent = 0
if (percent > 1)
percent = 1
sh(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => {
this.#screen = percent
this.changed("screen")
})
}
constructor() {
super()
const screenPath = `/sys/class/backlight/${screen}/brightness`
const kbdPath = `/sys/class/leds/${kbd}/brightness`
Utils.monitorFile(screenPath, async f => {
const v = await Utils.readFileAsync(f)
this.#screen = Number(v) / this.#screenMax
this.changed("screen")
})
Utils.monitorFile(kbdPath, async f => {
const v = await Utils.readFileAsync(f)
this.#kbd = Number(v) / this.#kbdMax
this.changed("kbd")
})
}
}
export default new Brightness

View file

@ -1,56 +0,0 @@
import icons from "lib/icons"
import { bash, dependencies } from "lib/utils"
const COLORS_CACHE = Utils.CACHE_DIR + "/colorpicker.json"
const MAX_NUM_COLORS = 10
class ColorPicker extends Service {
static {
Service.register(this, {}, {
"colors": ["jsobject"],
})
}
#notifID = 0
#colors = JSON.parse(Utils.readFile(COLORS_CACHE) || "[]") as string[]
get colors() { return [...this.#colors] }
set colors(colors) {
this.#colors = colors
this.changed("colors")
}
// TODO: doesn't work?
async wlCopy(color: string) {
if (dependencies("wl-copy"))
bash(`wl-copy ${color}`)
}
readonly pick = async () => {
if (!dependencies("hyprpicker"))
return
const color = await bash("hyprpicker -a -r")
if (!color)
return
this.wlCopy(color)
const list = this.colors
if (!list.includes(color)) {
list.push(color)
if (list.length > MAX_NUM_COLORS)
list.shift()
this.colors = list
Utils.writeFile(JSON.stringify(list, null, 2), COLORS_CACHE)
}
this.#notifID = await Utils.notify({
id: this.#notifID,
iconName: icons.ui.colorpicker,
summary: color,
})
}
}
export default new ColorPicker

View file

@ -1,110 +0,0 @@
import icons from "lib/icons"
import { bash, dependencies } from "lib/utils"
import options from "options"
const CACHE = `${Utils.CACHE_DIR}/nixpkgs`
const PREFIX = "legacyPackages.x86_64-linux."
const MAX = options.launcher.nix.max
const nixpkgs = options.launcher.nix.pkgs
export type Nixpkg = {
name: string
description: string
pname: string
version: string
}
class Nix extends Service {
static {
Service.register(this, {}, {
"available": ["boolean", "r"],
"ready": ["boolean", "rw"],
})
}
#db: { [name: string]: Nixpkg } = {}
#ready = true
private set ready(r: boolean) {
this.#ready = r
this.changed("ready")
}
get db() { return this.#db }
get ready() { return this.#ready }
get available() {
return Utils.exec("which nix", () => true, () => false)
}
constructor() {
super()
if (!this.available)
return this
this.#updateList()
nixpkgs.connect("changed", this.#updateList)
}
query = async (filter: string) => {
if (!dependencies("fzf", "nix") || !this.#ready)
return [] as string[]
return bash(`cat ${CACHE} | fzf -f ${filter} -e | head -n ${MAX} `)
.then(str => str.split("\n").filter(i => i))
}
nix(cmd: string, bin: string, args: string) {
return Utils.execAsync(`nix ${cmd} ${nixpkgs}#${bin} --impure ${args}`)
}
run = async (input: string) => {
if (!dependencies("nix"))
return
try {
const [bin, ...args] = input.trim().split(/\s+/)
this.ready = false
await this.nix("shell", bin, "--command sh -c 'exit'")
this.ready = true
this.nix("run", bin, ["--", ...args].join(" "))
} catch (err) {
if (typeof err === "string")
Utils.notify("NixRun Error", err, icons.nix.nix)
else
logError(err)
} finally {
this.ready = true
}
}
#updateList = async () => {
if (!dependencies("nix"))
return
this.ready = false
this.#db = {}
const search = await bash(`nix search ${nixpkgs} --json`)
if (!search) {
this.ready = true
return
}
const json = Object.entries(JSON.parse(search) as {
[name: string]: Nixpkg
})
for (const [pkg, info] of json) {
const name = pkg.replace(PREFIX, "")
this.#db[name] = { ...info, name }
}
const list = Object.keys(this.#db).join("\n")
await Utils.writeFile(list, CACHE)
this.ready = true
}
}
export default new Nix

View file

@ -1,47 +0,0 @@
import options from "options"
const { sleep, reboot, logout, shutdown } = options.powermenu
export type Action = "sleep" | "reboot" | "logout" | "shutdown"
class PowerMenu extends Service {
static {
Service.register(this, {}, {
"title": ["string"],
"cmd": ["string"],
})
}
#title = ""
#cmd = ""
get title() { return this.#title }
action(action: Action) {
[this.#cmd, this.#title] = {
sleep: [sleep.value, "Sleep"],
reboot: [reboot.value, "Reboot"],
logout: [logout.value, "Log Out"],
shutdown: [shutdown.value, "Shutdown"],
}[action]
this.notify("cmd")
this.notify("title")
this.emit("changed")
App.closeWindow("powermenu")
App.openWindow("verification")
}
readonly shutdown = () => {
this.action("shutdown")
}
readonly exec = () => {
App.closeWindow("verification")
Utils.exec(this.#cmd)
}
}
const powermenu = new PowerMenu
Object.assign(globalThis, { powermenu })
export default powermenu

View file

@ -1,102 +0,0 @@
import GLib from "gi://GLib"
import icons from "lib/icons"
import { dependencies, sh, bash } from "lib/utils"
const now = () => GLib.DateTime.new_now_local().format("%Y-%m-%d_%H-%M-%S")
class Recorder extends Service {
static {
Service.register(this, {}, {
"timer": ["int"],
"recording": ["boolean"],
})
}
#recordings = Utils.HOME + "/Videos/Screencasting"
#screenshots = Utils.HOME + "/Pictures/Screenshots"
#file = ""
#interval = 0
recording = false
timer = 0
async start() {
if (!dependencies("slurp", "wf-recorder"))
return
if (this.recording)
return
Utils.ensureDirectory(this.#recordings)
this.#file = `${this.#recordings}/${now()}.mp4`
sh(`wf-recorder -g "${await sh("slurp")}" -f ${this.#file} --pixel-format yuv420p`)
this.recording = true
this.changed("recording")
this.timer = 0
this.#interval = Utils.interval(1000, () => {
this.changed("timer")
this.timer++
})
}
async stop() {
if (!this.recording)
return
await bash("killall -INT wf-recorder")
this.recording = false
this.changed("recording")
GLib.source_remove(this.#interval)
Utils.notify({
iconName: icons.fallback.video,
summary: "Screenrecord",
body: this.#file,
actions: {
"Show in Files": () => sh(`xdg-open ${this.#recordings}`),
"View": () => sh(`xdg-open ${this.#file}`),
},
})
}
async screenshot(full = false) {
if (!dependencies("slurp", "wayshot"))
return
const file = `${this.#screenshots}/${now()}.png`
Utils.ensureDirectory(this.#screenshots)
if (full) {
await sh(`wayshot -f ${file}`)
}
else {
const size = await sh("slurp")
if (!size)
return
await sh(`wayshot -f ${file} -s "${size}"`)
}
bash(`wl-copy < ${file}`)
Utils.notify({
image: file,
summary: "Screenshot",
body: file,
actions: {
"Show in Files": () => sh(`xdg-open ${this.#screenshots}`),
"View": () => sh(`xdg-open ${file}`),
"Edit": () => {
if (dependencies("swappy"))
sh(`swappy -f ${file}`)
},
},
})
}
}
const recorder = new Recorder
Object.assign(globalThis, { recorder })
export default recorder

View file

@ -1,48 +0,0 @@
import GLib from "gi://GLib?version=2.0"
import { bash, dependencies } from "lib/utils"
import icons from "lib/icons"
import options from "options"
const MAX = options.launcher.sh.max
const BINS = `${Utils.CACHE_DIR}/binaries`
async function ls(path: string) {
return Utils.execAsync(`ls ${path}`).catch(() => "")
}
async function reload() {
const bins = await Promise.all(GLib.getenv("PATH")!
.split(":")
.map(ls))
Utils.writeFile(bins.join("\n"), BINS)
}
async function query(filter: string) {
if (!dependencies("fzf"))
return [] as string[]
return bash(`cat ${BINS} | fzf -f ${filter} | head -n ${MAX}`)
.then(str => Array.from(new Set(str.split("\n").filter(i => i)).values()))
.catch(err => { print(err); return [] })
}
function run(args: string) {
Utils.execAsync(args)
.then(out => {
print(`:sh ${args.trim()}:`)
print(out)
})
.catch(err => {
Utils.notify("ShRun Error", err, icons.app.terminal)
})
}
class Sh extends Service {
static { Service.register(this) }
constructor() { super(); reload() }
query = query
run = run
}
export default new Sh

View file

@ -1,99 +0,0 @@
import options from "options"
import { dependencies, sh } from "lib/utils"
export type Resolution = 1920 | 1366 | 3840
export type Market =
| "random"
| "en-US"
| "ja-JP"
| "en-AU"
| "en-GB"
| "de-DE"
| "en-NZ"
| "en-CA"
const WP = `${Utils.HOME}/.config/background`
const Cache = `${Utils.HOME}/Pictures/Wallpapers/Bing`
class Wallpaper extends Service {
static {
Service.register(this, {}, {
"wallpaper": ["string"],
})
}
#blockMonitor = false
#wallpaper() {
if (!dependencies("swww"))
return
sh("hyprctl cursorpos").then(pos => {
sh([
"swww", "img",
"--invert-y",
"--transition-type", "grow",
"--transition-pos", pos.replace(" ", ""),
WP,
]).then(() => {
this.changed("wallpaper")
})
})
}
async #setWallpaper(path: string) {
this.#blockMonitor = true
await sh(`cp ${path} ${WP}`)
this.#wallpaper()
this.#blockMonitor = false
}
async #fetchBing() {
const res = await Utils.fetch("https://bing.biturl.top/", {
params: {
resolution: options.wallpaper.resolution.value,
format: "json",
image_format: "jpg",
index: "random",
mkt: options.wallpaper.market.value,
},
}).then(res => res.text())
if (!res.startsWith("{"))
return console.warn("bing api", res)
const { url } = JSON.parse(res)
const file = `${Cache}/${url.replace("https://www.bing.com/th?id=", "")}`
if (dependencies("curl")) {
Utils.ensureDirectory(Cache)
await sh(`curl "${url}" --output ${file}`)
this.#setWallpaper(file)
}
}
readonly random = () => { this.#fetchBing() }
readonly set = (path: string) => { this.#setWallpaper(path) }
get wallpaper() { return WP }
constructor() {
super()
if (!dependencies("swww"))
return this
// gtk portal
Utils.monitorFile(WP, () => {
if (!this.#blockMonitor)
this.#wallpaper()
})
Utils.execAsync("swww-daemon")
.then(this.#wallpaper)
.catch(() => null)
}
}
export default new Wallpaper

View file

@ -1,59 +0,0 @@
import options from "options"
const { interval, key, cities, unit } = options.datemenu.weather
class Weather extends Service {
static {
Service.register(this, {}, {
"forecasts": ["jsobject"],
})
}
#forecasts: Forecast[] = []
get forecasts() { return this.#forecasts }
async #fetch(placeid: number) {
const url = "https://api.openweathermap.org/data/2.5/forecast"
const res = await Utils.fetch(url, {
params: {
id: placeid,
appid: key.value,
untis: unit.value,
},
})
return await res.json()
}
constructor() {
super()
if (!key.value)
return this
Utils.interval(interval.value, () => {
Promise.all(cities.value.map(this.#fetch)).then(forecasts => {
this.#forecasts = forecasts as Forecast[]
this.changed("forecasts")
})
})
}
}
export default new Weather
type Forecast = {
city: {
name: string,
}
list: Array<{
dt: number
main: {
temp: number
feels_like: number
},
weather: Array<{
main: string,
description: string,
icon: string,
}>
}>
}

View file

@ -1,67 +0,0 @@
@import './mixins/button.scss';
* {
font-size: $font-size;
font-family: $font-name;
}
separator {
&.horizontal {
min-height: $border-width;
}
&.vertical {
min-width: $border-width;
}
}
window.popup {
>* {
border: none;
box-shadow: none;
}
menu {
border-radius: $popover-radius;
background-color: $bg;
padding: $popover-padding;
border: $border-width solid $popover-border-color;
separator {
background-color: $border-color;
}
menuitem {
@include button;
padding: $spacing * .5;
margin: ($spacing * .5) 0;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}
}
tooltip {
* {
all: unset;
}
background-color: transparent;
border: none;
>*>* {
background-color: $bg;
border-radius: $radius;
border: $border-width solid $popover-border-color;
color: $fg;
padding: 8px;
margin: 4px;
box-shadow: 0 0 3px 0 $shadow-color;
}
}

View file

@ -1,48 +0,0 @@
@import './button';
@mixin accs-button($flat: false, $reactive: true) {
@include unset;
color: $fg;
>* {
border-radius: $radius;
transition: $transition;
@if $flat {
background-color: transparent;
box-shadow: none;
}
@else {
background-color: $widget-bg;
box-shadow: inset 0 0 0 $border-width $border-color;
}
}
@if $reactive {
&:focus>*,
&.focused>* {
@include button-focus;
}
&:hover>* {
@include button-hover;
}
&:active,
&.active,
&.on,
&:checked {
>* {
@include button-active;
}
&:hover>* {
box-shadow: inset 0 0 0 $border-width $border-color,
inset 0 0 0 99px $hover-bg;
}
}
}
}

View file

@ -1,70 +0,0 @@
@mixin button-focus() {
box-shadow: inset 0 0 0 $border-width $primary-bg;
background-color: $hover-bg;
color: $hover-fg;
}
@mixin button-hover() {
box-shadow: inset 0 0 0 $border-width $border-color;
background-color: $hover-bg;
color: $hover-fg;
}
@mixin button-active() {
box-shadow: inset 0 0 0 $border-width $border-color;
background-image: $active-gradient;
background-color: $primary-bg;
color: $primary-fg;
}
@mixin button-disabled() {
box-shadow: none;
background-color: transparent;
color: transparentize($fg, 0.7);
}
@mixin button($flat: false, $reactive: true, $radius: $radius, $focusable: true) {
all: unset;
transition: $transition;
border-radius: $radius;
color: $fg;
@if $flat {
background-color: transparent;
background-image: none;
box-shadow: none;
}
@else {
background-color: $widget-bg;
box-shadow: inset 0 0 0 $border-width $border-color;
}
@if $reactive {
@if $focusable {
&:focus {
@include button-focus;
}
}
&:hover {
@include button-hover;
}
&:active,
&.on,
&.active,
&:checked {
@include button-active;
&:hover {
box-shadow: inset 0 0 0 $border-width $border-color,
inset 0 0 0 99px $hover-bg;
}
}
}
&:disabled {
@include button-disabled;
}
}

View file

@ -1,12 +0,0 @@
@mixin floating-widget {
@if $shadows {
box-shadow: 0 0 5px 0 $shadow-color;
}
margin: max($spacing, 8px);
border: $border-width solid $popover-border-color;
background-color: $bg;
color: $fg;
border-radius: $popover-radius;
padding: $popover-padding;
}

View file

@ -1,15 +0,0 @@
@mixin hidden {
background-color: transparent;
background-image: none;
border-color: transparent;
box-shadow: none;
-gtk-icon-transform: scale(0);
* {
background-color: transparent;
background-image: none;
border-color: transparent;
box-shadow: none;
-gtk-icon-transform: scale(0);
}
}

View file

@ -1,42 +0,0 @@
@mixin media() {
@include widget;
padding: $padding;
.cover {
@if $shadows {
box-shadow: 2px 2px 2px 0 $shadow-color;
}
background-size: cover;
background-position: center;
border-radius: $radius*0.8;
margin-right: $spacing;
}
button {
@include button($flat: true);
padding: $padding * .5;
&.play-pause {
margin: 0 ($spacing * .5);
}
image {
font-size: 1.2em;
}
}
.artist {
color: transparentize($fg, .2);
font-size: .9em;
}
scale {
@include slider($width: .5em, $slider: false, $gradient: linear-gradient($fg, $fg));
margin-bottom: $padding * .5;
trough {
border: none;
}
}
}

View file

@ -1,42 +0,0 @@
@mixin scrollable($top: false, $bottom: false) {
@if $top and $shadows {
undershoot.top {
background: linear-gradient(to bottom, $shadow-color, transparent, transparent, transparent, transparent, transparent);
}
}
@if $bottom and $shadows {
undershoot.bottom {
background: linear-gradient(to top, $shadow-color, transparent, transparent, transparent, transparent, transparent);
}
}
scrollbar,
scrollbar * {
all: unset;
}
scrollbar.vertical {
transition: $transition;
background-color: transparentize($bg, 0.7);
&:hover {
background-color: transparentize($bg, 0.3);
slider {
background-color: transparentize($fg, 0.3);
min-width: .6em;
}
}
}
scrollbar.vertical slider {
background-color: transparentize($fg, 0.5);
border-radius: $radius;
min-width: .4em;
min-height: 2em;
transition: $transition;
}
}

View file

@ -1,74 +0,0 @@
@import './unset';
@mixin slider($width: 0.7em, $slider-width: .5em, $gradient: $active-gradient, $slider: true, $focusable: true, $radius: $radius) {
@include unset($rec: true);
trough {
transition: $transition;
border-radius: $radius;
border: $border;
background-color: $widget-bg;
min-height: $width;
min-width: $width;
highlight,
progress {
border-radius: max($radius - $border-width, 0);
background-image: $gradient;
min-height: $width;
min-width: $width;
}
}
slider {
box-shadow: none;
background-color: transparent;
border: $border-width solid transparent;
transition: $transition;
border-radius: $radius;
min-height: $width;
min-width: $width;
margin: -$slider-width;
}
&:hover {
trough {
background-color: $hover-bg;
}
slider {
@if $slider {
background-color: $fg;
border-color: $border-color;
@if $shadows {
box-shadow: 0 0 3px 0 $shadow-color;
}
}
}
}
&:disabled {
highlight,
progress {
background-color: transparentize($fg, 0.4);
background-image: none;
}
}
@if $focusable {
trough:focus {
background-color: $hover-bg;
box-shadow: inset 0 0 0 $border-width $primary-bg;
slider {
@if $slider {
background-color: $fg;
box-shadow: inset 0 0 0 $border-width $primary-bg;
}
}
}
}
}

View file

@ -1,53 +0,0 @@
@mixin spacing($multiplier: 1, $spacing: $spacing, $rec: false) {
&.horizontal>* {
margin: 0 calc($spacing * $multiplier / 2);
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
&.vertical>* {
margin: calc($spacing * $multiplier / 2) 0;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
@if $rec {
box {
&.horizontal>* {
margin: 0 $spacing * $multiplier / 2;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
&.vertical>* {
margin: $spacing * $multiplier / 2 0;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}
}
}

View file

@ -1,16 +0,0 @@
@import './button';
@mixin switch {
@include button;
slider {
background-color: $primary-fg;
border-radius: $radius;
min-width: 24px;
min-height: 24px;
}
image {
color: transparent;
}
}

View file

@ -1,9 +0,0 @@
@mixin unset($rec: false) {
all: unset;
@if $rec {
* {
all: unset
}
}
}

View file

@ -1,7 +0,0 @@
@mixin widget {
transition: $transition;
border-radius: $radius;
color: $fg;
background-color: $widget-bg;
border: $border;
}

View file

@ -1,115 +0,0 @@
/* eslint-disable max-len */
import { type Opt } from "lib/option"
import { bash, dependencies } from "lib/utils"
import options from "options"
const deps = [
"font",
"theme",
"bar.corners",
"bar.flatButtons",
"bar.position",
"bar.battery.charging",
"bar.battery.blocks",
]
const {
dark,
light,
blur,
scheme,
padding,
spacing,
radius,
shadows,
widget,
border,
} = options.theme
const popoverPaddingMultiplier = 1.6
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const t = (dark: Opt<any> | string, light: Opt<any> | string) => scheme.value === "dark"
? `${dark}` : `${light}`
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const $ = (name: string, value: string | Opt<any>) => `$${name}: ${value};`
const variables = () => [
$("bg", blur.value ? `transparentize(${t(dark.bg, light.bg)}, ${blur.value / 100})` : t(dark.bg, light.bg)),
$("fg", t(dark.fg, light.fg)),
$("primary-bg", t(dark.primary.bg, light.primary.bg)),
$("primary-fg", t(dark.primary.fg, light.primary.fg)),
$("error-bg", t(dark.error.bg, light.error.bg)),
$("error-fg", t(dark.error.fg, light.error.fg)),
$("scheme", scheme),
$("padding", `${padding}pt`),
$("spacing", `${spacing}pt`),
$("radius", `${radius}px`),
$("transition", `${options.transition}ms`),
$("shadows", `${shadows}`),
$("widget-bg", `transparentize(${t(dark.widget, light.widget)}, ${widget.opacity.value / 100})`),
$("hover-bg", `transparentize(${t(dark.widget, light.widget)}, ${(widget.opacity.value * .9) / 100})`),
$("hover-fg", `lighten(${t(dark.fg, light.fg)}, 8%)`),
$("border-width", `${border.width}px`),
$("border-color", `transparentize(${t(dark.border, light.border)}, ${border.opacity.value / 100})`),
$("border", "$border-width solid $border-color"),
$("active-gradient", `linear-gradient(to right, ${t(dark.primary.bg, light.primary.bg)}, darken(${t(dark.primary.bg, light.primary.bg)}, 4%))`),
$("shadow-color", t("rgba(0,0,0,.6)", "rgba(0,0,0,.4)")),
$("text-shadow", t("2pt 2pt 2pt $shadow-color", "none")),
$("box-shadow", t("2pt 2pt 2pt 0 $shadow-color, inset 0 0 0 $border-width $border-color", "none")),
$("popover-border-color", `transparentize(${t(dark.border, light.border)}, ${Math.max(((border.opacity.value - 1) / 100), 0)})`),
$("popover-padding", `$padding * ${popoverPaddingMultiplier}`),
$("popover-radius", radius.value === 0 ? "0" : "$radius + $popover-padding"),
$("font-size", `${options.font.size}pt`),
$("font-name", options.font.name),
// etc
$("charging-bg", options.bar.battery.charging),
$("bar-battery-blocks", options.bar.battery.blocks),
$("bar-position", options.bar.position),
$("hyprland-gaps-multiplier", options.hyprland.gaps),
$("screen-corner-multiplier", `${options.bar.corners.value * 0.01}`),
]
async function resetCss() {
if (!dependencies("sass", "fd"))
return
try {
const vars = `${TMP}/variables.scss`
const scss = `${TMP}/main.scss`
const css = `${TMP}/main.css`
const fd = await bash(`fd ".scss" ${App.configDir}`)
const files = fd.split(/\s+/)
const imports = [vars, ...files].map(f => `@import '${f}';`)
await Utils.writeFile(variables().join("\n"), vars)
await Utils.writeFile(imports.join("\n"), scss)
await bash`sass ${scss} ${css}`
App.applyCss(css, true)
} catch (error) {
error instanceof Error
? logError(error)
: console.error(error)
}
}
Utils.monitorFile(`${App.configDir}/style`, resetCss)
options.handler(deps, resetCss)
await resetCss()

View file

@ -1,265 +0,0 @@
@use 'sass:color';
$bar-spacing: $spacing * .3;
$button-radius: $radius;
@mixin panel-button($flat: true, $reactive: true) {
@include accs-button($flat, $reactive);
>* {
border-radius: $button-radius;
margin: $bar-spacing;
}
label,
image {
font-weight: bold;
}
>* {
padding: $padding * 0.4 $padding * 0.8;
}
}
.bar {
transition: $transition;
background-color: $bg;
.panel-button {
@include panel-button;
&:not(.flat) {
@include accs-button($flat: false);
}
}
.launcher {
.colored {
color: transparentize($primary-bg, 0.2);
}
&:hover .colored {
color: $primary-bg;
}
&:active .colored,
&.active .colored {
color: $primary-fg;
}
}
.workspaces {
label {
font-size: 0;
min-width: 5pt;
min-height: 5pt;
border-radius: $radius*.6;
box-shadow: inset 0 0 0 $border-width $border-color;
margin: 0 $padding * .5;
transition: $transition* .5;
background-color: transparentize($fg, .8);
&.occupied {
background-color: transparentize($fg, .2);
min-width: 7pt;
min-height: 7pt;
}
&.active {
// background-color: $primary-bg;
background-image: $active-gradient;
min-width: 20pt;
min-height: 12pt;
}
}
&.active,
&:active {
label {
background-color: transparentize($primary-fg, .3);
&.occupied {
background-color: transparentize($primary-fg, .15);
}
&.active {
background-color: $primary-fg;
}
}
}
}
.media label {
margin: 0 ($spacing * .5)
}
.taskbar .indicator.active {
background-color: $primary-bg;
border-radius: $radius;
min-height: 4pt;
min-width: 6pt;
margin: 2pt;
}
.powermenu.colored,
.recorder {
image {
color: transparentize($error-bg, 0.3);
}
&:hover image {
color: transparentize($error-bg, 0.15);
}
&:active image {
color: $primary-fg;
}
}
.quicksettings>box>box {
@include spacing($spacing: if($bar-spacing==0, $padding / 2, $bar-spacing));
}
.quicksettings:not(.active):not(:active) {
.bluetooth {
color: $primary-bg;
label {
font-size: $font-size * .7;
color: $fg;
text-shadow: $text-shadow;
}
}
}
.battery-bar {
>* {
padding: 0;
}
&.bar-hidden>box {
padding: 0 $spacing * .5;
image {
margin: 0;
}
}
levelbar * {
all: unset;
transition: $transition;
}
.whole {
@if $shadows {
image {
-gtk-icon-shadow: $text-shadow;
}
label {
text-shadow: $text-shadow;
}
}
}
.regular image {
margin-left: $spacing * .5;
}
trough {
@include widget;
min-height: 12pt;
min-width: 12pt;
}
.regular trough {
margin-right: $spacing * .5;
}
block {
margin: 0;
&:last-child {
border-radius: 0 $button-radius $button-radius 0;
}
&:first-child {
border-radius: $button-radius 0 0 $button-radius;
}
}
.vertical {
block {
&:last-child {
border-radius: 0 0 $button-radius $button-radius;
}
&:first-child {
border-radius: $button-radius $button-radius 0 0;
}
}
}
@for $i from 1 through $bar-battery-blocks {
block:nth-child(#{$i}).filled {
background-color: color.mix($bg, $primary-bg, $i*3)
}
&.low block:nth-child(#{$i}).filled {
background-color: color.mix($bg, $error-bg, $i*3)
}
&.charging block:nth-child(#{$i}).filled {
background-color: color.mix($bg, $charging-bg, $i*3)
}
&:active .regular block:nth-child(#{$i}).filled {
background-color: color.mix($bg, $primary-fg, $i*3)
}
}
&.low image {
color: $error-bg
}
&.charging image {
color: $charging-bg
}
&:active image {
color: $primary-fg
}
}
}
.bar.transparent {
background-color: transparent;
.panel-button {
&:hover>* {
box-shadow: 1px 1px 3px 0 $shadow-color, inset 0 0 0 $border-width $border-color;
background-color: $bg;
}
&:not(:hover):not(.active) {
label,
image {
text-shadow: $text-shadow;
-gtk-icon-shadow: $text-shadow;
}
}
}
.workspaces label {
box-shadow: inset 0 0 0 $border-width $border-color,
1px 1px 3px 0 $shadow-color;
}
.battery-bar trough {
box-shadow: 1px 1px 3px 0 $shadow-color;
}
}

View file

@ -1,110 +0,0 @@
@import "./notifications.scss";
@mixin calendar {
@include widget;
padding: $padding*2 $padding*2 0;
calendar {
all: unset;
&.button {
@include button($flat: true);
}
&:selected {
box-shadow: inset 0 -8px 0 0 transparentize($primary-bg, 0.5),
inset 0 0 0 1px $primary-bg;
border-radius: $radius*0.6;
}
&.header {
background-color: transparent;
border: none;
color: transparentize($fg, 0.5);
}
&.highlight {
background-color: transparent;
color: transparentize($primary-bg, 0.5);
}
&:indeterminate {
color: transparentize($fg, 0.9);
}
font-size: 1.1em;
padding: .2em;
}
}
window#datemenu .datemenu {
@include floating-widget;
.notifications {
.header {
margin-bottom: $spacing;
margin-right: $spacing;
>label {
margin-left: $radius * .5;
}
button {
@include button;
padding: $padding*.7 $padding;
}
}
.notification-scrollable {
@include scrollable($top: true, $bottom: true);
}
.notification-list {
margin-right: $spacing;
}
.notification {
@include notification;
@include widget;
padding: $padding;
margin-bottom: $spacing;
}
.placeholder {
image {
font-size: 7em;
}
label {
font-size: 1.2em;
}
}
}
separator {
background-color: $popover-border-color;
border-radius: $radius;
margin-right: $spacing;
}
.datemenu {
@include spacing;
}
.clock-box {
padding: $padding;
.clock {
font-size: 5em;
}
.uptime {
color: transparentize($fg, 0.2);
}
}
.calendar {
@include calendar;
}
}

View file

@ -1,64 +0,0 @@
@import "../mixins/floating-widget.scss";
@import "../mixins/widget.scss";
@import "../mixins/spacing.scss";
@import "../mixins/unset.scss";
@import "../mixins/a11y-button.scss";
@import "./bar.scss";
window#greeter {
background-color: lighten($bg, 6%);
color: $fg;
.bar {
background-color: transparent;
.date {
@include unset($rec: true);
@include panel-button($flat: true, $reactive: false);
}
}
.auth {
@include floating_widget;
border-radius: $radius;
min-width: 400px;
padding: 0;
.wallpaper {
min-height: 220px;
background-size: cover;
border-top-left-radius: $radius;
border-top-right-radius: $radius;
}
.wallpaper-contrast {
min-height: 100px;
}
.avatar {
border-radius: 99px;
min-width: 140px;
min-height: 140px;
background-size: cover;
box-shadow: 3px 3px 6px 0 $shadow-color;
margin-bottom: $spacing;
}
.password {
entry {
@include button;
padding: $padding*.7 $padding;
margin-left: $spacing*.5;
}
margin: 0 $padding*4;
margin-top: $spacing;
}
.response-box {
color: $error-bg;
margin: $spacing 0;
}
}
}

View file

@ -1,143 +0,0 @@
@use "sass:math";
@use "sass:color";
window#launcher .launcher {
@include floating_widget;
.quicklaunch {
@include spacing;
button {
@include button($flat: true);
padding: $padding;
}
}
entry {
@include button;
padding: $padding;
margin: $spacing;
selection {
color: color.mix($fg, $bg, 50%);
background-color: transparent;
}
label,
image {
color: $fg;
}
}
image.spinner {
color: $primary-bg;
margin-right: $spacing;
}
separator {
margin: 4pt 0;
background-color: $popover-border-color;
}
button.app-item {
@include button($flat: true, $reactive: false);
>box {
@include spacing(0.5);
}
transition: $transition;
padding: $padding;
label {
transition: $transition;
&.title {
color: $fg;
}
&.description {
color: transparentize($fg, 0.3);
}
}
image {
transition: $transition;
}
&:hover,
&:focus {
.title {
color: $primary-bg;
}
.description {
color: transparentize($primary-bg, .4);
}
image {
-gtk-icon-shadow: 2px 2px $primary-bg;
}
}
&:active {
background-color: transparentize($primary-bg, 0.5);
border-radius: $radius;
box-shadow: inset 0 0 0 $border-width $border-color;
.title {
color: $fg;
}
}
}
button.help,
button.nix-item {
@include button($flat: true, $reactive: false);
padding: 0 ($padding * .5);
label {
transition: $transition;
color: $fg;
}
.name {
font-size: 1.2em;
font-weight: bold;
}
.description {
color: transparentize($fg, .3)
}
&:hover,
&:focus {
label {
text-shadow: $text-shadow;
}
.name,
.version {
color: $primary-bg;
}
.description {
color: transparentize($primary-bg, .3)
}
}
}
button.sh-item {
@include button($flat: true, $reactive: false);
padding: 0 ($padding * .5);
transition: $transition;
color: $fg;
&:hover,
&:focus {
color: $primary-bg;
text-shadow: $text-shadow;
}
}
}

View file

@ -1,79 +0,0 @@
@mixin notification() {
&.critical {
box-shadow: inset 0 0 .5em 0 $error-bg;
}
&:hover button.close-button {
@include button-hover;
background-color: transparentize($error-bg, .5);
}
.content {
.title {
margin-right: $spacing;
color: $fg;
font-size: 1.1em;
}
.time {
color: transparentize($fg, .2);
}
.description {
font-size: .9em;
color: transparentize($fg, .2);
}
.icon {
border-radius: $radius*0.8;
margin-right: $spacing;
&.img {
border: $border;
}
}
}
box.actions {
@include spacing(0.5);
margin-top: $spacing;
button {
@include button;
border-radius: $radius*0.8;
font-size: 1.2em;
padding: $padding * 0.7;
}
}
button.close-button {
@include button($flat: true);
margin-left: $spacing / 2;
border-radius: $radius*0.8;
min-width: 1.2em;
min-height: 1.2em;
&:hover {
background-color: transparentize($error-bg, .2);
}
&:active {
background-image: none;
background-color: $error-bg;
}
}
}
window.notifications {
@include unset;
.notification {
@include notification;
@include floating-widget;
border-radius: $radius;
.description {
min-width: 350px;
}
}
}

View file

@ -1,26 +0,0 @@
window.indicator {
.progress {
@include floating-widget;
padding: $padding * .5;
border-radius: if($radius >0, calc($radius + $padding*.5), 0);
@debug $radius;
.fill {
border-radius: $radius;
background-color: $primary-bg;
color: $primary-fg;
image {
-gtk-icon-transform: scale(0.7);
}
}
}
.microphone {
@include floating-widget;
margin: $spacing * 2;
padding: $popover-padding * 2;
font-size: 58px;
color: transparentize($fg, .1)
}
}

View file

@ -1,34 +0,0 @@
window#overview .overview {
@include floating-widget;
@include spacing;
.workspace {
&.active>widget {
border-color: $primary-bg
}
>widget {
@include widget;
border-radius: if($radius ==0, 0, $radius + $padding);
&:hover {
background-color: $hover-bg;
}
&:drop(active) {
border-color: $primary-bg;
}
}
}
.client {
@include button;
border-radius: $radius;
margin: $padding;
&.hidden {
@include hidden;
transition: 0;
}
}
}

View file

@ -1,110 +0,0 @@
window#powermenu,
window#verification {
// the fraction has to be more than hyprland ignorealpha
background-color: rgba(0, 0, 0, .4);
}
window#verification .verification {
@include floating-widget;
padding: $popover-padding * 1.5;
min-width: 300px;
min-height: 100px;
.text-box {
margin-bottom: $spacing;
.title {
font-size: 1.6em;
}
.desc {
color: transparentize($fg, 0.1);
font-size: 1.1em;
}
}
.buttons {
@include spacing;
margin-top: $padding;
button {
@include button;
font-size: 1.5em;
padding: $padding;
}
}
}
window#powermenu .powermenu {
@include floating-widget;
&.line {
padding: $popover-padding * 1.5;
button {
padding: $popover-padding;
}
label {
margin-bottom: $spacing * -.5;
}
}
&.box {
padding: $popover-padding * 2;
button {
padding: $popover-padding * 1.5;
}
label {
margin-bottom: $spacing * -1;
}
}
button {
@include unset;
image {
@include button;
border-radius: $radius + ($popover-padding * 1.4);
min-width: 1.7em;
min-height: 1.7em;
font-size: 4em;
}
label,
image {
color: transparentize($fg, 0.1);
}
label {
margin-top: $spacing * .3;
}
&:hover {
image {
@include button-hover;
}
label {
color: $fg;
}
}
&:focus image {
@include button-focus;
}
&:active image {
@include button-active;
}
&:focus,
&:active {
label {
color: $primary-bg;
}
}
}
}

View file

@ -1,177 +0,0 @@
window#quicksettings .quicksettings {
@include floating-widget;
@include spacing;
padding: $popover-padding * 1.4;
.avatar {
@include widget;
border-radius: $radius * 3;
}
.header {
@include spacing(.5);
color: transparentize($fg, .15);
button {
@include button;
padding: $padding;
image {
font-size: 1.4em;
}
}
}
.sliders-box {
@include widget;
padding: $padding;
button {
@include button($flat: true);
padding: $padding * .5;
}
.volume button.arrow:last-child {
margin-left: $spacing * .4;
}
.volume,
.brightness {
padding: $padding * .5;
}
scale {
@include slider;
margin: 0 ($spacing * .5);
&.muted highlight {
background-image: none;
background-color: transparentize($fg, $amount: .2);
}
}
}
.row {
@include spacing;
}
.menu {
@include unset;
@include widget;
padding: $padding;
margin-top: $spacing;
.icon {
margin: 0 ($spacing * .5);
margin-left: $spacing * .2;
}
.title {
font-weight: bold;
}
separator {
margin: ($radius * .5);
background-color: $border-color;
}
button {
@include button($flat: true);
padding: ($padding * .5);
image:first-child {
margin-right: $spacing * .5;
}
}
.bluetooth-devices {
@include spacing(.5);
}
switch {
@include switch;
}
}
.sliders-box .menu {
margin: ($spacing * .5) 0;
&.app-mixer {
.mixer-item {
padding: $padding * .5;
padding-left: 0;
padding-right: $padding * 2;
scale {
@include slider($width: .5em);
}
image {
font-size: 1.2em;
margin: 0 $padding;
}
}
}
}
.toggle-button {
@include button;
font-weight: bold;
image {
font-size: 1.3em;
}
label {
margin-left: $spacing * .3;
}
button {
@include button($flat: true);
&:first-child {
padding: $padding * 1.2;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&:last-child {
padding: $padding * .5;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
&.active {
background-color: $primary-bg;
label,
image {
color: $primary-fg;
}
}
}
.simple-toggle {
@include button;
font-weight: bold;
padding: $padding * 1.2;
label {
margin-left: $spacing * .3;
}
image {
font-size: 1.3em;
}
}
.media {
@include spacing;
.player {
@include media;
}
}
}

View file

@ -1,52 +0,0 @@
$_shadow-size: $padding;
$_radius: $radius * $hyprland-gaps-multiplier * $screen-corner-multiplier;
$_margin: 99px;
window.screen-corner:not(.hidden) {
transition: $transition;
box.shadow {
margin-right: $_margin * -1;
margin-left: $_margin * -1;
@if $shadows {
box-shadow: inset 0 0 $_shadow-size 0 $shadow-color;
}
@if $bar-position =="top" {
margin-bottom: $_margin * -1;
}
@if $bar-position =="bottom" {
margin-top: $_margin * -1;
}
}
box.border {
@if $bar-position =="top" {
border-top: $border-width solid $bg;
}
@if $bar-position =="bottom" {
border-bottom: $border-width solid $bg;
}
margin-right: $_margin;
margin-left: $_margin;
}
box.corner {
box-shadow: 0 0 0 $border-width $border-color;
}
&.corners {
box.border {
border-radius: if($radius>0, $_radius, 0);
box-shadow: 0 0 0 $_radius $bg;
}
box.corner {
border-radius: if($radius>0, $_radius, 0);
}
}
}

View file

@ -1,144 +0,0 @@
window.settings-dialog {
background-color: $bg;
color: $fg;
.header {
.pager {
@include spacing(.5);
}
padding: $padding;
button {
@include button;
font-weight: bold;
padding: $padding*.5 $padding;
box {
@include spacing($spacing: .3em);
}
}
button.close {
padding: $padding * .5;
}
button.reset {
@include button($flat: true);
padding: $padding*.5;
}
}
.page {
@include scrollable($top: true);
.page-content {
padding: $padding*2;
padding-top: 0;
}
}
.group {
.group-title {
color: $primary-bg;
margin-bottom: $spacing*.5;
}
.group-reset {
@include button($flat: true);
margin: $spacing * .5;
padding: $padding * .5;
&:disabled {
color: transparent;
}
}
&:not(:first-child) {
margin-top: $spacing;
}
}
.row {
background-color: $widget-bg;
padding: $padding;
border: $border;
border-top: none;
&:first-child {
border-radius: $radius $radius 0 0;
border: $border;
}
&:last-child {
border-radius: 0 0 $radius $radius;
}
&:first-child:last-child {
border-radius: $radius;
border: $border;
}
button.reset {
margin-left: $spacing;
}
label.id,
label.note {
color: transparentize($fg, .4)
}
entry,
button {
@include button;
padding: $padding;
}
switch {
@include switch;
}
spinbutton {
@include unset;
entry {
border-radius: $radius 0 0 $radius;
}
button {
border-radius: 0;
}
button:last-child {
border-radius: 0 $radius $radius 0;
}
}
.enum-setter {
label {
background-color: $widget-bg;
border: $border;
padding: 0 $padding;
border-radius: $radius 0 0 $radius;
}
button {
border-radius: 0;
}
button:last-child {
border-radius: 0 $radius $radius 0;
}
}
&.wallpaper {
button {
margin-top: $spacing * .5;
}
.preview {
border-radius: $radius;
}
}
}
}

View file

@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": [
"ES2022"
],
"allowJs": true,
"checkJs": true,
"strict": true,
"noImplicitAny": false,
"baseUrl": ".",
"typeRoots": [
"./types",
"./node_modules/@girs"
],
"skipLibCheck": true
}
}

View file

@ -1,156 +0,0 @@
import { type WindowProps } from "types/widgets/window"
import { type RevealerProps } from "types/widgets/revealer"
import { type EventBoxProps } from "types/widgets/eventbox"
import type Gtk from "gi://Gtk?version=3.0"
import options from "options"
type Transition = RevealerProps["transition"]
type Child = WindowProps["child"]
type PopupWindowProps = Omit<WindowProps, "name"> & {
name: string
layout?: keyof ReturnType<typeof Layout>
transition?: Transition,
}
export const Padding = (name: string, {
css = "",
hexpand = true,
vexpand = true,
}: EventBoxProps = {}) => Widget.EventBox({
hexpand,
vexpand,
can_focus: false,
child: Widget.Box({ css }),
setup: w => w.on("button-press-event", () => App.toggleWindow(name)),
})
const PopupRevealer = (
name: string,
child: Child,
transition: Transition = "slide_down",
) => Widget.Box(
{ css: "padding: 1px;" },
Widget.Revealer({
transition,
child: Widget.Box({
class_name: "window-content",
child,
}),
transitionDuration: options.transition.bind(),
setup: self => self.hook(App, (_, wname, visible) => {
if (wname === name)
self.reveal_child = visible
}),
}),
)
const Layout = (name: string, child: Child, transition?: Transition) => ({
"center": () => Widget.CenterBox({},
Padding(name),
Widget.CenterBox(
{ vertical: true },
Padding(name),
PopupRevealer(name, child, transition),
Padding(name),
),
Padding(name),
),
"top": () => Widget.CenterBox({},
Padding(name),
Widget.Box(
{ vertical: true },
PopupRevealer(name, child, transition),
Padding(name),
),
Padding(name),
),
"top-right": () => Widget.Box({},
Padding(name),
Widget.Box(
{
hexpand: false,
vertical: true,
},
PopupRevealer(name, child, transition),
Padding(name),
),
),
"top-center": () => Widget.Box({},
Padding(name),
Widget.Box(
{
hexpand: false,
vertical: true,
},
PopupRevealer(name, child, transition),
Padding(name),
),
Padding(name),
),
"top-left": () => Widget.Box({},
Widget.Box(
{
hexpand: false,
vertical: true,
},
PopupRevealer(name, child, transition),
Padding(name),
),
Padding(name),
),
"bottom-left": () => Widget.Box({},
Widget.Box(
{
hexpand: false,
vertical: true,
},
Padding(name),
PopupRevealer(name, child, transition),
),
Padding(name),
),
"bottom-center": () => Widget.Box({},
Padding(name),
Widget.Box(
{
hexpand: false,
vertical: true,
},
Padding(name),
PopupRevealer(name, child, transition),
),
Padding(name),
),
"bottom-right": () => Widget.Box({},
Padding(name),
Widget.Box(
{
hexpand: false,
vertical: true,
},
Padding(name),
PopupRevealer(name, child, transition),
),
),
})
export default ({
name,
child,
layout = "center",
transition,
exclusivity = "ignore",
...props
}: PopupWindowProps) => Widget.Window<Gtk.Widget>({
name,
class_names: [name, "popup-window"],
setup: w => w.keybind("Escape", () => App.closeWindow(name)),
visible: false,
keymode: "on-demand",
exclusivity,
layer: "top",
anchor: ["top", "bottom", "right", "left"],
child: Layout(name, child, transition)[layout](),
...props,
})

View file

@ -1,3 +0,0 @@
import Gtk from "gi://Gtk?version=3.0"
export default Widget.subclass<typeof Gtk.Window, Gtk.Window.ConstructorProperties>(Gtk.Window)

View file

@ -1,60 +0,0 @@
import BatteryBar from "./buttons/BatteryBar"
import ColorPicker from "./buttons/ColorPicker"
import Date from "./buttons/Date"
import Launcher from "./buttons/Launcher"
import Media from "./buttons/Media"
import PowerMenu from "./buttons/PowerMenu"
import SysTray from "./buttons/SysTray"
import SystemIndicators from "./buttons/SystemIndicators"
import Taskbar from "./buttons/Taskbar"
import Workspaces from "./buttons/Workspaces"
import ScreenRecord from "./buttons/ScreenRecord"
import Messages from "./buttons/Messages"
import options from "options"
const { start, center, end } = options.bar.layout
const { transparent, position } = options.bar
export type BarWidget = keyof typeof widget
const widget = {
battery: BatteryBar,
colorpicker: ColorPicker,
date: Date,
launcher: Launcher,
media: Media,
powermenu: PowerMenu,
systray: SysTray,
system: SystemIndicators,
taskbar: Taskbar,
workspaces: Workspaces,
screenrecord: ScreenRecord,
messages: Messages,
expander: () => Widget.Box({ expand: true }),
}
export default (monitor: number) => Widget.Window({
monitor,
class_name: "bar",
name: `bar${monitor}`,
exclusivity: "exclusive",
anchor: position.bind().as(pos => [pos, "right", "left"]),
child: Widget.CenterBox({
css: "min-width: 2px; min-height: 2px;",
startWidget: Widget.Box({
hexpand: true,
children: start.bind().as(s => s.map(w => widget[w]())),
}),
centerWidget: Widget.Box({
hpack: "center",
children: center.bind().as(c => c.map(w => widget[w]())),
}),
endWidget: Widget.Box({
hexpand: true,
children: end.bind().as(e => e.map(w => widget[w]())),
}),
}),
setup: self => self.hook(transparent, () => {
self.toggleClassName("transparent", transparent.value)
}),
})

View file

@ -1,46 +0,0 @@
import options from "options"
import { ButtonProps } from "types/widgets/button"
type PanelButtonProps = ButtonProps & {
window?: string,
flat?: boolean
}
export default ({
window = "",
flat,
child,
setup,
...rest
}: PanelButtonProps) => Widget.Button({
child: Widget.Box({ child }),
setup: self => {
let open = false
self.toggleClassName("panel-button")
self.toggleClassName(window)
self.hook(options.bar.flatButtons, () => {
self.toggleClassName("flat", flat ?? options.bar.flatButtons.value)
})
self.hook(App, (_, win, visible) => {
if (win !== window)
return
if (open && !visible) {
open = false
self.toggleClassName("active", false)
}
if (visible) {
open = true
self.toggleClassName("active")
}
})
if (setup)
setup(self)
},
...rest,
})

View file

@ -1,29 +0,0 @@
import options from "options"
const { corners, transparent } = options.bar
export default (monitor: number) => Widget.Window({
monitor,
name: `corner${monitor}`,
class_name: "screen-corner",
anchor: ["top", "bottom", "right", "left"],
click_through: true,
child: Widget.Box({
class_name: "shadow",
child: Widget.Box({
class_name: "border",
expand: true,
child: Widget.Box({
class_name: "corner",
expand: true,
}),
}),
}),
setup: self => self
.hook(corners, () => {
self.toggleClassName("corners", corners.value > 0)
})
.hook(transparent, () => {
self.toggleClassName("hidden", transparent.value)
}),
})

View file

@ -1,94 +0,0 @@
import icons from "lib/icons"
import options from "options"
import PanelButton from "../PanelButton"
const battery = await Service.import("battery")
const { bar, percentage, blocks, width, low } = options.bar.battery
const Indicator = () => Widget.Icon({
setup: self => self.hook(battery, () => {
self.icon = battery.charging || battery.charged
? icons.battery.charging
: battery.icon_name
}),
})
const PercentLabel = () => Widget.Revealer({
transition: "slide_right",
click_through: true,
reveal_child: percentage.bind(),
child: Widget.Label({
label: battery.bind("percent").as(p => `${p}%`),
}),
})
const LevelBar = () => {
const level = Widget.LevelBar({
bar_mode: "discrete",
max_value: blocks.bind(),
visible: bar.bind().as(b => b !== "hidden"),
value: battery.bind("percent").as(p => (p / 100) * blocks.value),
})
const update = () => {
level.value = (battery.percent / 100) * blocks.value
level.css = `block { min-width: ${width.value / blocks.value}pt; }`
}
return level
.hook(width, update)
.hook(blocks, update)
.hook(bar, () => {
level.vpack = bar.value === "whole" ? "fill" : "center"
level.hpack = bar.value === "whole" ? "fill" : "center"
})
}
const WholeButton = () => Widget.Overlay({
vexpand: true,
child: LevelBar(),
class_name: "whole",
pass_through: true,
overlay: Widget.Box({
hpack: "center",
children: [
Widget.Icon({
icon: icons.battery.charging,
visible: Utils.merge([
battery.bind("charging"),
battery.bind("charged"),
], (ing, ed) => ing || ed),
}),
Widget.Box({
hpack: "center",
vpack: "center",
child: PercentLabel(),
}),
],
}),
})
const Regular = () => Widget.Box({
class_name: "regular",
children: [
Indicator(),
PercentLabel(),
LevelBar(),
],
})
export default () => PanelButton({
class_name: "battery-bar",
hexpand: false,
on_clicked: () => { percentage.value = !percentage.value },
visible: battery.bind("available"),
child: Widget.Box({
expand: true,
visible: battery.bind("available"),
child: bar.bind().as(b => b === "whole" ? WholeButton() : Regular()),
}),
setup: self => self
.hook(bar, w => w.toggleClassName("bar-hidden", bar.value === "hidden"))
.hook(battery, w => {
w.toggleClassName("charging", battery.charging || battery.charged)
w.toggleClassName("low", battery.percent < low.value)
}),
})

View file

@ -1,37 +0,0 @@
import PanelButton from "../PanelButton"
import colorpicker from "service/colorpicker"
import Gdk from "gi://Gdk"
const css = (color: string) => `
* {
background-color: ${color};
color: transparent;
}
*:hover {
color: white;
text-shadow: 2px 2px 3px rgba(0,0,0,.8);
}`
export default () => {
const menu = Widget.Menu({
class_name: "colorpicker",
children: colorpicker.bind("colors").as(c => c.map(color => Widget.MenuItem({
child: Widget.Label(color),
css: css(color),
on_activate: () => colorpicker.wlCopy(color),
}))),
})
return PanelButton({
class_name: "color-picker",
child: Widget.Icon("color-select-symbolic"),
tooltip_text: colorpicker.bind("colors").as(v => `${v.length} colors`),
on_clicked: colorpicker.pick,
on_secondary_click: self => {
if (colorpicker.colors.length === 0)
return
menu.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null)
},
})
}

View file

@ -1,15 +0,0 @@
import { clock } from "lib/variables"
import PanelButton from "../PanelButton"
import options from "options"
const { format, action } = options.bar.date
const time = Utils.derive([clock, format], (c, f) => c.format(f) || "")
export default () => PanelButton({
window: "datemenu",
on_clicked: action.bind(),
child: Widget.Label({
justification: "center",
label: time.bind(),
}),
})

View file

@ -1,49 +0,0 @@
import PanelButton from "../PanelButton"
import options from "options"
import nix from "service/nix"
const { icon, label, action } = options.bar.launcher
function Spinner() {
const child = Widget.Icon({
icon: icon.icon.bind(),
class_name: Utils.merge([
icon.colored.bind(),
nix.bind("ready"),
], (c, r) => `${c ? "colored" : ""} ${r ? "" : "spinning"}`),
css: `
@keyframes spin {
to { -gtk-icon-transform: rotate(1turn); }
}
image.spinning {
animation-name: spin;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
`,
})
return Widget.Revealer({
transition: "slide_left",
child,
reveal_child: Utils.merge([
icon.icon.bind(),
nix.bind("ready"),
], (i, r) => Boolean(i || r)),
})
}
export default () => PanelButton({
window: "launcher",
on_clicked: action.bind(),
child: Widget.Box([
Spinner(),
Widget.Label({
class_name: label.colored.bind().as(c => c ? "colored" : ""),
visible: label.label.bind().as(v => !!v),
label: label.label.bind(),
}),
]),
})

View file

@ -1,92 +0,0 @@
import { type MprisPlayer } from "types/service/mpris"
import PanelButton from "../PanelButton"
import options from "options"
import icons from "lib/icons"
import { icon } from "lib/utils"
const mpris = await Service.import("mpris")
const { length, direction, preferred, monochrome, format } = options.bar.media
const getPlayer = (name = preferred.value) =>
mpris.getPlayer(name) || mpris.players[0] || null
const Content = (player: MprisPlayer) => {
const revealer = Widget.Revealer({
click_through: true,
visible: length.bind().as(l => l > 0),
transition: direction.bind().as(d => `slide_${d}` as const),
setup: self => {
let current = ""
self.hook(player, () => {
if (current === player.track_title)
return
current = player.track_title
self.reveal_child = true
Utils.timeout(3000, () => {
!self.is_destroyed && (self.reveal_child = false)
})
})
},
child: Widget.Label({
truncate: "end",
max_width_chars: length.bind().as(n => n > 0 ? n : -1),
label: Utils.merge([
player.bind("track_title"),
player.bind("track_artists"),
format.bind(),
], () => `${format}`
.replace("{title}", player.track_title)
.replace("{artists}", player.track_artists.join(", "))
.replace("{artist}", player.track_artists[0] || "")
.replace("{album}", player.track_album)
.replace("{name}", player.name)
.replace("{identity}", player.identity),
),
}),
})
const playericon = Widget.Icon({
icon: Utils.merge([player.bind("entry"), monochrome.bind()], (entry => {
const name = `${entry}${monochrome.value ? "-symbolic" : ""}`
return icon(name, icons.fallback.audio)
})),
})
return Widget.Box({
attribute: { revealer },
children: direction.bind().as(d => d === "right"
? [playericon, revealer] : [revealer, playericon]),
})
}
export default () => {
let player = getPlayer()
const btn = PanelButton({
class_name: "media",
child: Widget.Icon(icons.fallback.audio),
})
const update = () => {
player = getPlayer()
btn.visible = !!player
if (!player)
return
const content = Content(player)
const { revealer } = content.attribute
btn.child = content
btn.on_primary_click = () => { player.playPause() }
btn.on_secondary_click = () => { player.playPause() }
btn.on_scroll_up = () => { player.next() }
btn.on_scroll_down = () => { player.previous() }
btn.on_hover = () => { revealer.reveal_child = true }
btn.on_hover_lost = () => { revealer.reveal_child = false }
}
return btn
.hook(preferred, update)
.hook(mpris, update, "notify::players")
}

View file

@ -1,16 +0,0 @@
import icons from "lib/icons"
import PanelButton from "../PanelButton"
import options from "options"
const n = await Service.import("notifications")
const notifs = n.bind("notifications")
const action = options.bar.messages.action.bind()
export default () => PanelButton({
class_name: "messages",
on_clicked: action,
visible: notifs.as(n => n.length > 0),
child: Widget.Box([
Widget.Icon(icons.notifications.message),
]),
})

View file

@ -1,15 +0,0 @@
import icons from "lib/icons"
import PanelButton from "../PanelButton"
import options from "options"
const { monochrome, action } = options.bar.powermenu
export default () => PanelButton({
window: "powermenu",
on_clicked: action.bind(),
child: Widget.Icon(icons.powermenu.shutdown),
setup: self => self.hook(monochrome, () => {
self.toggleClassName("colored", !monochrome.value)
self.toggleClassName("box")
}),
})

View file

@ -1,21 +0,0 @@
import PanelButton from "../PanelButton"
import screenrecord from "service/screenrecord"
import icons from "lib/icons"
export default () => PanelButton({
class_name: "recorder",
on_clicked: () => screenrecord.stop(),
visible: screenrecord.bind("recording"),
child: Widget.Box({
children: [
Widget.Icon(icons.recorder.recording),
Widget.Label({
label: screenrecord.bind("timer").as(time => {
const sec = time % 60
const min = Math.floor(time / 60)
return `${min}:${sec < 10 ? "0" + sec : sec}`
}),
}),
],
}),
})

View file

@ -1,39 +0,0 @@
import { type TrayItem } from "types/service/systemtray"
import PanelButton from "../PanelButton"
import Gdk from "gi://Gdk"
import options from "options"
const systemtray = await Service.import("systemtray")
const { ignore } = options.bar.systray
const SysTrayItem = (item: TrayItem) => PanelButton({
class_name: "tray-item",
child: Widget.Icon({ icon: item.bind("icon") }),
tooltip_markup: item.bind("tooltip_markup"),
setup: self => {
const { menu } = item
if (!menu)
return
const id = menu.connect("popped-up", () => {
self.toggleClassName("active")
menu.connect("notify::visible", () => {
self.toggleClassName("active", menu.visible)
})
menu.disconnect(id!)
})
self.connect("destroy", () => menu.disconnect(id))
},
on_primary_click: btn => item.menu?.popup_at_widget(
btn, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null),
on_secondary_click: btn => item.menu?.popup_at_widget(
btn, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null),
})
export default () => Widget.Box()
.bind("children", systemtray, "items", i => i
.filter(({ id }) => !ignore.value.includes(id))
.map(SysTrayItem))

View file

@ -1,98 +0,0 @@
import PanelButton from "../PanelButton"
import icons from "lib/icons"
import asusctl from "service/asusctl"
const notifications = await Service.import("notifications")
const bluetooth = await Service.import("bluetooth")
const audio = await Service.import("audio")
const network = await Service.import("network")
const powerprof = await Service.import("powerprofiles")
const ProfileIndicator = () => {
const visible = asusctl.available
? asusctl.bind("profile").as(p => p !== "Balanced")
: powerprof.bind("active_profile").as(p => p !== "balanced")
const icon = asusctl.available
? asusctl.bind("profile").as(p => icons.asusctl.profile[p])
: powerprof.bind("active_profile").as(p => icons.powerprofile[p])
return Widget.Icon({ visible, icon })
}
const ModeIndicator = () => {
if (!asusctl.available) {
return Widget.Icon({
setup(self) {
Utils.idle(() => self.visible = false)
},
})
}
return Widget.Icon({
visible: asusctl.bind("mode").as(m => m !== "Hybrid"),
icon: asusctl.bind("mode").as(m => icons.asusctl.mode[m]),
})
}
const MicrophoneIndicator = () => Widget.Icon()
.hook(audio, self => self.visible =
audio.recorders.length > 0
|| audio.microphone.is_muted
|| false)
.hook(audio.microphone, self => {
const vol = audio.microphone.is_muted ? 0 : audio.microphone.volume
const { muted, low, medium, high } = icons.audio.mic
const cons = [[67, high], [34, medium], [1, low], [0, muted]] as const
self.icon = cons.find(([n]) => n <= vol * 100)?.[1] || ""
})
const DNDIndicator = () => Widget.Icon({
visible: notifications.bind("dnd"),
icon: icons.notifications.silent,
})
const BluetoothIndicator = () => Widget.Overlay({
class_name: "bluetooth",
passThrough: true,
visible: bluetooth.bind("enabled"),
child: Widget.Icon({
icon: icons.bluetooth.enabled,
}),
overlay: Widget.Label({
hpack: "end",
vpack: "start",
label: bluetooth.bind("connected_devices").as(c => `${c.length}`),
visible: bluetooth.bind("connected_devices").as(c => c.length > 0),
}),
})
const NetworkIndicator = () => Widget.Icon().hook(network, self => {
const icon = network[network.primary || "wifi"]?.icon_name
self.icon = icon || ""
self.visible = !!icon
})
const AudioIndicator = () => Widget.Icon()
.hook(audio.speaker, self => {
const vol = audio.speaker.is_muted ? 0 : audio.speaker.volume
const { muted, low, medium, high, overamplified } = icons.audio.volume
const cons = [[101, overamplified], [67, high], [34, medium], [1, low], [0, muted]] as const
self.icon = cons.find(([n]) => n <= vol * 100)?.[1] || ""
})
export default () => PanelButton({
window: "quicksettings",
on_clicked: () => App.toggleWindow("quicksettings"),
on_scroll_up: () => audio.speaker.volume += 0.02,
on_scroll_down: () => audio.speaker.volume -= 0.02,
child: Widget.Box([
ProfileIndicator(),
ModeIndicator(),
DNDIndicator(),
BluetoothIndicator(),
NetworkIndicator(),
AudioIndicator(),
MicrophoneIndicator(),
]),
})

View file

@ -1,90 +0,0 @@
import { launchApp, icon } from "lib/utils"
import icons from "lib/icons"
import options from "options"
import PanelButton from "../PanelButton"
const hyprland = await Service.import("hyprland")
const apps = await Service.import("applications")
const { monochrome, exclusive, iconSize } = options.bar.taskbar
const { position } = options.bar
const focus = (address: string) => hyprland.messageAsync(
`dispatch focuswindow address:${address}`)
const DummyItem = (address: string) => Widget.Box({
attribute: { address },
visible: false,
})
const AppItem = (address: string) => {
const client = hyprland.getClient(address)
if (!client || client.class === "")
return DummyItem(address)
const app = apps.list.find(app => app.match(client.class))
const btn = PanelButton({
class_name: "panel-button",
tooltip_text: Utils.watch(client.title, hyprland, () =>
hyprland.getClient(address)?.title || "",
),
on_primary_click: () => focus(address),
on_middle_click: () => app && launchApp(app),
child: Widget.Icon({
size: iconSize.bind(),
icon: monochrome.bind().as(m => icon(
(app?.icon_name || client.class) + (m ? "-symbolic" : ""),
icons.fallback.executable + (m ? "-symbolic" : ""),
)),
}),
})
return Widget.Box(
{
attribute: { address },
visible: Utils.watch(true, [exclusive, hyprland], () => {
return exclusive.value
? hyprland.active.workspace.id === client.workspace.id
: true
}),
},
Widget.Overlay({
child: btn,
pass_through: true,
overlay: Widget.Box({
className: "indicator",
hpack: "center",
vpack: position.bind().as(p => p === "top" ? "start" : "end"),
setup: w => w.hook(hyprland, () => {
w.toggleClassName("active", hyprland.active.client.address === address)
}),
}),
}),
)
}
function sortItems<T extends { attribute: { address: string } }>(arr: T[]) {
return arr.sort(({ attribute: a }, { attribute: b }) => {
const aclient = hyprland.getClient(a.address)!
const bclient = hyprland.getClient(b.address)!
return aclient.workspace.id - bclient.workspace.id
})
}
export default () => Widget.Box({
class_name: "taskbar",
children: sortItems(hyprland.clients.map(c => AppItem(c.address))),
setup: w => w
.hook(hyprland, (w, address?: string) => {
if (typeof address === "string")
w.children = w.children.filter(ch => ch.attribute.address !== address)
}, "client-removed")
.hook(hyprland, (w, address?: string) => {
if (typeof address === "string")
w.children = sortItems([...w.children, AppItem(address)])
}, "client-added")
.hook(hyprland, (w, event?: string) => {
if (event === "movewindow")
w.children = sortItems(w.children)
}, "event"),
})

View file

@ -1,38 +0,0 @@
import PanelButton from "../PanelButton"
import options from "options"
import { sh, range } from "lib/utils"
const hyprland = await Service.import("hyprland")
const { workspaces } = options.bar.workspaces
const dispatch = (arg: string | number) => {
sh(`hyprctl dispatch workspace ${arg}`)
}
const Workspaces = (ws: number) => Widget.Box({
children: range(ws || 20).map(i => Widget.Label({
attribute: i,
vpack: "center",
label: `${i}`,
setup: self => self.hook(hyprland, () => {
self.toggleClassName("active", hyprland.active.workspace.id === i)
self.toggleClassName("occupied", (hyprland.getWorkspace(i)?.windows || 0) > 0)
}),
})),
setup: box => {
if (ws === 0) {
box.hook(hyprland.active.workspace, () => box.children.map(btn => {
btn.visible = hyprland.workspaces.some(ws => ws.id === btn.attribute)
}))
}
},
})
export default () => PanelButton({
window: "overview",
class_name: "workspaces",
on_scroll_up: () => dispatch("m+1"),
on_scroll_down: () => dispatch("m-1"),
on_clicked: () => App.toggleWindow("overview"),
child: workspaces.bind().as(Workspaces),
})

View file

@ -1,37 +0,0 @@
import { clock, uptime } from "lib/variables"
function up(up: number) {
const h = Math.floor(up / 60)
const m = Math.floor(up % 60)
return `uptime: ${h}:${m < 10 ? "0" + m : m}`
}
export default () => Widget.Box({
vertical: true,
class_name: "date-column vertical",
children: [
Widget.Box({
class_name: "clock-box",
vertical: true,
children: [
Widget.Label({
class_name: "clock",
label: clock.bind().as(t => t.format("%H:%M")!),
}),
Widget.Label({
class_name: "uptime",
label: uptime.bind().as(up),
}),
],
}),
Widget.Box({
class_name: "calendar",
children: [
Widget.Calendar({
hexpand: true,
hpack: "center",
}),
],
}),
],
})

View file

@ -1,36 +0,0 @@
import PopupWindow from "widget/PopupWindow"
import NotificationColumn from "./NotificationColumn"
import DateColumn from "./DateColumn"
import options from "options"
const { bar, datemenu } = options
const pos = bar.position.bind()
const layout = Utils.derive([bar.position, datemenu.position], (bar, qs) =>
`${bar}-${qs}` as const,
)
const Settings = () => Widget.Box({
class_name: "datemenu horizontal",
vexpand: false,
children: [
NotificationColumn(),
Widget.Separator({ orientation: 1 }),
DateColumn(),
],
})
const DateMenu = () => PopupWindow({
name: "datemenu",
exclusivity: "exclusive",
transition: pos.as(pos => pos === "top" ? "slide_down" : "slide_up"),
layout: layout.value,
child: Settings(),
})
export function setupDateMenu() {
App.addWindow(DateMenu())
layout.connect("changed", () => {
App.removeWindow("datemenu")
App.addWindow(DateMenu())
})
}

View file

@ -1,113 +0,0 @@
import { type Notification as Notif } from "types/service/notifications"
import Notification from "widget/notifications/Notification"
import options from "options"
import icons from "lib/icons"
const notifications = await Service.import("notifications")
const notifs = notifications.bind("notifications")
const Animated = (n: Notif) => Widget.Revealer({
transition_duration: options.transition.value,
transition: "slide_down",
child: Notification(n),
setup: self => Utils.timeout(options.transition.value, () => {
if (!self.is_destroyed)
self.reveal_child = true
}),
})
const ClearButton = () => Widget.Button({
on_clicked: notifications.clear,
sensitive: notifs.as(n => n.length > 0),
child: Widget.Box({
children: [
Widget.Label("Clear "),
Widget.Icon({
icon: notifs.as(n => icons.trash[n.length > 0 ? "full" : "empty"]),
}),
],
}),
})
const Header = () => Widget.Box({
class_name: "header",
children: [
Widget.Label({ label: "Notifications", hexpand: true, xalign: 0 }),
ClearButton(),
],
})
const NotificationList = () => {
const map: Map<number, ReturnType<typeof Animated>> = new Map
const box = Widget.Box({
vertical: true,
children: notifications.notifications.map(n => {
const w = Animated(n)
map.set(n.id, w)
return w
}),
visible: notifs.as(n => n.length > 0),
})
function remove(_: unknown, id: number) {
const n = map.get(id)
if (n) {
n.reveal_child = false
Utils.timeout(options.transition.value, () => {
n.destroy()
map.delete(id)
})
}
}
return box
.hook(notifications, remove, "closed")
.hook(notifications, (_, id: number) => {
if (id !== undefined) {
if (map.has(id))
remove(null, id)
const n = notifications.getNotification(id)!
const w = Animated(n)
map.set(id, w)
box.children = [w, ...box.children]
}
}, "notified")
}
const Placeholder = () => Widget.Box({
class_name: "placeholder",
vertical: true,
vpack: "center",
hpack: "center",
vexpand: true,
hexpand: true,
visible: notifs.as(n => n.length === 0),
children: [
Widget.Icon(icons.notifications.silent),
Widget.Label("Your inbox is empty"),
],
})
export default () => Widget.Box({
class_name: "notifications",
css: options.notifications.width.bind().as(w => `min-width: ${w}px`),
vertical: true,
children: [
Header(),
Widget.Scrollable({
vexpand: true,
hscroll: "never",
class_name: "notification-scrollable",
child: Widget.Box({
class_name: "notification-list vertical",
vertical: true,
children: [
NotificationList(),
Placeholder(),
],
}),
}),
],
})

View file

@ -1,40 +0,0 @@
import options from "options"
import { matugen } from "lib/matugen"
const mpris = await Service.import("mpris")
const pref = () => options.bar.media.preferred.value
export default (monitor: number) => Widget.Window({
monitor,
layer: "bottom",
name: `desktop${monitor}`,
class_name: "desktop",
anchor: ["top", "bottom", "left", "right"],
child: Widget.Box({
expand: true,
css: options.theme.dark.primary.bg.bind().as(c => `
transition: 500ms;
background-color: ${c}`),
child: Widget.Box({
class_name: "wallpaper",
expand: true,
vpack: "center",
hpack: "center",
setup: self => self
.hook(mpris, () => {
const img = mpris.getPlayer(pref())!.cover_path
matugen("image", img)
Utils.timeout(500, () => self.css = `
background-image: url('${img}');
background-size: contain;
background-repeat: no-repeat;
transition: 200ms;
min-width: 700px;
min-height: 700px;
border-radius: 30px;
box-shadow: 25px 25px 30px 0 rgba(0,0,0,0.5);`,
)
}),
}),
}),
})

View file

@ -1,130 +0,0 @@
import { type Application } from "types/service/applications"
import { launchApp, icon } from "lib/utils"
import options from "options"
import icons from "lib/icons"
const apps = await Service.import("applications")
const { query } = apps
const { iconSize } = options.launcher.apps
const QuickAppButton = (app: Application) => Widget.Button({
hexpand: true,
tooltip_text: app.name,
on_clicked: () => {
App.closeWindow("launcher")
launchApp(app)
},
child: Widget.Icon({
size: iconSize.bind(),
icon: icon(app.icon_name, icons.fallback.executable),
}),
})
const AppItem = (app: Application) => {
const title = Widget.Label({
class_name: "title",
label: app.name,
hexpand: true,
xalign: 0,
vpack: "center",
truncate: "end",
})
const description = Widget.Label({
class_name: "description",
label: app.description || "",
hexpand: true,
wrap: true,
max_width_chars: 30,
xalign: 0,
justification: "left",
vpack: "center",
})
const appicon = Widget.Icon({
icon: icon(app.icon_name, icons.fallback.executable),
size: iconSize.bind(),
})
const textBox = Widget.Box({
vertical: true,
vpack: "center",
children: app.description ? [title, description] : [title],
})
return Widget.Button({
class_name: "app-item",
attribute: { app },
child: Widget.Box({
children: [appicon, textBox],
}),
on_clicked: () => {
App.closeWindow("launcher")
launchApp(app)
},
})
}
export function Favorites() {
const favs = options.launcher.apps.favorites.bind()
return Widget.Revealer({
visible: favs.as(f => f.length > 0),
child: Widget.Box({
vertical: true,
children: favs.as(favs => favs.flatMap(fs => [
Widget.Separator(),
Widget.Box({
class_name: "quicklaunch horizontal",
children: fs
.map(f => query(f)?.[0])
.filter(f => f)
.map(QuickAppButton),
}),
])),
}),
})
}
export function Launcher() {
const applist = Variable(query(""))
const max = options.launcher.apps.max
let first = applist.value[0]
function SeparatedAppItem(app: Application) {
return Widget.Revealer(
{ attribute: { app } },
Widget.Box(
{ vertical: true },
Widget.Separator(),
AppItem(app),
),
)
}
const list = Widget.Box({
vertical: true,
children: applist.bind().as(list => list.map(SeparatedAppItem)),
setup: self => self
.hook(apps, () => applist.value = query(""), "notify::frequents"),
})
return Object.assign(list, {
filter(text: string | null) {
first = query(text || "")[0]
list.children.reduce((i, item) => {
if (!text || i >= max.value) {
item.reveal_child = false
return i
}
if (item.attribute.app.match(text)) {
item.reveal_child = true
return ++i
}
item.reveal_child = false
return i
}, 0)
},
launchFirst() {
launchApp(first)
},
})
}

View file

@ -1,139 +0,0 @@
import { type Binding } from "lib/utils"
import PopupWindow, { Padding } from "widget/PopupWindow"
import icons from "lib/icons"
import options from "options"
import nix from "service/nix"
import * as AppLauncher from "./AppLauncher"
import * as NixRun from "./NixRun"
import * as ShRun from "./ShRun"
const { width, margin } = options.launcher
const isnix = nix.available
function Launcher() {
const favs = AppLauncher.Favorites()
const applauncher = AppLauncher.Launcher()
const sh = ShRun.ShRun()
const shicon = ShRun.Icon()
const nix = NixRun.NixRun()
const nixload = NixRun.Spinner()
function HelpButton(cmd: string, desc: string | Binding<string>) {
return Widget.Box(
{ vertical: true },
Widget.Separator(),
Widget.Button(
{
class_name: "help",
on_clicked: () => {
entry.grab_focus()
entry.text = `:${cmd} `
entry.set_position(-1)
},
},
Widget.Box([
Widget.Label({
class_name: "name",
label: `:${cmd}`,
}),
Widget.Label({
hexpand: true,
hpack: "end",
class_name: "description",
label: desc,
}),
]),
),
)
}
const help = Widget.Revealer({
child: Widget.Box(
{ vertical: true },
HelpButton("sh", "run a binary"),
isnix ? HelpButton("nx", options.launcher.nix.pkgs.bind().as(pkg =>
`run a nix package from ${pkg}`,
)) : Widget.Box(),
),
})
const entry = Widget.Entry({
hexpand: true,
primary_icon_name: icons.ui.search,
on_accept: ({ text }) => {
if (text?.startsWith(":nx"))
nix.run(text.substring(3))
else if (text?.startsWith(":sh"))
sh.run(text.substring(3))
else
applauncher.launchFirst()
App.toggleWindow("launcher")
entry.text = ""
},
on_change: ({ text }) => {
text ||= ""
favs.reveal_child = text === ""
help.reveal_child = text.split(" ").length === 1 && text?.startsWith(":")
if (text?.startsWith(":nx"))
nix.filter(text.substring(3))
else
nix.filter("")
if (text?.startsWith(":sh"))
sh.filter(text.substring(3))
else
sh.filter("")
if (!text?.startsWith(":"))
applauncher.filter(text)
},
})
function focus() {
entry.text = "Search"
entry.set_position(-1)
entry.select_region(0, -1)
entry.grab_focus()
favs.reveal_child = true
}
const layout = Widget.Box({
css: width.bind().as(v => `min-width: ${v}pt;`),
class_name: "launcher",
vertical: true,
vpack: "start",
setup: self => self.hook(App, (_, win, visible) => {
if (win !== "launcher")
return
entry.text = ""
if (visible)
focus()
}),
children: [
Widget.Box([entry, nixload, shicon]),
favs,
help,
applauncher,
nix,
sh,
],
})
return Widget.Box(
{ vertical: true, css: "padding: 1px" },
Padding("launcher", {
css: margin.bind().as(v => `min-height: ${v}pt;`),
vexpand: false,
}),
layout,
)
}
export default () => PopupWindow({
name: "launcher",
layout: "top",
child: Launcher(),
})

View file

@ -1,118 +0,0 @@
import icons from "lib/icons"
import nix, { type Nixpkg } from "service/nix"
const iconVisible = Variable(false)
function Item(pkg: Nixpkg) {
const name = Widget.Label({
class_name: "name",
label: pkg.name.split(".").at(-1),
})
const subpkg = pkg.name.includes(".") ? Widget.Label({
class_name: "description",
hpack: "end",
hexpand: true,
label: ` ${pkg.name.split(".").slice(0, -1).join(".")}`,
}) : null
const version = Widget.Label({
class_name: "version",
label: pkg.version,
hexpand: true,
hpack: "end",
})
const description = pkg.description ? Widget.Label({
class_name: "description",
label: pkg.description,
justification: "left",
wrap: true,
hpack: "start",
max_width_chars: 40,
}) : null
return Widget.Box(
{
attribute: { name: pkg.name },
vertical: true,
},
Widget.Separator(),
Widget.Button(
{
class_name: "nix-item",
on_clicked: () => {
nix.run(pkg.name)
App.closeWindow("launcher")
},
},
Widget.Box(
{ vertical: true },
Widget.Box([name, version]),
Widget.Box([
description as ReturnType<typeof Widget.Label>,
subpkg as ReturnType<typeof Widget.Label>,
]),
),
),
)
}
export function Spinner() {
const icon = Widget.Icon({
icon: icons.nix.nix,
class_name: "spinner",
css: `
@keyframes spin {
to { -gtk-icon-transform: rotate(1turn); }
}
image.spinning {
animation-name: spin;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
`,
setup: self => self.hook(nix, () => {
self.toggleClassName("spinning", !nix.ready)
}),
})
return Widget.Revealer({
transition: "slide_left",
child: icon,
reveal_child: Utils.merge([
nix.bind("ready"),
iconVisible.bind(),
], (ready, show) => !ready || show),
})
}
export function NixRun() {
const list = Widget.Box<ReturnType<typeof Item>>({
vertical: true,
})
const revealer = Widget.Revealer({
child: list,
})
async function filter(term: string) {
iconVisible.value = Boolean(term)
if (!term)
revealer.reveal_child = false
if (term.trim()) {
const found = await nix.query(term)
list.children = found.map(k => Item(nix.db[k]))
revealer.reveal_child = true
}
}
return Object.assign(revealer, {
filter,
run: nix.run,
})
}

View file

@ -1,66 +0,0 @@
import icons from "lib/icons"
import sh from "service/sh"
const iconVisible = Variable(false)
function Item(bin: string) {
return Widget.Box(
{
attribute: { bin },
vertical: true,
},
Widget.Separator(),
Widget.Button({
child: Widget.Label({
label: bin,
hpack: "start",
}),
class_name: "sh-item",
on_clicked: () => {
Utils.execAsync(bin)
App.closeWindow("launcher")
},
}),
)
}
export function Icon() {
const icon = Widget.Icon({
icon: icons.app.terminal,
class_name: "spinner",
})
return Widget.Revealer({
transition: "slide_left",
child: icon,
reveal_child: iconVisible.bind(),
})
}
export function ShRun() {
const list = Widget.Box<ReturnType<typeof Item>>({
vertical: true,
})
const revealer = Widget.Revealer({
child: list,
})
async function filter(term: string) {
iconVisible.value = Boolean(term)
if (!term)
revealer.reveal_child = false
if (term.trim()) {
const found = await sh.query(term)
list.children = found.map(Item)
revealer.reveal_child = true
}
}
return Object.assign(revealer, {
filter,
run: sh.run,
})
}

View file

@ -1,138 +0,0 @@
import { type Notification } from "types/service/notifications"
import GLib from "gi://GLib"
import icons from "lib/icons"
const time = (time: number, format = "%H:%M") => GLib.DateTime
.new_from_unix_local(time)
.format(format)
const NotificationIcon = ({ app_entry, app_icon, image }: Notification) => {
if (image) {
return Widget.Box({
vpack: "start",
hexpand: false,
class_name: "icon img",
css: `
background-image: url("${image}");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
min-width: 78px;
min-height: 78px;
`,
})
}
let icon = icons.fallback.notification
if (Utils.lookUpIcon(app_icon))
icon = app_icon
if (Utils.lookUpIcon(app_entry || ""))
icon = app_entry || ""
return Widget.Box({
vpack: "start",
hexpand: false,
class_name: "icon",
css: `
min-width: 78px;
min-height: 78px;
`,
child: Widget.Icon({
icon,
size: 58,
hpack: "center", hexpand: true,
vpack: "center", vexpand: true,
}),
})
}
export default (notification: Notification) => {
const content = Widget.Box({
class_name: "content",
children: [
NotificationIcon(notification),
Widget.Box({
hexpand: true,
vertical: true,
children: [
Widget.Box({
children: [
Widget.Label({
class_name: "title",
xalign: 0,
justification: "left",
hexpand: true,
max_width_chars: 24,
truncate: "end",
wrap: true,
label: notification.summary.trim(),
use_markup: true,
}),
Widget.Label({
class_name: "time",
vpack: "start",
label: time(notification.time),
}),
Widget.Button({
class_name: "close-button",
vpack: "start",
child: Widget.Icon("window-close-symbolic"),
on_clicked: notification.close,
}),
],
}),
Widget.Label({
class_name: "description",
hexpand: true,
use_markup: true,
xalign: 0,
justification: "left",
label: notification.body.trim(),
max_width_chars: 24,
wrap: true,
}),
],
}),
],
})
const actionsbox = notification.actions.length > 0 ? Widget.Revealer({
transition: "slide_down",
child: Widget.EventBox({
child: Widget.Box({
class_name: "actions horizontal",
children: notification.actions.map(action => Widget.Button({
class_name: "action-button",
on_clicked: () => notification.invoke(action.id),
hexpand: true,
child: Widget.Label(action.label),
})),
}),
}),
}) : null
const eventbox = Widget.EventBox({
vexpand: false,
on_primary_click: notification.dismiss,
on_hover() {
if (actionsbox)
actionsbox.reveal_child = true
},
on_hover_lost() {
if (actionsbox)
actionsbox.reveal_child = true
notification.dismiss()
},
child: Widget.Box({
vertical: true,
children: actionsbox ? [content, actionsbox] : [content],
}),
})
return Widget.Box({
class_name: `notification ${notification.urgency}`,
child: eventbox,
})
}

View file

@ -1,90 +0,0 @@
import Notification from "./Notification"
import options from "options"
const notifications = await Service.import("notifications")
const { transition } = options
const { position } = options.notifications
const { timeout, idle } = Utils
function Animated(id: number) {
const n = notifications.getNotification(id)!
const widget = Notification(n)
const inner = Widget.Revealer({
transition: "slide_left",
transition_duration: transition.value,
child: widget,
})
const outer = Widget.Revealer({
transition: "slide_down",
transition_duration: transition.value,
child: inner,
})
const box = Widget.Box({
hpack: "end",
child: outer,
})
idle(() => {
outer.reveal_child = true
timeout(transition.value, () => {
inner.reveal_child = true
})
})
return Object.assign(box, {
dismiss() {
inner.reveal_child = false
timeout(transition.value, () => {
outer.reveal_child = false
timeout(transition.value, () => {
box.destroy()
})
})
},
})
}
function PopupList() {
const map: Map<number, ReturnType<typeof Animated>> = new Map
const box = Widget.Box({
hpack: "end",
vertical: true,
css: options.notifications.width.bind().as(w => `min-width: ${w}px;`),
})
function remove(_: unknown, id: number) {
map.get(id)?.dismiss()
map.delete(id)
}
return box
.hook(notifications, (_, id: number) => {
if (id !== undefined) {
if (map.has(id))
remove(null, id)
if (notifications.dnd)
return
const w = Animated(id)
map.set(id, w)
box.children = [w, ...box.children]
}
}, "notified")
.hook(notifications, remove, "dismissed")
.hook(notifications, remove, "closed")
}
export default (monitor: number) => Widget.Window({
monitor,
name: `notifications${monitor}`,
anchor: position.bind(),
class_name: "notifications",
child: Widget.Box({
css: "padding: 2px;",
child: PopupList(),
}),
})

View file

@ -1,111 +0,0 @@
import { icon } from "lib/utils"
import icons from "lib/icons"
import Progress from "./Progress"
import brightness from "service/brightness"
import options from "options"
const audio = await Service.import("audio")
const { progress, microphone } = options.osd
const DELAY = 2500
function OnScreenProgress(vertical: boolean) {
const indicator = Widget.Icon({
size: 42,
vpack: "start",
})
const progress = Progress({
vertical,
width: vertical ? 42 : 300,
height: vertical ? 300 : 42,
child: indicator,
})
const revealer = Widget.Revealer({
transition: "slide_left",
child: progress,
})
let count = 0
function show(value: number, icon: string) {
revealer.reveal_child = true
indicator.icon = icon
progress.setValue(value)
count++
Utils.timeout(DELAY, () => {
count--
if (count === 0)
revealer.reveal_child = false
})
}
return revealer
.hook(brightness, () => show(
brightness.screen,
icons.brightness.screen,
), "notify::screen")
.hook(brightness, () => show(
brightness.kbd,
icons.brightness.keyboard,
), "notify::kbd")
.hook(audio.speaker, () => show(
audio.speaker.volume,
icon(audio.speaker.icon_name || "", icons.audio.type.speaker),
), "notify::volume")
}
function MicrophoneMute() {
const icon = Widget.Icon({
class_name: "microphone",
})
const revealer = Widget.Revealer({
transition: "slide_up",
child: icon,
})
let count = 0
let mute = audio.microphone.stream?.is_muted ?? false
return revealer.hook(audio.microphone, () => Utils.idle(() => {
if (mute !== audio.microphone.stream?.is_muted) {
mute = audio.microphone.stream!.is_muted
icon.icon = icons.audio.mic[mute ? "muted" : "high"]
revealer.reveal_child = true
count++
Utils.timeout(DELAY, () => {
count--
if (count === 0)
revealer.reveal_child = false
})
}
}))
}
export default (monitor: number) => Widget.Window({
monitor,
name: `indicator${monitor}`,
class_name: "indicator",
layer: "overlay",
click_through: true,
anchor: ["right", "left", "top", "bottom"],
child: Widget.Box({
css: "padding: 2px;",
expand: true,
child: Widget.Overlay(
{ child: Widget.Box({ expand: true }) },
Widget.Box({
hpack: progress.pack.h.bind(),
vpack: progress.pack.v.bind(),
child: progress.vertical.bind().as(OnScreenProgress),
}),
Widget.Box({
hpack: microphone.pack.h.bind(),
vpack: microphone.pack.v.bind(),
child: MicrophoneMute(),
}),
),
}),
})

View file

@ -1,74 +0,0 @@
import type Gtk from "gi://Gtk?version=3.0"
import GLib from "gi://GLib?version=2.0"
import { range } from "lib/utils"
import options from "options"
type ProgressProps = {
height?: number
width?: number
vertical?: boolean
child: Gtk.Widget
}
export default ({
height = 18,
width = 180,
vertical = false,
child,
}: ProgressProps) => {
const fill = Widget.Box({
class_name: "fill",
hexpand: vertical,
vexpand: !vertical,
hpack: vertical ? "fill" : "start",
vpack: vertical ? "end" : "fill",
child,
})
const container = Widget.Box({
class_name: "progress",
child: fill,
css: `
min-width: ${width}px;
min-height: ${height}px;
`,
})
let fill_size = 0
let animations: number[] = []
return Object.assign(container, {
setValue(value: number) {
if (value < 0)
return
if (animations.length > 0) {
for (const id of animations)
GLib.source_remove(id)
animations = []
}
const axis = vertical ? "height" : "width"
const axisv = vertical ? height : width
const min = vertical ? width : height
const preferred = (axisv - min) * value + min
if (!fill_size) {
fill_size = preferred
fill.css = `min-${axis}: ${preferred}px;`
return
}
const frames = options.transition.value / 10
const goal = preferred - fill_size
const step = goal / frames
animations = range(frames, 0).map(i => Utils.timeout(5 * i, () => {
fill_size += step
fill.css = `min-${axis}: ${fill_size}px`
animations.shift()
}))
},
})
}

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