Updated Hypr, Yazi

This commit is contained in:
2025-10-17 02:05:03 +02:00
parent e20f8b6ea2
commit 7cd7d746e7
141 changed files with 133 additions and 8479 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,407 +0,0 @@
Attribution-NonCommercial 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-NonCommercial 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-NonCommercial 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. NonCommercial means not primarily intended for or directed towards
commercial advantage or monetary compensation. For purposes of
this Public License, the exchange of the Licensed Material for
other material subject to Copyright and Similar Rights by digital
file-sharing or similar means is NonCommercial provided there is
no payment of monetary compensation in connection with the
exchange.
j. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
k. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
l. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part, for NonCommercial purposes only; and
b. produce, reproduce, and Share Adapted Material for
NonCommercial purposes only.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties, including when
the Licensed Material is used other than for NonCommercial
purposes.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database for NonCommercial purposes
only;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.â€<C3A2> The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

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: 1009 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: 1014 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/ags/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, 0],
}
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,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,109 +0,0 @@
import AccountsService from "gi://AccountsService?version=1.0"
import GLib from "gi://GLib?version=2.0"
import icons from "lib/icons"
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(realName || 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,64 +0,0 @@
@import "../style/mixins/floating-widget.scss";
@import "../style/mixins/widget.scss";
@import "../style/mixins/spacing.scss";
@import "../style/mixins/unset.scss";
@import "../style/mixins/a11y-button.scss";
@import "../widget/bar/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,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,20 +0,0 @@
import GLib from "gi://GLib?version=2.0"
import AccountsService from "gi://AccountsService?version=1.0"
const { userName } = AccountsService.UserManager.get_default().list_users()[0]
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,74 +0,0 @@
import options from "options"
const { messageAsync } = await Service.import("hyprland")
const {
hyprland,
theme: {
radius,
blur,
shadows,
dark: {
primary: { bg: darkActive },
},
light: {
primary: { bg: lightActive },
},
scheme,
},
} = options
const deps = [
"hyprland",
radius.id,
blur.id,
shadows.id,
darkActive.id,
lightActive.id,
scheme.id,
]
function activeBorder() {
const color = scheme.value === "dark"
? darkActive.value
: lightActive.value
return color.replace("#", "")
}
function sendBatch(batch: string[]) {
const cmd = batch
.filter(x => !!x)
.map(x => `keyword ${x}`)
.join("; ")
return messageAsync(`[[BATCH]]/${cmd}`)
}
async function setupHyprland() {
sendBatch([
`general:border_size ${hyprland.borderSize.value}`,
`general:gaps_out ${hyprland.gapsOut.value}`,
`general:gaps_in ${hyprland.gapsIn.value}`,
`general:col.active_border rgba(${activeBorder()}ff)`,
`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,116 +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 = `${App.configDir}/config.json`
console.log("Config file: " + configFile)
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"))
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,111 +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).map(widget).flat(1)
}
/**
* @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 => {
return !Utils.exec(`which ${bin}`)
})
if (missing.length > 0) {
console.warn("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,242 +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(true),
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(14),
},
transition: opt(200),
font: {
size: opt(12),
name: opt("CaskaydiaCove Nerd Font"),
},
bar: {
flatButtons: opt(true),
position: opt<"top" | "bottom">("top"),
corners: opt(true),
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",
"battery",
"system",
"powermenu",
]),
},
launcher: {
icon: {
colored: opt(true),
icon: opt(icon(distro.logo, icons.ui.search)),
},
label: {
colored: opt(false),
label: opt(""),
},
action: opt(() => App.toggleWindow("launcher")),
},
date: {
format: opt("%H:%M - %d.%m.%Y"),
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(false),
exclusive: opt(false),
},
messages: {
action: opt(() => App.toggleWindow("datemenu")),
},
systray: {
ignore: opt([
"KDE Connect Indicator",
"spotify-client",
]),
},
media: {
monochrome: opt(false),
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([
[
"brave",
"org.gnome.Calendar",
"obsidian",
],
]),
},
},
overview: {
scale: opt(9),
workspaces: opt(7),
monochromeIcon: opt(false),
},
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("nm-connection-editor"),
media: {
monochromeIcon: opt(false),
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([""]),
width: opt(440),
},
hyprland: {
gaps: opt(2.4),
gapsIn: opt(2),
gapsOut: opt(3),
borderSize: opt(1),
inactiveBorder: opt("333333ff"),
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,52 +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"],
})
}
available = !!Utils.exec("which asusctl")
#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")
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,109 +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") }
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`)
const search = ""
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,43 +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 }
get cmd() { return this.#cmd }
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")
}
}
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,98 +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",
"--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: "png",
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 init")
.then(() => this.#wallpaper)
.catch((e) => console.warn(e))
}
}
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,103 +0,0 @@
/* eslint-disable max-len */
import { type Opt } from "lib/option"
import options from "options"
import { bash, dependencies, sh } from "lib/utils"
const deps = [
"font",
"theme",
"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")),
$("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),
]
async function resetCss() {
if (!dependencies("sass", "fd"))
return
try {
const vars = `${TMP}/variables.scss`
await Utils.writeFile(variables().join("\n"), vars)
const fd = await sh(`fd ".scss" ${App.configDir}`)
const files = fd.split(/\s+/).map(f => `@import '${f}';`)
const scss = [`@import '${vars}';`, ...files].join("\n")
const css = await bash`echo "${scss}" | sass --stdin`
App.applyCss(css, true)
} catch (error) {
logError(error)
}
}
Utils.monitorFile(App.configDir, resetCss)
options.handler(deps, resetCss)
await resetCss()

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,57 +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 pos = options.bar.position.bind()
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: pos.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]())),
}),
}),
})

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,25 +0,0 @@
import options from "options"
const { corners } = 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)
}),
})

View File

@@ -1,234 +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 {
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
}
}
}

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,92 +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,
child: Widget.Icon({
icon: icons.bluetooth.enabled,
visible: bluetooth.bind("enabled"),
}),
})
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,50 +0,0 @@
$_shadow-size: $padding;
$_radius: $radius * $hyprland-gaps-multiplier;
$_margin: 99px;
window.screen-corner {
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 * $hyprland-gaps-multiplier, 0);
box-shadow: 0 0 0 $_radius $bg;
}
box.corner {
border-radius: if($radius>0, $radius * $hyprland-gaps-multiplier, 0);
}
}
}

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,110 +0,0 @@
@import "../notifications/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,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("applauncher", {
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,89 +0,0 @@
import icons from "lib/icons"
import options from "options"
import { bash, dependencies } from "lib/utils"
const iconVisible = Variable(false)
const MAX = options.launcher.sh.max
const BINS = `${Utils.CACHE_DIR}/binaries`
bash("{ IFS=:; ls -H $PATH; } | sort ")
.then(bins => Utils.writeFile(bins, 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)
})
}
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 query(term)
list.children = found.map(Item)
revealer.reveal_child = true
}
}
return Object.assign(revealer, { filter, run })
}

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,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,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,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()
}))
},
})
}

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,41 +0,0 @@
import PopupWindow from "widget/PopupWindow"
import Workspace from "./Workspace"
import options from "options"
import { range } from "lib/utils"
const hyprland = await Service.import("hyprland")
const Overview = (ws: number) => Widget.Box({
class_name: "overview horizontal",
children: ws > 0
? range(ws).map(Workspace)
: hyprland.workspaces
.map(({ id }) => Workspace(id))
.sort((a, b) => a.attribute.id - b.attribute.id),
setup: w => {
if (ws > 0)
return
w.hook(hyprland, (w, id?: string) => {
if (id === undefined)
return
w.children = w.children
.filter(ch => ch.attribute.id !== Number(id))
}, "workspace-removed")
w.hook(hyprland, (w, id?: string) => {
if (id === undefined)
return
w.children = [...w.children, Workspace(Number(id))]
.sort((a, b) => a.attribute.id - b.attribute.id)
}, "workspace-added")
},
})
export default () => PopupWindow({
name: "overview",
layout: "center",
child: options.overview.workspaces.bind().as(Overview),
})

View File

@@ -1,48 +0,0 @@
import { type Client } from "types/service/hyprland"
import { createSurfaceFromWidget, icon } from "lib/utils"
import Gdk from "gi://Gdk"
import Gtk from "gi://Gtk?version=3.0"
import options from "options"
import icons from "lib/icons"
const monochrome = options.overview.monochromeIcon
const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)]
const hyprland = await Service.import("hyprland")
const apps = await Service.import("applications")
const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`)
export default ({ address, size: [w, h], class: c, title }: Client) => Widget.Button({
class_name: "client",
attribute: { address },
tooltip_text: `${title}`,
child: Widget.Icon({
css: options.overview.scale.bind().as(v => `
min-width: ${(v / 100) * w}px;
min-height: ${(v / 100) * h}px;
`),
icon: monochrome.bind().as(m => {
const app = apps.list.find(app => app.match(c))
if (!app)
return icons.fallback.executable + (m ? "-symbolic" : "")
return icon(
app.icon_name + (m ? "-symbolic" : ""),
icons.fallback.executable + (m ? "-symbolic" : ""),
)
}),
}),
on_secondary_click: () => dispatch(`closewindow address:${address}`),
on_clicked: () => {
dispatch(`focuswindow address:${address}`)
App.closeWindow("overview")
},
setup: btn => btn
.on("drag-data-get", (_w, _c, data) => data.set_text(address, address.length))
.on("drag-begin", (_, context) => {
Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(btn))
btn.toggleClassName("hidden", true)
})
.on("drag-end", () => btn.toggleClassName("hidden", false))
.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY),
})

View File

@@ -1,76 +0,0 @@
import Window from "./Window"
import Gdk from "gi://Gdk"
import Gtk from "gi://Gtk?version=3.0"
import options from "options"
const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)]
const scale = (size: number) => (options.overview.scale.value / 100) * size
const hyprland = await Service.import("hyprland")
const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`)
const size = (id: number) => {
const def = { h: 1080, w: 1920 }
const ws = hyprland.getWorkspace(id)
if (!ws)
return def
const mon = hyprland.getMonitor(ws.monitorID)
return mon ? { h: mon.height, w: mon.width } : def
}
export default (id: number) => {
const fixed = Widget.Fixed()
// TODO: early return if position is unchaged
async function update() {
const json = await hyprland.messageAsync("j/clients").catch(() => null)
if (!json)
return
fixed.get_children().forEach(ch => ch.destroy())
const clients = JSON.parse(json) as typeof hyprland.clients
clients
.filter(({ workspace }) => workspace.id === id)
.forEach(c => {
const x = c.at[0] - (hyprland.getMonitor(c.monitor)?.x || 0)
const y = c.at[1] - (hyprland.getMonitor(c.monitor)?.y || 0)
c.mapped && fixed.put(Window(c), scale(x), scale(y))
})
fixed.show_all()
}
return Widget.Box({
attribute: { id },
tooltipText: `${id}`,
class_name: "workspace",
vpack: "center",
css: options.overview.scale.bind().as(v => `
min-width: ${(v / 100) * size(id).w}px;
min-height: ${(v / 100) * size(id).h}px;
`),
setup(box) {
box.hook(options.overview.scale, update)
box.hook(hyprland, update, "notify::clients")
box.hook(hyprland.active.client, update)
box.hook(hyprland.active.workspace, () => {
box.toggleClassName("active", hyprland.active.workspace.id === id)
})
},
child: Widget.EventBox({
expand: true,
on_primary_click: () => {
App.closeWindow("overview")
dispatch(`workspace ${id}`)
},
setup: eventbox => {
eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY)
eventbox.connect("drag-data-received", (_w, _c, _x, _y, data) => {
const address = new TextDecoder().decode(data.get_data())
dispatch(`movetoworkspacesilent ${id},address:${address}`)
})
},
child: fixed,
}),
})
}

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,56 +0,0 @@
import PopupWindow from "widget/PopupWindow"
import powermenu, { type Action } from "service/powermenu"
import icons from "lib/icons"
import options from "options"
import type Gtk from "gi://Gtk?version=3.0"
const { layout, labels } = options.powermenu
const SysButton = (action: Action, label: string) => Widget.Button({
on_clicked: () => powermenu.action(action),
child: Widget.Box({
vertical: true,
class_name: "system-button",
children: [
Widget.Icon(icons.powermenu[action]),
Widget.Label({
label,
visible: labels.bind(),
}),
],
}),
})
export default () => PopupWindow({
name: "powermenu",
transition: "crossfade",
child: Widget.Box<Gtk.Widget>({
class_name: "powermenu horizontal",
setup: self => self.hook(layout, () => {
self.toggleClassName("box", layout.value === "box")
self.toggleClassName("line", layout.value === "line")
}),
children: layout.bind().as(layout => {
switch (layout) {
case "line": return [
SysButton("shutdown", "Shutdown"),
SysButton("logout", "Log Out"),
SysButton("reboot", "Reboot"),
SysButton("sleep", "Sleep"),
]
case "box": return [
Widget.Box(
{ vertical: true },
SysButton("shutdown", "Shutdown"),
SysButton("logout", "Log Out"),
),
Widget.Box(
{ vertical: true },
SysButton("reboot", "Reboot"),
SysButton("sleep", "Sleep"),
),
]
}
}),
}),
})

View File

@@ -1,47 +0,0 @@
import PopupWindow from "widget/PopupWindow"
import powermenu from "service/powermenu"
export default () => PopupWindow({
name: "verification",
transition: "crossfade",
child: Widget.Box({
class_name: "verification",
vertical: true,
children: [
Widget.Box({
class_name: "text-box",
vertical: true,
children: [
Widget.Label({
class_name: "title",
label: powermenu.bind("title"),
}),
Widget.Label({
class_name: "desc",
label: "Are you sure?",
}),
],
}),
Widget.Box({
class_name: "buttons horizontal",
vexpand: true,
vpack: "end",
homogeneous: true,
children: [
Widget.Button({
child: Widget.Label("No"),
on_clicked: () => App.toggleWindow("verification"),
setup: self => self.hook(App, (_, name: string, visible: boolean) => {
if (name === "verification" && visible)
self.grab_focus()
}),
}),
Widget.Button({
child: Widget.Label("Yes"),
on_clicked: () => Utils.exec(powermenu.cmd),
}),
],
}),
],
}),
})

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