Compare commits

..

No commits in common. "master" and "2021-eleventy/final" have entirely different histories.

244 changed files with 810 additions and 18683 deletions

76
.eleventy.js Normal file
View File

@ -0,0 +1,76 @@
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
const markdownIt = require('markdown-it')
const markdownItAnchor = require('markdown-it-anchor')
const htmlmin = require("html-minifier")
module.exports = function(eleventyConfig) {
// Plugins
eleventyConfig.addPlugin(syntaxHighlight)
eleventyConfig.addTransform("htmlmin", (content, outputPath) => {
if (outputPath.endsWith(".html")) {
return htmlmin.minify(content, {
collapseWhitespace: true,
removeComments: true,
useShortDoctype: true,
});
}
return content;
});
// To enable merging of tags
eleventyConfig.setDataDeepMerge(true)
// Copy these static files to _site folder
eleventyConfig.addPassthroughCopy('src/assets')
eleventyConfig.addPassthroughCopy('src/manifest.json')
// To create excerpts
eleventyConfig.setFrontMatterParsingOptions({
excerpt: true,
excerpt_alias: 'post_excerpt',
excerpt_separator: '<!-- excerpt -->'
})
// To create a filter to determine duration of post
eleventyConfig.addFilter('readTime', (value) => {
const content = value
const textOnly = content.split(" ") // content.replace(/(<([^>]+)>)/gi, '')
const readingSpeedPerMin = 200
return Math.max(1, Math.floor(textOnly.length / readingSpeedPerMin))
})
// get proper date in utc
eleventyConfig.addFilter('realDate', (value) => {
const actualDate = new Date(value);
actualDate.setDate(actualDate.getDate() + 1);
return actualDate;
})
// Enable us to iterate over all the tags, excluding posts and all
eleventyConfig.addCollection('tagList', collection => {
const tagsSet = new Set()
collection.getAll().forEach(item => {
if (!item.data.tags) return
item.data.tags
.filter(tag => !['posts', 'all'].includes(tag))
.forEach(tag => tagsSet.add(tag))
})
return Array.from(tagsSet).sort()
})
const md = markdownIt({ linkify: true, html: true })
md.use(markdownItAnchor, { level: [1, 2], permalink: true, permalinkBefore: false, permalinkSymbol: '#' })
eleventyConfig.setLibrary('md', md)
// asset_img shortcode
eleventyConfig.addLiquidShortcode('asset_img', (filename, css) => {
return `<img class="my-4" src="/assets/img/posts/${filename}" style="${css}" />`
})
return {
dir: {
input: 'src'
}
}
}

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
_site/*
!.eleventy.js

34
.eslintrc.json Normal file
View File

@ -0,0 +1,34 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2020": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 11
},
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
],
"array-element-newline": ["error", {
"ArrayExpression": "consistent",
"ArrayPattern": { "minItems": 3 }
}]
}
}

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
yarn.lock binary
package-lock.json binary

9
.gitignore vendored
View File

@ -1,8 +1,3 @@
package-lock.json
_site
node_modules
*.log*
.nuxt
.nitro
.cache
.output
.env
dist

View File

@ -1,3 +0,0 @@
pages/ignore/*.vue
layouts/*-ignore.vue

661
LICENSE
View File

@ -1,661 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

View File

@ -1,36 +1,3 @@
# Oeufs?
# public
Après le HTML manuscrit et le générateur de site statique — c'est Nuxt!
Instructions post-compilation (pendant Nuxt n'a pas le prérendu)
- Compilez `/script.ts` à `/script.js` (`tsc script.ts -m esnext -t esnext --moduleResolution node`)
Lisez la [documentation de Nuxt](https://v3.nuxtjs.org) pour en savoir plus.
## Installation
Assurez-vous d'installer les dépendances:
```bash
# yarn
yarn install
```
## Serveur de développement
Démarrez le serveur de développement sur http://localhost:3000
```bash
yarn dev
```
## Production
Prévisualisez la production sur votre système local:
```bash
yarn preview
```
Lisez la [documentation de déploiement](https://v3.nuxtjs.org/guide/deploy/presets) pour en savoir plus.
Site at [https://eggworld.tk](https://eggworld.tk)

View File

@ -1,5 +0,0 @@
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>

View File

@ -1,52 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Bitter:wght@300;400;600;700;800;900&display=swap");
@mixin headings {
h1,
h2,
h3,
h4,
h5,
h6 {
@content;
}
}
* {
box-sizing: border-box;
// for that cool wave dark mode effect
z-index: 1;
position: relative;
}
html,
body,
div#__nuxt {
height: 100%;
}
main {
flex-grow: 1;
}
:root {
--text-color: #243746;
--bg: #f1e7d0;
}
.dark {
--text-color: #ebf4f1;
--bg: #091a28;
}
.text-bitter {
font-family: Bitter, ui-sans-serif, system-ui, -apple-system,
BlinkMacSystemFont, "Segoe UI", Roboto, "Open Sans", "Helvetica Neue",
sans-serif;
}
.text-article {
font-family: "Source Serif Pro", serif;
line-height: 1.8;
color: #111;
font-size: 1.25rem;
}

View File

@ -1,22 +0,0 @@
@import "base.scss";
.prose article {
@include headings {
& > a:hover,
& > a:active {
text-decoration: underline;
text-decoration-skip-ink: all;
@apply text-blue-700 dark:text-blue-400;
&::before {
content: "#";
position: absolute;
opacity: 0.5;
left: -2rem;
}
}
}
a:hover {
@apply hover:text-blue-700 dark:hover:text-blue-400;
}
}

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 11.807C10.7418 10.5483 9.88488 8.94484 9.53762 7.1993C9.19037 5.45375 9.36832 3.64444 10.049 2C8.10826 2.38205 6.3256 3.33431 4.92899 4.735C1.02399 8.64 1.02399 14.972 4.92899 18.877C8.83499 22.783 15.166 22.782 19.072 18.877C20.4723 17.4805 21.4245 15.6983 21.807 13.758C20.1625 14.4385 18.3533 14.6164 16.6077 14.2692C14.8622 13.9219 13.2588 13.0651 12 11.807V11.807Z" />
</svg>

Before

Width:  |  Height:  |  Size: 490 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="0" stroke-linecap="round" stroke-linejoin="round" class="feather feather-star"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon></svg>

Before

Width:  |  Height:  |  Size: 339 B

View File

@ -1,7 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.995 12C6.995 14.761 9.241 17.007 12.002 17.007C14.763 17.007 17.009 14.761 17.009 12C17.009 9.239 14.763 6.993 12.002 6.993C9.241 6.993 6.995 9.239 6.995 12ZM11 19H13V22H11V19ZM11 2H13V5H11V2ZM2 11H5V13H2V11ZM19 11H22V13H19V11Z" />
<path d="M5.63702 19.778L4.22302 18.364L6.34402 16.243L7.75802 17.657L5.63702 19.778Z" />
<path d="M16.242 6.34405L18.364 4.22205L19.778 5.63605L17.656 7.75805L16.242 6.34405Z" />
<path d="M6.34402 7.75902L4.22302 5.63702L5.63802 4.22302L7.75802 6.34502L6.34402 7.75902Z" />
<path d="M19.778 18.3639L18.364 19.7779L16.242 17.6559L17.656 16.2419L19.778 18.3639Z" />
</svg>

Before

Width:  |  Height:  |  Size: 712 B

BIN
blog-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
blog-v2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@ -1,56 +0,0 @@
<script setup lang="ts">
import type { BlogParsedContent } from "@/shared/types";
import { calcReadingTime } from "@/shared/metadata";
const docs = await queryContent<BlogParsedContent>("/blog")
.sort({ date: 1 })
.where({ _draft: false })
.find();
const latest = docs.at(-1) as BlogParsedContent;
</script>
<template>
<div class="prose dark:prose-invert flex onhover">
<HomeStatBox
:href="latest._path"
color="lightblue"
darkcolor="#497482"
title="Latest blog post"
>
<h2 class="m-0 mt-4 mb-1">{{ latest.title }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 m-0">
<Date :doc="latest" /> · {{ calcReadingTime(latest).minutes }} min read
</p>
<div class="tag-list mt-1">
<Tag
v-for="(tag, index) in latest.tags"
:key="index"
:dest="`/tags/blog/${tag}`"
:name="tag"
/>
</div>
<ContentRenderer
tag="article"
:value="latest"
:excerpt="true"
class="text-gray-600 dark:text-gray-300 text-base m-0 mt-5"
>
<ContentRendererMarkdown :value="latest" :excerpt="true" />
<template #empty>
<p>No description found.</p>
</template>
</ContentRenderer>
</HomeStatBox>
</div>
</template>
<style scoped lang="scss">
h2 {
overflow-wrap: break-word;
}
div.onhover:hover h2 {
@apply text-blue-700 dark:text-blue-400;
}
</style>

View File

@ -1,34 +0,0 @@
<template>
<a href="#" class="go-top" />
</template>
<style scoped>
.go-top {
--offset: 20rem;
position: sticky;
bottom: 1rem;
left: 1rem;
margin-right: 1rem;
place-self: end;
margin-top: calc(100vh + var(--offset));
width: 2rem;
height: 2rem;
background: #ff8b24;
border-radius: 1rem;
box-shadow: 0 0.1rem 0.5rem 0 gray;
z-index: 2;
}
html.dark .go-top {
box-shadow: 0 0.1rem 0.5rem 0 black;
}
.go-top:before {
content: "";
position: absolute;
inset: 30%;
transform: translateY(20%) rotate(-45deg);
border-top: 0.35rem solid #fff;
border-right: 0.35rem solid #fff;
}
</style>

View File

@ -1,99 +0,0 @@
<script setup lang="ts">
import IconSun from "@/assets/images/sun.svg?component";
import IconMoon from "@/assets/images/moon.svg?component";
const colorMode = useColorMode();
const toggle = () => {
colorMode.preference = colorMode.value === "light" ? "dark" : "light";
};
</script>
<template>
<label
for="dark-toggle"
class="toggle-wrapper"
aria-label="Dark mode indicator label"
>
<div class="toggle">
<div class="icons">
<IconMoon />
<IconSun />
</div>
<input
id="dark-toggle"
name="dark-toggle"
type="checkbox"
ref="darkToggleEl"
aria-label="Toggle dark mode"
@click="toggle"
/>
</div>
</label>
</template>
<style scoped>
.toggle-wrapper {
width: 6rem;
display: block;
--black: #333333;
--white: #f5f5f5;
--scale: 2rem;
--transition: 0.2s ease;
--bg: var(--white);
--fg: var(--black);
}
html.dark .toggle-wrapper {
--black: #f5f5f5;
--white: #333333;
}
.toggle {
height: var(--scale);
width: calc(var(--scale) * 2);
background: var(--fg);
border-radius: var(--scale);
padding: calc(var(--scale) * 0.175);
position: relative;
margin: auto;
cursor: pointer;
transition: background var(--transition);
}
.toggle::before {
content: "";
display: block;
height: calc(var(--scale) * 0.65);
width: calc(var(--scale) * 0.65);
border-radius: 50%;
background: var(--bg);
position: absolute;
z-index: 2;
transform: translate(0);
transition: transform var(--transition), background var(--transition);
}
html.dark .toggle::before {
transform: translateX(calc(var(--scale)));
}
.toggle input {
position: absolute;
top: 0;
opacity: 0;
}
.toggle .icons {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
}
.toggle .icons svg {
transform: scale(0.7);
z-index: 0;
fill: var(--bg);
}
</style>

View File

@ -1,45 +0,0 @@
<script setup lang="ts">
import type { GithubPushEvent } from "@/shared/github";
import type { Ref } from "vue";
const FEED_URL = "https://api.github.com/users/potatoeggy/events";
const imgUrl = ref("");
const href = ref("");
onMounted(async () => {
const results = (await useFetch(FEED_URL)).data as Ref<GithubPushEvent[]>;
const latestEvent = results.value.find(
(event) => event.type === "PushEvent"
) as GithubPushEvent;
const latestCommit = latestEvent.payload.commits[0];
imgUrl.value = `https://opengraph.githubassets.com/hash/${latestEvent.repo.name}/commit/${latestCommit.sha}`;
href.value = `https://github.com/${latestEvent.repo.name}/commit/${latestCommit.sha}`;
});
</script>
<template>
<div class="prose dark:prose-invert">
<HomeStatBox
:href
id="github-commit-a"
color="lightgray"
darkcolor="slategray"
title="Latest commit"
:clearstyles="true"
>
<img
class="m-0 w-full h-full"
:src="imgUrl"
id="github-commit-img"
alt="Latest GitHub commit"
/>
<!--
<div>
<h2>{{ title }}</h2>
<p v-if="description">{{ description }}</p>
</div>
-->
<noscript> Enable JavaScript to see the latest commit! </noscript>
</HomeStatBox>
</div>
</template>

View File

@ -1,13 +0,0 @@
<script setup lang="ts">
import { getPrettyDate, getUtcDate } from "~~/shared/metadata";
import type { AnyParsedContent } from "~~/shared/types";
const { doc } = defineProps<{ doc: AnyParsedContent }>();
const prettyDate = getPrettyDate(doc);
const utcDate = getUtcDate(doc);
</script>
<template>
<time pubdate :datetime="utcDate">{{ prettyDate }}</time>
</template>

View File

@ -1,203 +0,0 @@
<script setup lang="ts">
import { navItems } from "@/data/navItems";
const getSvgIcon = async (name: string) => {
const module = await import(
`../assets/images/nav/${name.toLowerCase()}.svg?raw`
);
return module.default;
};
</script>
<template>
<div class="hamburger">
<input
class="checkbox"
type="checkbox"
id="checkbox"
aria-label="Hamburger menu toggle"
/>
<label
class="checkbox-label"
for="checkbox"
aria-label="Hamburger menu indicator label"
>
<svg class="ham ham-rotate" viewBox="0 0 100 100" width="60">
<path
class="line top"
d="m 30,33 h 40 c 0,0 9.044436,-0.654587 9.044436,-8.508902 0,-7.854315 -8.024349,-11.958003 -14.89975,-10.85914 -6.875401,1.098863 -13.637059,4.171617 -13.637059,16.368042 v 40"
/>
<path class="line middle" d="m 30,50 h 40" />
<path
class="line bottom"
d="m 30,67 h 40 c 12.796276,0 15.357889,-11.717785 15.357889,-26.851538 0,-15.133752 -4.786586,-27.274118 -16.667516,-27.274118 -11.88093,0 -18.499247,6.994427 -18.435284,17.125656 l 0.252538,40"
/>
</svg>
</label>
<ul class="drawer prose dark:prose-invert">
<li class="m-0" v-for="(item, index) in navItems" :key="index">
<!-- stupid vite doesn't let require work
i should have just hardcoded the navbar items -->
<a :href="item.href" class="p-2 flex gap-2">
<img
:src="`/nav/${item.title.toLowerCase()}.svg`"
class="m-0"
preload="auto"
:alt="`${item.title} logo`"
/>
{{ item.title }}
</a>
<hr class="m-2" v-if="index !== navItems.length - 1" />
</li>
</ul>
</div>
</template>
<style scoped>
input.checkbox {
outline: none;
width: 0;
opacity: 0;
}
input.checkbox ~ .drawer {
opacity: 0;
right: 0;
top: 0;
position: absolute;
transform: scale(0);
}
input.checkbox:checked ~ .drawer,
.drawer:hover {
/** input.checkbox:focus:not(:checked) ~ .drawer,
* input.checkbox:hover ~ .drawer,
*
* play with focus to make it so that you can click outside
* of the hamburger to close it
* problem with focus is that pressing the menu again doesn't close it
* also so that you can hover over it to open it these are
* surprisingly annoying
*/
opacity: 1;
transform: scale(1) translate(0.5rem, 3.25rem);
}
.drawer {
--drawer-bg: white;
--drawer-border-bg: gray;
transition: transform var(--trans), opacity var(--trans), border var(--trans),
background var(--trans);
padding: 1rem;
right: 0;
background: var(--drawer-bg);
border: 1px solid var(--drawer-border-bg);
display: flex;
flex-direction: column;
align-items: center;
border-radius: 0.5rem;
width: 12rem;
--drawer-drop-color: gray;
box-shadow: 0 0.25rem 0.5rem 0 var(--drawer-drop-color);
}
html.dark .drawer {
--drawer-bg: #222;
--drawer-border-bg: darkslategray;
--drawer-drop-color: black;
}
.drawer::before {
content: "";
width: 0;
height: 0;
position: absolute;
--tri-size: 0.6rem;
border-left: var(--tri-size) solid transparent;
border-right: var(--tri-size) solid transparent;
border-bottom: var(--tri-size) solid var(--drawer-border-bg);
right: 1.75rem;
top: calc(-1 * var(--tri-size));
transition: border var(--trans);
}
.drawer::after {
content: "";
width: 0;
height: 0;
position: absolute;
--tri-size: 0.56rem;
border-left: var(--tri-size) solid transparent;
border-right: var(--tri-size) solid transparent;
border-bottom: var(--tri-size) solid var(--drawer-bg);
right: 1.8rem;
top: -0.53rem; /*calc(-1 * var(--tri-size));*/
transition: border var(--trans);
}
.drawer li {
list-style: none;
width: 100%;
}
.drawer li a {
/* overwrite tailwind */
text-decoration: none;
border-radius: 0.5rem;
width: 100%;
}
.drawer li a:hover,
.drawer li a:active {
--drawer-active-color: lightgray;
background: var(--drawer-active-color);
}
html.dark .drawer li a {
--drawer-active-color: darkslategray;
}
html.dark .drawer img {
filter: invert(1); /* brightness didn't work */
}
/* hamburger animation */
.ham {
cursor: pointer;
transition: transform 400ms;
user-select: none;
height: 3.75rem;
}
.line {
fill: none;
transition: stroke-dasharray 400ms, stroke-dashoffset 400ms;
stroke: #000;
stroke-width: 5.5;
stroke-linecap: round;
}
html.dark .line {
stroke: #fff;
}
.ham .top {
stroke-dasharray: 40 139;
}
.ham .bottom {
stroke-dasharray: 40 180;
}
input.checkbox:checked ~ label.checkbox-label .ham .top {
stroke-dashoffset: -98px;
}
input.checkbox:checked ~ label.checkbox-label .ham .bottom {
stroke-dashoffset: -138px;
}
input.checkbox:checked ~ label.checkbox-label .ham-rotate {
transform: rotate(45deg);
}
</style>

View File

@ -1,101 +0,0 @@
<script setup lang="ts">
const props = defineProps<{ strings: string[]; class?: string }>();
</script>
<template>
<h1 :class="[props.class, 'text-loop relative text-center w-full h-16']">
<span class="text absolute w-full" v-for="s in props.strings" :key="s">
{{ s }}
</span>
</h1>
</template>
<style scoped lang="scss">
@use "sass:math";
@mixin text-loop($els) {
.text-loop {
overflow: hidden;
$duration: 3s;
@if $els > 1 {
& > span {
display: block;
opacity: 0;
@for $i from 1 through $els {
&:nth-child(#{$i}) {
animation: move-test-#{$i} $duration * $els infinite;
}
}
}
}
}
@for $i from 1 through $els {
@keyframes move-test-#{$i} {
$interval: calc(100% / $els);
$upper_bound: $interval * $i;
$lower_bound: $interval * ($i - 1);
// we try to make the previous exit and the next enter
// at the same time, also taking care of negatives
// for i = 1, this is negative, so start the animation at the end of the cycle
@if $i > 1 {
0% {
opacity: 0;
transform: translateY(100%);
}
#{$lower_bound - $interval * 0.05} {
opacity: 0;
transform: translateY(100%);
}
}
#{$lower_bound} {
opacity: 1;
transform: translateY(0%);
}
#{$lower_bound + $interval * 0.95} {
opacity: 1;
transform: translateY(0%);
}
#{$upper_bound} {
opacity: 0;
transform: translateY(-100%);
}
@if $i == 1 {
// reset el 1
#{100% - $interval * 0.05} {
opacity: 0;
transform: translateY(100%);
}
100% {
opacity: 1;
transform: translateY(0%);
}
} @else {
100% {
opacity: 0;
transform: translateY(-100%);
}
}
}
}
}
/**
* For one element, we have the following pattern. To expand it to 2+
* els, we divide 100% by the number of els and turn on the animation
* only at the correct time.
* -5%: invis
* 0%: vis
* 95%: vis
* 100%: invis
*/
@include text-loop(3);
</style>

View File

@ -1,87 +0,0 @@
<script setup lang="ts">
import type { Color, ViewportLength } from "csstype";
const {
color = "pink",
darkcolor = "#c88994",
clearstyles = false,
...props
} = defineProps<{
href?: string;
id?: string;
color?: Color;
darkcolor?: Color;
title?: string;
clearstyles?: boolean;
forceheight?: ViewportLength<"rem">;
}>();
const padding = clearstyles ? "0" : "1rem";
const height = props.forceheight ?? "100%";
// v-bind DOES NOT WORK on initial render
// so unfortunately we have to use the old way
const cssVars = {
"--padding": padding,
"--height": height,
"--color": color,
"--darkcolor": darkcolor,
};
</script>
<template>
<a class="no-underline inline-block flex flex-col items-stretch" :href :id>
<div class="container box" :style="cssVars">
<p class="m-0 w-full title">{{ title }}</p>
<div class="main-content">
<slot />
</div>
</div>
</a>
</template>
<style scoped>
.container {
/* make sure width is good for fullscreen 1080p,
* fullscreen 1080p at 1.25 scaling,
* mobile
*/
width: 28rem;
height: var(--height);
border: 0.5rem solid var(--color);
border-radius: 0.5rem;
transition: transform 0.2s ease;
box-shadow: 0 0.1rem 0.5rem 0 gray;
}
.container:hover,
.container:active {
transform: scale(1.05);
}
html.dark .container {
border: 0.5rem solid var(--darkcolor);
box-shadow: 0 0.1rem 0.5rem 0 black;
}
.main-content {
padding: var(--padding);
padding-top: 0;
overflow-wrap: break-word;
}
.title {
background: var(--color);
}
html.dark .title {
background: var(--darkcolor);
}
@media screen and (max-width: 600px) {
.container {
width: 90vw;
}
}
</style>

View File

@ -1,128 +0,0 @@
<script setup lang="ts">
import ColourPicker from "./ColourPicker.vue";
import { navItems } from "@/data/navItems";
</script>
<template>
<nav class="flex items-center justify-between">
<ul>
<li class="home-text"><a href="/">Oeufs?</a></li>
<li v-for="(item, index) in navItems" :key="index">
<a :href="item.href" class="flex gap-2">
<img
:src="`/nav/${item.title.toLowerCase()}.svg`"
:alt="`${item.title} logo`"
/>
{{ item.title }}</a
>
</li>
</ul>
<div class="flex items-center">
<ColourPicker />
<div class="hamburger">
<HamburgerMenu />
</div>
</div>
</nav>
</template>
<style scoped>
nav {
--nav-drop-color: lightgray;
height: 4rem;
width: 100%;
box-shadow: 0 0.25rem 0.5rem 0 var(--nav-drop-color);
padding: 1rem;
/* main stuff is z-index 1 and the hamburger must be above everything else */
z-index: 2;
}
html.dark nav {
--nav-drop-color: black;
}
html.dark nav img {
filter: invert(1);
}
ul {
display: flex;
align-items: center;
gap: 1rem;
}
li {
font-size: large;
border-radius: 0.5rem;
padding: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
}
li:hover:not(.home-text),
li:active:not(.home-text) {
--nav-active-color: lightgray;
background: var(--nav-active-color);
}
html.dark li:hover,
html.dark li:active {
--nav-active-color: darkslategray;
}
li.home-text {
font-size: x-large;
font-weight: bold;
}
.hamburger {
width: 0rem;
opacity: 0;
}
* {
--trans: 0.2s ease;
--box-trans-time: 0.4s;
transition:
opacity var(--trans),
transform var(--trans),
gap var(--trans),
width var(--trans),
box-shadow var(--box-trans-time) ease,
filter var(--trans),
padding-left var(--trans),
padding-right var(--trans);
}
@media screen and (max-width: 600px) {
.hamburger {
display: flex;
width: 4rem;
opacity: 1;
}
li:not(.home-text) {
width: 0;
opacity: 0;
padding: 0;
padding-left: 0;
padding-right: 0;
/* accessibility? screw accessibility
* i want my pretty animations
*/
}
ul {
gap: 0rem;
}
nav {
padding-left: 0;
padding-right: 0;
}
}
html.dark svg {
fill: white;
}
</style>

View File

@ -1,58 +0,0 @@
<script setup lang="ts">
import type { AnyParsedContent } from "@/shared/types";
import { calcReadingTime } from "@/shared/metadata";
import { SpecialTags } from "@/data/specialTags";
import IconStar from "@/assets/images/star.svg?component";
const { post, type } = defineProps<{
post: AnyParsedContent;
type: "stories" | "blog";
highlighttags?: string[];
}>();
const readingTime = calcReadingTime(post);
const descText =
type === "stories"
? `${readingTime.words.total} words`
: `${readingTime.minutes} min read`;
</script>
<template>
<div
class="break-words max-w-full rounded-lg p-4 shadow-md border border-2 border-gray-300 dark:border-gray-600"
>
<h3 class="m-0 flex items-center gap-1.5">
<a :href="`/tags/${type}/featured`" v-if="post.tags.includes('featured')">
<IconStar class="fill-yellow-500 outline-none" />
</a>
<a
:href="post._path"
class="no-underline text-left text-2xl sm:text-2xl font-bold hover:text-blue-700 dark:hover:text-blue-400 leading-tight transition"
>
{{ post.title }}
</a>
</h3>
<p class="my-1 text-sm"><Date :doc="post" /> · {{ descText }}</p>
<div class="flex flex-wrap">
<template v-for="(tag, index) in post.tags" :key="index">
<Tag
:dest="`/tags/${type}/${tag}`"
:name="tag"
:highlight="highlighttags?.includes(tag)"
v-if="!SpecialTags.includes(tag)"
/>
</template>
</div>
<ContentRenderer :value="post" :excerpt="true" tag="section">
<template #empty>No excerpt available.</template>
</ContentRenderer>
<div class="text-right" v-if="!post.nopreview">
<a
:href="post._path"
class="no-underline hover:underline font-semibold text-blue-700 dark:text-blue-400"
>
Continue reading
</a>
</div>
</div>
</template>

View File

@ -1,147 +0,0 @@
<script setup lang="ts">
import type { Project } from "@/data/projects";
import { unref as _unref } from "vue";
const { project } = defineProps<{
project: Project;
reverse?: boolean;
}>();
const imgUrl = project.img ? `url(/images/projects/${project.img})` : "none";
</script>
<template>
<a :href="project.href" class="no-underline project-anchor">
<div class="card flex items-center justify-between">
<div class="card-text h-full px-4 py-2">
<div class="h-full flex flex-col justify-between">
<div>
<h3 class="m-0 font-bold font-sans">{{ project.name }}</h3>
<div class="flex gap-1 items-center flex-nowrap">
<img
class="h-5 w-5 m-0"
:src="`/images/langs/${lang}.svg`"
v-for="(lang, index) in project.langs"
:key="index"
:alt="`${lang} logo`"
/>
<span
class="text-xs text-gray-500 dark:text-gray-300 whitespace-nowrap"
>· {{ project.license ?? "no license" }}</span
>
</div>
</div>
<div class="flex flex-col justify-between grow">
<p
class="desc-text text-gray-600 dark:text-gray-200 mt-3 mb-0 text-left text-sm"
>
{{ project.description }}
</p>
<p
class="desc-text text-gray-600 dark:text-gray-200 text-left text-sm m-0 whitespace-nowrap"
>
{{ project.longDescription }}
</p>
</div>
</div>
</div>
<div class="card-img h-full p-4 flex" :style="{ '--imgurl': imgUrl }" />
</div>
</a>
</template>
<style scoped>
.project-anchor {
display: inline-block;
width: 100%;
}
.project-anchor:hover h3 {
@apply text-blue-700 dark:text-blue-400;
}
.card {
border: 0.2rem solid pink;
background: white;
border-radius: 1.5rem 0 1.5rem 0;
height: 12rem;
line-height: 1.25;
transition: all 0.2s ease;
box-shadow: 0 0.1rem 0.5rem 0 gray;
}
html.dark .card {
border: 0.2rem solid rgb(126, 93, 98);
background: #444;
box-shadow: 0 0.1rem 0.5rem 0 black;
}
.card:hover,
.card:active {
transform: scale(1.03);
}
.card-text {
width: 25%;
background: white;
border-radius: 1.5rem 0 0 0;
transition: width 0.2s ease;
}
html.dark .card-text {
background: #444;
}
.card-img {
width: 75%;
background: var(--imgurl);
background-color: rgb(255, 237, 241);
background-position: right 90% top 15%;
background-size: cover;
background-repeat: no-repeat;
border-radius: 0 0 1.5rem 100%;
transition: width 0.2s ease;
}
html.dark .card-img {
background-color: rgb(180, 136, 143);
}
.desc-text {
width: 140%;
/* 140% is too close */
transition: width 0.2s ease;
}
a.unclickable {
pointer-events: none;
}
@media screen and (max-width: 720px) {
.card-text {
width: 30%;
}
.card-img {
width: 70%;
}
.desc-text {
width: 136%;
}
}
@media screen and (max-width: 540px) {
.card-text {
width: 45%;
}
.card-img {
width: 55%;
}
.desc-text {
width: 120%;
font-size: 0.72rem;
}
}
</style>

View File

@ -1,87 +0,0 @@
<script setup lang="ts">
const { img } = defineProps<{
name: string;
href: string;
img: string;
unclickable?: boolean;
broken?: boolean;
}>();
const imgUrl = `/images/services/${img}`;
</script>
<template>
<a
:href="unclickable ? '' : href"
:class="['no-underline', { unclickable: unclickable || broken, broken }]"
>
<div class="card flex flex-col items-center justify-around">
<img class="m-0" :src="imgUrl" :alt="`${name} logo`" />
<h3 class="m-0">{{ name }}</h3>
<p class="desc-text text-gray-600 dark:text-gray-200"><slot /></p>
</div>
</a>
</template>
<style scoped>
img {
width: 6rem;
}
.card {
padding: 1rem;
border: 0.2rem solid pink;
background: rgb(255, 237, 241);
border-radius: 0.5rem;
width: 12rem;
height: 12rem;
line-height: 1.25;
transition: all 0.2s ease;
box-shadow: 0 0.1rem 0.5rem 0 gray;
}
a.broken::before {
content: "PANQUIA IS ON FIRE";
position: absolute;
color: red;
transform: rotate(-40deg);
font-size: 1.5rem;
text-align: center;
z-index: 2;
top: 32.5%;
left: -8%;
width: 125%;
font-family: "Roboto", sans-serif;
font-weight: bold;
}
a.broken > .card {
filter: grayscale(100%);
opacity: 0.4;
}
html.dark .card {
border: 0.2rem solid rgb(126, 93, 98);
background: rgb(110, 90, 92);
box-shadow: 0 0.1rem 0.5rem 0 black;
}
.card:hover,
.card:active {
transform: scale(1.05);
}
.desc-text {
font-size: 0.8rem;
margin: 0;
text-align: center;
}
a.unclickable {
pointer-events: none;
}
a.unclickable .card {
box-shadow: none;
}
</style>

View File

@ -1,56 +0,0 @@
<script setup lang="ts">
import type { StoryParsedContent } from "@/shared/types";
import { calcReadingTime } from "@/shared/metadata";
const docs = await queryContent<StoryParsedContent>("/stories")
.sort({ date: 1 })
.where({ _draft: false })
.find();
const latest = docs.at(-1) as StoryParsedContent;
</script>
<template>
<div class="prose dark:prose-invert flex onhover">
<HomeStatBox
:href="latest._path"
color="lightgreen"
darkcolor="#2c8a2c"
title="Latest story"
>
<h2 class="m-0 mt-4 mb-1">{{ latest.title }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 m-0">
<Date :doc="latest" /> · {{ calcReadingTime(latest).words.total }} words
</p>
<div class="tag-list mt-1">
<Tag
v-for="(tag, index) in latest.tags"
:key="index"
:dest="`/tags/stories/${tag}`"
:name="tag"
/>
</div>
<ContentRenderer
tag="article"
:value="latest"
:excerpt="true"
class="text-gray-600 dark:text-gray-300 text-base m-0 mt-5 text-ellipsis"
>
<ContentRendererMarkdown :value="latest" :excerpt="true" />
<template #empty>
<p>No description found.</p>
</template>
</ContentRenderer>
</HomeStatBox>
</div>
</template>
<style scoped>
h2 {
overflow-wrap: break-word;
}
div.onhover:hover h2 {
@apply text-blue-700 dark:text-blue-400;
}
</style>

View File

@ -1,26 +0,0 @@
<script setup lang="ts">
const { highlight } = defineProps<{
name: string;
dest: string;
highlight?: boolean;
}>();
// const isLinkableTag = !props.name.includes(" ");
const isLinkableTag = true;
const tagClass = [
"inline-block text-xs rounded-lg py-1 px-2 mt-1 mr-1 transition border border-pink-200 dark:border-pink-900 border-2 font-medium no-underline",
{ "bg-pink-200 dark:bg-pink-900": highlight },
{ "shadow-md": isLinkableTag },
];
</script>
<template>
<div :class="tagClass">
<a :href="dest" v-if="isLinkableTag">
{{ name }}
</a>
<div v-else>
{{ name }}
</div>
</div>
</template>

View File

@ -1,15 +0,0 @@
<script setup lang="ts">
const { src, alt = "" } = defineProps<{ src: string; alt?: string }>();
const imgSrc =
src.startsWith("http://") || src.startsWith("https://")
? src
: `/images/posts/${src}`;
</script>
<template>
<figure class="flex flex-col items-center">
<img :src="imgSrc" class="drop-shadow-lg" :alt="alt" />
<figcaption class="text-center" v-if="alt">{{ alt }}</figcaption>
</figure>
</template>

View File

@ -1,89 +0,0 @@
<script setup lang="ts">
import { projects } from "@/data/projects";
</script>
<template>
<div class="prose dark:prose-invert w-full flex flex-col mt-9">
<h1 class="text-center mb-0">Fun things</h1>
<p class="text-center">(aka my programming projects)</p>
<div class="flex flex-col items-center justify-around gap-5 mt-6">
<ProjectCard
v-for="(proj, index) in projects"
:project="proj"
:key="index"
/>
</div>
<h1 id="about" class="text-center mb-4 mt-8">About</h1>
<!-- this could be in markdown but eh -->
<p>
Hello! It's very nice to meet you — I'm a student who is quite passionate
about some subjects but is quite lazy in every other.
</p>
<p>
I've dabbled extensively and non-extensively in a variety of topics to
play with, including:
</p>
<ul>
<li>competitive programming on DMOJ</li>
<li>Linux and server administration</li>
<li>web development</li>
<li>hackathons</li>
<li>ski instruction</li>
<li>writing of literature</li>
<li>video game console emulation</li>
</ul>
<p>and other things that I'm forgetting right now.</p>
<p>
I have three server machines at home a Dell OptiPlex 780, a Dell
Latitude E5520, and a custom-built PC. One of them is a laptop and
<s>I'm surprised it hasn't burnt up yet </s>
<span class="redphasis">it has burnt up.</span>
</p>
<h3>Custom PC ("hwaboon")</h3>
<ul>
<li><strong>CPU:</strong> AMD Ryzen 7700X (8c/16t)</li>
<li><strong>GPU:</strong> Integrated</li>
<li><strong>RAM:</strong> 2× 16 GB DDR5</li>
<li><strong>Storage:</strong> Crucial P3 1 TB SSD</li>
<li><strong>OS:</strong> Arch Linux</li>
</ul>
<h3>OptiPlex 780 ("asvyn")</h3>
<ul>
<li><strong>CPU:</strong> Intel Core 2 Duo E8400 (2c/2t)</li>
<li><strong>GPU:</strong> AMD ATI Radeon HD 3450</li>
<li><strong>RAM:</strong> 2× 2 GB DDR3</li>
<li><strong>Storage:</strong> Western Digital 150 GB hard drive</li>
<li><strong>OS:</strong> Arch Linux</li>
</ul>
<h3>Latitude E5520 ("panquia")</h3>
<ul>
<li><strong>CPU:</strong> Intel Core i5-3320M (2c/4t)</li>
<li><strong>GPU:</strong> Integrated</li>
<li><strong>RAM:</strong> 10 GB</li>
<li><strong>Storage:</strong> 300 GB hard drive</li>
<li><strong>OS:</strong> Arch Linux</li>
<li>
<strong>Status: </strong>
<span class="redphasis">ON FIRE.</span>
</li>
</ul>
</div>
</template>
<style scoped>
p {
margin: 0.5rem;
}
ul {
margin: 0;
line-height: 1.35;
}
.redphasis {
font-weight: bold;
color: red;
}
</style>

View File

@ -1,64 +0,0 @@
<template>
<div
class="container prose dark:prose-invert w-full flex flex-col items-center mt-9"
>
<h1 class="m-0">Services</h1>
<p class="prose dark:prose-invert">
This site is statically generated using
<a href="https://v3.nuxtjs.org">Nuxt.js</a> with the help of templates and
Markdown because really, writing HTML by hand is tedious and I don't
know why I ever tried and its
<a href="https://github.com/potatoeggy/public">source is available here</a
>.
</p>
<!-- i could make this a list but god i'm so tired with nuxt -->
<div class="flex justify-around flex-wrap gap-8 items-center">
<ServiceCard name="Gitea" href="https://git.eggworld.me" img="gitea.svg">
Self-hosted GitHub
</ServiceCard>
<ServiceCard
name="Eifueo"
href="https://eifueo.eggworld.me"
img="eifueo.svg"
>
Note collection
</ServiceCard>
<ServiceCard
name="Primoprod"
href="https://primoprod.eggworld.me"
img="primogem.webp"
>
Wish simulator
</ServiceCard>
<ServiceCard
name="Calibre"
href="https://calibre.eggworld.me"
img="calibre-web.webp"
>
Kobo Cloud
</ServiceCard>
<ServiceCard
name="Jellyfin"
href="https://jellyfin.eggworld.me"
img="jellyfin.svg"
>
FOSS media server
</ServiceCard>
<ServiceCard
name="Minecraft"
href="minecraft.eggworld.me"
img="minecraft.svg"
unclickable
broken
>
Whitelisted
</ServiceCard>
</div>
</div>
</template>
<style scoped>
.container {
max-width: unset;
}
</style>

View File

@ -1,13 +0,0 @@
/**
* Set the page title in the format [title] | [site name].
* @param title The title string.
*/
export function useTitle(title: string, description?: string) {
useHead({
title: `${title} | Oeufs?`,
meta: [
{ name: "viewport", content: " width=device-width,initial-scale=1" },
{ name: "description", content: description ?? "" },
],
});
}

View File

@ -1,52 +0,0 @@
---
title: "Stay Anonymous Online With These 4 Browser Extensions"
date: "2022-08-06"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/stay-anonymous-online-with-these-4-browser-extensions-f032c43f2bb)
It's a given that no matter what you do while browsing the web, Big Tech has their grubby fingers all over your data and tracks every site you visit, selling it to advertisers and other shady actors. Preventing this is almost impossible, short of something like Tor Browser behind a VPN in a virtual machine, which is slow and cumbersome.
<!-- more -->
If you're enamored with the convenience of major browsers, you can still increase your privacy by installing these well-known extensions for Chrome/Firefox, each tackling a different part of web security.
### 1. uBlock Origin
You might already know this extension as a popular ad blocker. However, it can do so much more — in addition to blocking ads, uBlock Origin [blocks trackers and malware sites](https://github.com/gorhill/uBlock) while being one of the lightest ad blockers out there to keep your sites snappy. By blocking trackers, you obviously reduce the amount of data that sites can collect, but by blocking ads, you also don't perform the *request* for the ad, so it's like the ad service doesn't even know you were ever there.
### 2. Decentraleyes
Whenever you connect to virtually any modern website, that website loads JavaScript libraries to make itself interactive, typically from content delivery networks (CDNs) such as Google, Microsoft, and Cloudflare. This, of course, isn't great, because that means that those CDNs know what site you're loading them from.
Enter Decentraleyes! This extension bundles quite a few common libraries so that whenever a site tries to grab it from a CDN, it loads it from Decentraleyes running locally on your computer instead. Privacy benefits aside, this also means that those sites load faster by not having to fetch more files from the web!
### 3. ClearURLs
Have you ever clicked through a bunch of links and ended up with the longest URL you've ever seen, all for a simple search query?
**A simple search for Wikipedia on Google:**
https://www.google.com/search?q=wikipedia&hl=en&ei=Ex7vYq-HI4KH0PEPpKus0Ac&ved=0ahUKEwjv3Lil0rP5AhWCAzQIHaQVC3oQ4dUDCA0&oq=wikipedia&gs_lcp=Cgdnd3Mtd2l6EAxKBAhBGABKBAhGGABQAFgAYABoAHABeACAAQCIAQCSAQCYAQA&sclient=gws-wiz
**A search for dog food on Amazon:**
https://www.amazon.com/s?k=dog+food&crid=2UT0FTXBL16XJ&sprefix=dog+foo%2Caps%2C182&ref=nb_sb_noss_2
All the nonsense after the ampersand (&) are used purely for tracking and won't be caught by content blockers like uBlock Origin because they're *in the initial request itself*. This data includes device and browser information, your search history, how you arrived at the site, and more.
ClearURLs offers a solution by simply removing all of the nonessential parts of a URL before sending it to Google or Amazon so that they never receive this information, securing a little bit more of your privacy.
### 4. NoScript
Lastly, the most intrusive forms of data collection are through JavaScript. So what if you just turned off JavaScript? You'd dramatically improve your browsing experience as sites load much faster, ads don't load at all, and none of the trackers can do a thing, but it could also result in broken sites that rely on it to function at all.
Therefore, if you truly care about privacy and want maximum control over what is allowed to load in your browser, you'll want to be able to selectively enable JavaScript per-script per website. NoScript is just the tool for this, with an easy-to-use interface that streamlines the troubleshooting process when sites require JavaScript.
------
You only need four extensions to dramatically reduce the data sites can collect on you from your browser. Although even these are no match for a properly tuned, custom solution like [LibreWolf](https://librewolf.net/), they provide an excellent first step into becoming more privacy-aware and in securing your data.

View File

@ -1,48 +0,0 @@
---
title: "AV1 — The FOSS Video Codec"
date: 2022-11-13
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/av1-the-foss-video-codec-1761ad9b0a4a)
More than 60% of all internet traffic is video — YouTube and Netflix are 20% alone! In fact, during COVID, so many people started to watch so much video that that number climbed up to 25%, even as they reduced the quality and size of the videos they served.
This much traffic costs lots of money for internet service providers, who carry on this cost to the streaming service.
And so, media companies, including YouTube and Netflix, have banded together as the Alliance of Open Media (AOM) to develop a video format to reduce the file size of videos: AV1!
<!-- more -->
## How did they shrink video?
Digital video today is represented as a collection of many still pictures known as “frames” that are shown to the viewer really quickly to create the *illusion* of motion.
Each individual frame contains thousands to *millions* of tiny squares called *pixels.*
However, at a typical 24 to 30 frames per second, youd have to store more than a *thousand* frames per minute! Uncompressed, a 1080p would need to stream nearly 50 million pixels per second, or 50 MB/s. You might see how this could grow expensive for both the streaming service and the consumer, *fast*.
So, someone figured out that, hey, we can compress pictures! Why dont we also compress video, too?
And thats exactly what we did — video *codecs* were created to provide a standard format to compress or “encode” video, providing large file size savings at the cost of more resources required to decode them upon playback.
For example, MPEG-2 in DVDs was able to use only 0.25 MB/s of bandwidth for 1080p video when pushed to its limits, though it was a pixelated, smeary mess.
## Why not use H.265?
H.265 is the successor to the ubiquitous H.264 codec that virtually every video player can process. Popularised on many physical media such as Blu-Rays, no browser is currently able to natively play back H.265-encoded content, for one very good reason: MPEG-LA, the organisation that designed it, charges royalties for each of its users.
Understandably, browsers dont want to have to pay millions of dollars recurringly just to play video, so its been stuck playing local media.
Why doesnt H.264 have this problem, you ask? [Cisco generously open sourced](https://en.wikipedia.org/wiki/OpenH264) their implementation of the codec and agreed to pay royalties to MPEG-LA, letting anyone legally use the codec for free.
## Support AV1!
In light of these problems, Google led the development of AV1 as a royalty-free, high quality alternative to H.265. All modern browsers today have already implemented AV1 playback, and hardware released within the last two years all support hardware decoding of AV1, meaning that the performance and power cost of supporting the codec has decreased drastically.
By supporting open standards, you can support a world where outdated royalty models no longer exist, and we can all benefit off of each others work.

View File

@ -1,172 +0,0 @@
---
title: "Etymology of Barin"
date: 2022-10-12
_draft: true
tags:
- barin
---
The [Barin](/tags/stories/barin) universe hosts a variety of different locations. The word "Barin" itself originates as an anagram of the word "brain".
<!-- more -->
## Preton
This major alliance
### Herdit
This nation
### Kora
This kingdom
### Ptuyo
This nation
## Farele
The Farelean Confederacy ("Farele")
### Ciers
This city-state
- Larapelio Avenue
- Nyread Tower
- SleepCity Ciers
- Orwell Library
- Bibliothèque de Lispector
### Leeco
This nation
- Universe City
- Cekendery
- Porter Hall
- Seascout Avenue
- Ira Hagey
- Brian Wright
### Demauge
This nation
- Ceseo Convention Centre
- Data Structure
- Stadio Avenue
- Deathfalcon Drive
- Triplesea Street
- French / FrenchScript
## Enigma
This alliance
### Xunil
This nation
### Weilam
This nation
- Saiyu Sphere
### Eos
This nation
- Emerald Forest
- Laveli Town
### Asvyn
This empire
- Favonius
- Shiganshina
- Kanokari
- Keion
- Shuchiin
- Musani
- Tonikawa
- Ruvinheigen
- Renge Academy
- Biyori
- Sayoasa
- Panquia
- Emina
- The Sinamaria Rose
- Dedication Road
- Kuvira Smith
## Other locations
### Aucervean Mountains
### Moyen Channel
### Ambera Connection (CiersEos)
### English Connection (CiersLeeco)
### Scrivener Connection (CiersXunil)
### Ezwon Connection (CiersDemauge)
### Arslash Connection (CiersHerdit)
## Characters
### Eifueo
### George Anstion
### Siava Pythone
### Minestro
### Nano and Rymo
### Rio Nohigi
### Cloche
### Garson
### Mrs. Lowshi
### Alston
### Brendan May
### Hina Asvyn
### Retadux
### Arro
### Calitea

View File

@ -1,54 +0,0 @@
---
title: "Choosing a License — Politics in FOSS"
date: "2022-09-02"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/choosing-a-license-politics-in-foss-df2cbfe48237)
All FOSS projects must have a license before other people can use them — but which should you choose, and what are the consequences behind each one?
<!-- more -->
## You need a license
Under the [Berne Convention](https://en.wikipedia.org/wiki/Berne_Convention) signed by the vast majority of countries in 1886, you own copyright to your software the moment you create it. Rights *exclusive to you* unless given otherwise include the right to copy and modify that software.
In a nutshell, it means that even if you submit your code to GitHub, *no one else* is allowed to copy or redistribute your code (e.g., via forking the repository).
Licenses work around this by granting specific permissions to other people *so long* as they follow the rules in the license.
Although there are many different types and variations of licenses, they can be broadly broken down into two categories: **copyleft** licenses and **permissive** licenses.
## Permissive licenses (e.g., MIT, BSD, Apache)
These licenses are pretty simple: they let anyone do virtually anything with them, so long as they credit you for using your code. This makes it easier for people to incorporate your code into theirs, but also raises the possibility that others, such as corporations, simply take your code without giving back.
Permissively licensed programs tend to be used more often by bigger projects due to the lack of restrictions.
The BSD operating system is a typical example of the dynamic of permissive licenses: Apple used BSD code as a basis for all of their operating systems (macOS, iOS, iPadOS, etc.), as well as Sony in their PlayStations, Nintendo in the Nintendo Switch, and much more. These corporations chose BSD because of how easy it is to take the code for free and build off of it.
## Copyleft licenses (e.g., GPL, MPL, CC-BY-SA)
If you really care about the ideology behind the free software movement, you might consider a copyleft license instead. These require all **derivative works** to have the same license that the original program had. They can still do whatever they want with your code, though.
For example, if library A held a copyleft license and application B bundled it in an app that they published, application B must also be compatible with that copyleft license or else they are in violation of library A's license.
…Which is a lot of words to say that copyleft licenses are "viral" in that they make everything they touch copyleft.
If you're a developer, this is really good for you, because it means that if a large corporation adapts your code to make it work for them and improves it, they have to share those improvements with you.
The Linux kernel is a great example of how copyleft has helped it grow to become the most-used operating system in the world. As devices adopt Linux (e.g., in Android phones), they are required to publish sources that make Linux compatible with their hardware, which is how the custom ROM community exists today!
Some corporations really hate copyleft because it forces them to open source their code, such as Google's [infamous policy on avoiding the AGPL](https://opensource.google/documentation/reference/using/agpl-policy/) like the plague. If that matters to you, you should use a more permissive license instead.
------
It's important to make sure that you are *allowed* to use a license in your project! After all, if you have a copyleft dependency, you can't license your program permissively. In addition, plenty of licenses are incompatible with one another, so you can't use both of them together.
In general, your program must be at least as copyleft as the most copyleft license in your dependency chain.
Although not a definitive guide, [https://choosealicense.com](https://choosealicense.com/) from GitHub is a great starting point to choose a license! So long as you're careful and check your dependencies' licenses, you'll be well on your way to contributing to the FOSS community!

View File

@ -1,77 +0,0 @@
---
title: "Git is a Blockchain"
date: "2022-10-02"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/git-is-a-blockchain-1060b53cea1f)
Git today is a beloved technology developers all around the world now use to track the history of a project through revisions. Obviously, it's not magic — if you look at the hidden files in a Git repository, you'll find a `.git` folder at least as big as the rest of your repo.
<!-- more -->
But for a technology that lets you revert the exact state of your files back any number of years, that `.git` folder is surprisingly small. You'd expect that any backup program worth its salt would actually back up each version of each file, but Git tracks *changes* to files instead of the actual files themselves, a method known as [delta encoding](https://en.wikipedia.org/wiki/Delta_encoding).
Not to mention all of the other features that Git piles on for practically no storage cost, such as branches, merges, cherry-picking, and more?
How does it do it, you ask?
Quantum Web3 decentralised machine learning VR blockchain agile AI cloud storage microservice architecture.
Only two out of the many buzzwords above are are actually used in Git, but Git was the decentralised blockchain before decentralised blockchains were cool.
But, I hear you cry, Git couldn't *possibly* be a blockchain! Blockchains are the stuff used in cryptocurrencies, scams, and other overhyped technologies!
In that case, why don't we compare the two? Let's start with the [Wikipedia definition of a blockchain:](https://en.wikipedia.org/wiki/Blockchain)
## A blockchain is a distributed ledger.
In simple terms, a blockchain isn't centralised, and a blockchain is copied across many computers, typically via peer-to-peer, such that each person with the data can verify that it's true.
…What do you know? That's exactly what Git does! Each Git repository is copied in its entirety by each person who clones it. When you push a commit, you send an update to another repo hosted somewhere else. When someone else pulls your commit, they *also* do it from a repo hosted somewhere else.
## A blockchain is decentralised.
At this point, Git servers have largely centralised into large services such as GitHub and GitLab, but that does not mean that the repository hosted there is the "true" one. Any contributor can overwrite the "centralised" version with their own local changes. In fact, there are lots of other server options out there from FOSS hosts such as Gitea, Codeberg, Sourcehut, and more. You can even host your own Git server!
Although Git *can* be centralised, the technology is inherently decentralised because it does not differentiate between servers — all of them are simple "remote"s.
## A blockchain consists of a growing list of records.
Transaction, meet commit. This one doesn't even need an explanation.
## Each record contains a cryptographic hash of the previous hash!
Hypothetically, right now, what if you run `git show` in your repository? Oh, hey! Is that a SHA-1 commit hash? Leading to the previous SHA-1 commit hash?? Who would've thunk it??? It's almost as if Git is a blockchain!!!!
```
commit ff25f8f352ed9e9f2fd07275ff136182a1711508
Author: NAME <EMAIL@EMAIL.COM>
Date: Tue Aug 16 22:45:12 2022 -0400
fix(api): add back imports
pylance keeps deleting them >:(
diff --git a/mandown/__init__.py b/mandown/__init__.py
index 4bba27f..9b12daa 100644
```
Each Git commit is hashed in a cryptographically secure* way that links back to the previous hash, which makes it so that you can't modify a previous hash without changing all of the hashes afterward.
This is literally what happens when you mess up a commit and try to revert it but the server yells at you due to mismatched histories because you messed up reverting it properly.
------
By every commonplace definition of the word, Git utilises a blockchain in its revision control system. It's at the heart of how each change can be uniquely tracked across systems.
A blockchain is nothing special. It's a technology you can use to avoid data tampering via communal tracking of transactions / commits. So, the next time you hear someone rambling on and on about blockchain and crypto, remember that it's just a tool as a means to an end, not some magical solution to everything.
------
*SHA-1 is no longer cryptographically secure, but Git has moved to a patched version that hasn't been cracked yet. SHA-256 support is also in the works.

View File

@ -1,52 +0,0 @@
---
title: "GitHub for Dummies"
date: "2022-06-17"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/github-for-dummies-1bb448962fc5)
Ever been linked to a GitHub page to download something and couldn't figure out what to click? This short, simple guide will help you get to wherever you need in 4 easy steps.
<!-- more -->
![What do all these words mean? Issues? Pull requests? Actions? Projects? Releases?](https://lh4.googleusercontent.com/u03FMDrVGVaU7x0ojxnNTAnM6_sPaSsnP1R6pZDJaTH95xqiH8LQKBN4OTZoU0Bigf6seLcCcDtSkuxcMwuLqLrCQH2fs6QsUZFyw58DN26sdbJcmMjXrhWjRQg6aoSzu-gBzib3gz20s0uFi_9h5k7QpgbohXqNkXw2pXPfPu4j3VibM_MNlHBK)
### The README and wiki
Always remember to first RTFM (Read The Fine Manual, with a slightly different word in place of "fine")! The README is always located on the home page of a repository, and it should contain a wealth of information for newcomers to familiarize themselves with the project. Installation instructions are often placed here if you scroll down far enough.
If that doesn't work, check out the project's wiki if they have one, located in the top navigation bar of the repository. Community members can also contribute to this page, so if you want to help the project and make it easier for newcomers, feel free to add or edit a page!
### Downloading releases
Now, if neither the README nor wiki have any hints to finding the link you want, you can go to the *Releases* section of the project, which on a desktop browser is in the right sidebar, while on mobile is located at the very bottom of the page.
![In this case, clicking one of the "primoprod" assets with the file extension for your device will get you a runnable program.](https://lh4.googleusercontent.com/v6G-c31NECe6ZJZhe2YSQXocQ4eCBJhYuXjNWSmECm5QQcSKaMWLpxe_roIkIonkMfUcDK4UtuqQEegVXCD1sAwHQnkssxOEk3uUrnQaMbhXL8zyeXdi0nUNv_QTKFsD5ZAUDJijHv_dc5wdTOEjggZipsIStM3vwaiabiNQ8XUY5bolApOupOwd)
Releases are the "official" way for projects to upload stable versions of their program to send to others. In the "Assets" section of a release, clicking the link that is not labeled "Source code" will get you a runnable version of the program.
### Downloading repository files
Let's say you don't want to download the whole program, but instead just a certain file *inside* the repository. What do you do?
Similar to Google Drive and other cloud storage platforms, you can click through different folders and eventually on files. Although you can't download folders, you *can* download individual files by clicking on them and then clicking "Raw" or "View Raw".
If that doesn't work, right-click the page that clicking "Raw" or "View Raw" opened and press "Save Page As".
### Filing issues
Trouble in paradise? If none of the above options worked, you can always file a new issue in the "Issues" tab of the project, where you can report bugs and ask questions directly to the project owner.
![](https://lh6.googleusercontent.com/l7mlo6OTPsAi17WcYgLeZ39aVp65D_24Kz4PMYOgKArwxJcz4jRcTCtud9UtChEUiUdnVR8sR7_6TvQJAAL2mFcKecLK-hhPvr7De_tPqrvh_mbaNCfVisD2yBn2icaXSl0eFDD4cIHKOzPKOM--2hruiM6qHkC6foW-6Pu63pU9c6FZOid10WXN)
Remember to read the project's issue guidelines, as some of them have a dedicated support forum or Discord to send help requests to.
### Contribute to FOSS!
For those just trying to get a file and dip, GitHub's interface is certainly more complex than it needs to be. The many buttons to streamline developers' experiences often get in the way of a user just trying to download the program.
As a developer, though, GitHub's many features are powerful and make development faster and more organised. If you ever decide to contribute to the FOSS community, return to GitHub and try to learn about the many other tools available to you!

View File

@ -1,56 +0,0 @@
---
title: "Google's Guide to Taking Over the Web"
date: "2022-07-16"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/googles-guide-to-taking-over-the-web-26847a389ac5)
Do you have a dream? A dream where you call the shots for billions of other people and how they communicate with each other? Well, we've got the guide of the decade for you, taken straight from personal experience. In just four easy steps, you'll be able to corner the tech industry yourself!
<!-- more -->
## 1. Bribe your competitors.
This first step is the most important. Without getting your name out there, you don't have the influence needed for web domination. Take out a small loan if you have to. We've bought out Mozilla for $450 million and Apple for $15 billion so that we're the default search engine in Firefox and Safari. Why would our users ever bother to change the default — to something like *Bing*, no less — when ours is good enough?
You gotta get your customers to associate you with the web, and you know you've got that when your company name is added to the English dictionary. What's the first thing you do whenever you want to look something up? You Google it. And the simplest, easiest, lowest-effort way to do this is by bribing your competitors.
## 2. Create a browser.
Make it simple. Make it fast. Make it such that people actually want to use it. Creating your own browser lets you into a whole bunch of important standards organizations, including Ecma and ISO, but most importantly, the W3C.
Now that everyone is using your search engine, you can abuse your near-monopoly there to tell everyone to use your new browser.
"A better way to surf the web."
And since you're Google, they trust you. After all, they get all your information from you, so why would you lie to them? Your users will all happily switch. And, if you've gotten creative, your newfound popularity might mean that your browser engine will be used *outside* of the browser in, say, a popular [server-side language](https://nodejs.org/en/), or even to [make desktop applications](https://www.electronjs.org/)!
All giving you more power over where the future of the web goes.
## 3. Extend open standards.
Now that you have a secure foothold in guiding the future of the web and everyone loves your products, it's time to take the rest of the pages out of Microsoft's playbook: Embrace, Extend, and Extinguish. It's time to add new features. Ones that your users like! But make sure you leverage your own services to show just how important you are to the web. Make others *depend* on you.
For example, you could [send all traffic to news sites through your own servers](https://en.wikipedia.org/wiki/Accelerated_Mobile_Pages) and call it "speeding up page loads." Don't forget to pretty it up! Open source it, but *you're* the only one allowed to contribute to it. In your search engine — you know, the one that everyone relies on? — rank sites higher depending on if they use your service. That'll encourage them.
Also, this point is a great time to start hobbling your browser competitors. Lots of people are using your own browser now, but the other browsers are just as good and less people are switching. That's a problem. What can you do about that?
Hypothetically, of course, you could take another one of your services — one might even say one that is indispensable to the web — and make it [several times slower in other browsers](https://fossbytes.com/youtube-slow-mozilla-firefox-edge/) by using special code in your own browser. Now you've got users' attention. An essential service they use is slow in their browser! How convenient, then, that your browser just happens to fix all those problems!
Alternatively, if you happen to own an operating system that [powers 70% of all smartphones](https://gs.statcounter.com/os-market-share/mobile/worldwide), you can also put it in there, as only [10% of users change their default mobile browser](https://www.independent.co.uk/tech/google-alternatives-privacy-duckduckgo-search-engine-browser-chrome-eu-fine-a8455321.html)!
## 4. Make so many standards until no one can catch up.
If you've made it this far, you've got this in the bag. Just make the web experience "more complete" and "more streamlined!" Do what you've been doing in step 3 but make it impossible for any newcomers to do it securely and properly. Add a protocol for [USB access in the browser](https://en.wikipedia.org/wiki/WebUSB). Add a protocol for [Bluetooth in the browser](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API). Replace third-party cookies with your own specialized tracking mechanism. All in the name of security and privacy, of course.
There are so many "standard" features in Chrome that it is practically unsustainable to create a new browser engine properly. Opera gave up and switched to Chrome. *Microsoft* tried with Edge before they gave up and used Chrome's engine instead.
## 5. Profit!
That's it! No one can stop you now. You have a stranglehold on the web. Your browser / browser engine have [70% of browser share worldwide](https://gs.statcounter.com/os-market-share/mobile/worldwide). Even in China, where your whole ecosystem is practically banned, you have [more than 50% market share](https://gs.statcounter.com/browser-market-share/all/china). Developers optimize for you, further reducing the market share of other browsers as sites are now broken in other browsers.
You're done. You've taken over the web. There is nothing anyone can do…except switch to Firefox. But who's going to do that? Why would anyone sacrifice the convenience of Chrome just to reject anti-competitive behavior of one company?

View File

@ -1,553 +0,0 @@
---
title: "13 Tricks to Write Nicer Python"
date: "2022-08-21"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/13-tricks-to-write-nicer-python-d6c65897cd59)
Known as an easy-to-use and flexible programming language, Python nevertheless still has plenty of tricks you can use to make your code prettier and faster to write. No matter if youre new to Python or have years of experience, read more to find a tip for you!
<!-- more -->
## 1. F-strings
When printing out lots of text, you might find that you have to add lots of text together, which you might do by string concatenation:
```py
name = "John"
lastname = "Doe"
print("My name is " + name + " and my last name is " + lastname + ".")
```
As you can see, it gets quite long and cumbersome if the string is long enough and if youre adding enough strings. This is where **f-strings** come in to make the code readable and actually more performant! These special strings begin with the letter “f” immediately before the opening quote of a string, and any expression in curly braces will be evaluated.
```py
print(f"My name is {name} and my last name is {lastname}.")
```
Completely clear, right?
Thats not all they can do, either! F-strings also provide some ways to easily format the data by providing how you want the data to be displayed after a colon in the expression.
For example, you can limit the number of decimal places shown in a float to two decimal places…
```py
num = 123.456789
print(f"{num:.2f}")
```
…and even dates and times!
```py
from datetime import date
today = date(2022, 8, 21)
print(f"{today:%m/%d/%Y}")
```
Output:
```
08/21/2022
```
## 2. Using “if” to its maximum potential
Like any language, Python has its quirks with values that evaluate to `True` and `False` in if statements. Specifically, **only the following are False** and every other value is True.
- Zero (`0` and `0.0`)
- Empty containers, such as lists, tuples, dictionaries, sets, **and strings**
- `False`
- `None`
This means that actions like checking for empty containers can be drastically shortened from:
```py
array = []
if len(array) != 0:
print("something is in the list!")
```
to:
```py
array = []
if array:
print("something is in the list!")
```
## 3. List comprehensions
You can generate a new list very easily with an inline `for`.
```py
array = [i for i in range(10)]
print(array)
```
Output:
```py
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```
List comprehensions are just syntactic sugar for a regular for loop, so the above code is equivalent to:
```py
array = []
for i in range(10):
array.append(i)
print(array)
```
Theyre also useful for performing operations *on* the elements, much like `map` in other functional programming languages.
```py
array = [i for i in range(10)]
new_array = [i ** 2 for i in array]
print(new_array)
```
Output:
```py
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```
In addition, as an alternative to `filter`, you can only include specific elements by adding an `if` at the end:
```py
array = [i ** 2 for i in range(10) if i % 2 == 0]
print(array)
```
Output:
```py
[0, 4, 16, 36, 64]
```
This is equivalent to:
```py
array = []
for i in range(10):
if i % 2 == 0:
array.append(i ** 2)
print(array)
```
## 4. Slicing strings and arrays
Compared to more traditional languages that only allow array accesses `array[i]` for one element, Python lets you "slice" a list or any other sequence (like strings) by a colon between the two indexes.
```py
string = "hello world!"
array = [1, 2, 3, 4, 5, 6]
print(string[2:7])
print(array[:-2])
```
Output:
```
llo w
[1, 2, 3, 4]
```
## 5. Tuple expansion
Tuple expansion is one of Pythons most powerful features, allowing you to expand or assign multiple values in a single line.
```py
a, b = 1, 2
s1, s2 = "baguette", "tomato" + "cheese"
print(a, b)
print(s1, s2)
```
Output:
```
1 2
baguette tomatocheese
```
The code above effectively assigns a tuple `(a, b)` to another tuple `(1, 2)` and is equivalent to the code below:
```py
a = 1
b = 2
s1 = "baguette"
s2 = "tomato" + "cheese"
```
This can let you return multiple values from a function.
```py
def init():
return (5, 6)
a, b = init()
```
And its also really useful in swapping variables!
```py
a = 2
b = 4
# oops, assigned them wrong
b, a = a, b
```
Tuple expansion can even be used in for loops to iterate over tuples or dictionaries!
```py
items = {
"apple": "juice",
"orange": "pulp",
"banana": "smoothie",
"mango": "slushie"
}
for key, value in items.items():
print(key, value)
```
Output:
```
apple juice
banana smoothie
mango slushie
orange pulp
```
## 6. Shorter code with shortcircuiting
Imagine you want to assign a variable based on the value of another variable. You might do it this way:
```py
name = "John"
if name == "John":
last_name = "Doe"
else:
last_name = "Unknown"
```
But thats long, and `last_name` appears twice. You can have an inline if to do it in just one line:
```py
name = "John"
last_name = "Doe" if name == "John" else "Unknown"
```
Much nicer!
You also might be familiar with logical boolean operators and how theyre used in if statements.
```py
if password == "hunter2" and name == "Joe":
print("password accepted")
```
But you might not know some of their quirks or exactly how they work.
If you have two things opposite an `and`, for example `x and y`:
- If `x` evaluates to True, `y` is returned.
- If `x` evaluates to False, `x` is returned.
This might not seem that useful, but then look at `or` in `x or y`:
- If `x` evaluates to True, `x` is returned.
- If `x` evaluates to False, `y` is returned.
This might also not seem that useful until you learn that logical operators can also be used in assignments, where theyre most commonly used for fallback values.
```py
confirm = input("Accept the EULA? (Y/n) ") or "y"
```
Because `input` returns a string, if the user doesn't enter anything, it evaluates to False, so the value `"y"` is assigned to `confirm`.
## 7. Safer file handing with context managers
In most languages, when you write something to a file, its actually held in a buffer until you close it manually or automatically when the program ends.
In Python, you would run the following to write to a file:
```py
file = open("myfile.txt")
file.write("hello file")
file.close()
```
But thats a lot of lines, and you might forget to run `file.close()`, particularly in long programs with lots of stuff being written to the file.
Thats where **context managers** come in, abstracting the whole process and calling `file.close()` automagically:
```py
with open("myfile.txt") as file:
file.write("hello file")
```
## 8. Nicer iteration with zip() and enumerate()
Pythons for loop is commonly known in other programming languages as a for-each loop. This is great if you just want each item in an iterable, but sometimes you want the index too! Instead of having to resort to `range(len(array))`, instead you can use `enumerate()` and tuple expansion to easily get both the index of the element and the element itself:
```py
array = ["a", "b", "c", "d", "e"]
for i, c in enumerate(array):
print(i, c)
```
Output:
```
0 a
1 b
2 c
3 d
4 e
```
In a similar vein, if you have two arrays you want to process at the same time, you dont need to use `range(len(array))` when you have `zip()`, which will bundle the different iterators into one big one as big as the smallest iterable.
```py
ints = [1, 2, 3, 4]
strs = ("pomme", "poutine", "pinterest", "pear")
floats = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
for i, s, f in zip(ints, strs, floats):
print(i, s, f)
```
Output:
```
1 pomme 1.0
2 poutine 2.0
3 pinterest 3.0
4 pear 4.0
```
## 9. Nicer paths with pathlib
Python is a cross-platform language, and if theres one annoying difference between Windows and macOS / Linux, its that their path separators are different: Windows uses the backslash (`\`) while macOS and Linux use the forward slash (`/`), and attempting to access a path the wrong way will result in file not found.
So, in the olden days, you would have to string together a long string with `os.path.join` just to be safe:
```py
import os
path = os.path.join("folder", os.path.join("subfolder", "subsubfile.txt"))
```
Doesnt that look clunky?
Luckily, a “new” (read: years-old) [addition to the standard library](https://docs.python.org/3/library/pathlib.html) makes that *much* easier:
```py
from pathlib import Path
path = Path("folder") / "subfolder" / "subsubfile.txt"
```
It also includes a bunch of helper methods to check for things and navigate the filesystem tree just because Python loves making your life easier.
```py
from pathlib import Path
path = Path("folder")
if path.exists() and path.is_file():
print("yay!")
print(path.parent)
print(path.suffix)
if not path.exists():
path.mkdir() ### create the folder if it doesn't exist
```
## 10. Iterable unpacking
n competitive programming, often you have to print out space-separated results. This can be done by the mildly inconveniencing
```py
print(" ".join([1, 2, 3, 4]))
```
or heaven forbid, via iteration:
```py
for i in [1, 2, 3, 4]:
print(i, end=" ")
print()
```
which is where iterable unpacking comes in, and you can go straight to
```py
array = [1, 2, 3, 4]
print(*array)
```
The **unpacking operator** (the asterisk) basically gets rid of the container and throws all of the elements inside directly into the print function as parameters.
That means that the above line of code is equivalent to:
```py
print(1, 2, 3, 4)
```
which nicely prints out the integers separated by spaces with a newline at the end.
But wait, theres more! The unpacking operator is also commonly used in function definitions as a catch-all parameter for extra arguments, stuffing them into a list.
```py
def init(a, b, *args):
print(a, b)
print(args)
init(1, 2, "pomme", 4, 6.0)
```
Output:
```
1, 2
['pomme', 4, 6.0]
```
You can also use this in normal assignment to, say, only get the first and last elements of an array:
```py
first, *args, last = [1, 2, 3, 4, 5]
print(first)
print(args)
print(last)
```
Output:
```
1
[2, 3, 4]
5
```
## 11. Else outside of if
Everyone knows what if-else does. But did you know that Python also lets you use it after loops and exception blocks?
- In loops, `else` is run *only if* the loop did not `break`.
- In exception blocks, `else` is run *only if* there was no exception.
These are especially useful so you dont have to add an indicator variable yourself:
```py
for i in array:
if i.is_tomato():
print("found a tomato!")
break
else:
print("no tomato found :(")
```
…is equivalent to
```py
found_tomato = False
for i in array:
if i.is_tomato():
found_tomato = True
break
if found_tomato:
print("found a tomato!")
else:
print("non tomato found :(")
```
Similarly, in a try-except block:
```py
try:
number = int(input("Enter a number: "))
except ValueError:
print("That's not a number >:(")
else:
print("You know how to follow instructions! :D")
```
…which is equivalent to:
```py
is_number = True
try:
number = int(input("Enter a number: "))
except ValueError:
is_number = False
if is_number:
print("You know how to follow instructions! :D")
else:
print("That's not a number >:(")
```
## 12. Type hinting
When you use a library, your IDE often knows what types a function will accept so you dont have to guess.
These come from **type hints** in the code, which you can use in your own code, especially if there is a lot of reused code and its a long program.
A colon after a variable shows its type:
```py
a: int = 4
```
…while an arrow after a function shows its return value.
```py
def pow(x: int, y: int) -> int:
return x ** 2
def largest(array: list[int]) -> int:
return max(array)
```
In more complex programs, type hinting is especially useful as your IDE can provide autocomplete and better syntax highlighting as it knows the limits of your program, so if you accidentally assume the wrong type of an object, your IDE will complain and find the bug before it causes a runtime crash.
## 13. The walrus operator (:=)
Say youre doing something over and over again and checking for a condition until its true. You could do it in a while loop:
```py
import requests
r = requests.get("https://google.com")
while r.status_code != 200:
print(r.status_code)
time.sleep(1)
r = requests.get("https://google.com")
```
But the assignment is repeated twice!
Introducing the walrus operator, which assigns *and returns the assigned value* in the same statement, allowing for less repeated code and some pretty crazy one-liners:
```py
import requests
while (r := requests.get("https://google.com")).status_code != 200:
print(r.status_code)
time.sleep(1)
```
---
Although thirteen of them are covered here, there are endless ways to optimise your code so that its faster to read, write, and run. Python is a “batteries included” language — chances are that the way youre used to doing things in other languages have a shorter and more concise method in Python.
The most important tip I can give you is to check the standard library if you want to do something — from [image format recognition](https://docs.python.org/3/library/imghdr.html) to [config file management](https://docs.python.org/3/library/configparser.html) to [basic database operations](https://docs.python.org/3/library/sqlite3.html), the standard library is chock full of useful tools included over the years.

View File

@ -1,55 +0,0 @@
---
title: "Reviving Older Games Through Emulation"
date: "2022-05-22"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/reviving-older-games-through-emulation-ca4e9705700c)
Throughout the past few decades, video games have evolved from an art medium restricted solely to specialized consoles to one enjoyable on all sorts of platforms, including everyday devices such as PCs and phones, replayable for the years to come.
However, for all of the beloved games that *are* locked to consoles, what option do you have but to let them die out as discontinued second-hand consoles grow more and more expensive as they break down?
Introducing…emulation!
<!-- more -->
### TIL converting games to Australian birds will preserve them.
![(Wikipedia Commons, public domain)](https://upload.wikimedia.org/wikipedia/commons/9/9d/Emu_1_-_Tidbinbilla.jpg)
Though *emu* and *emulation* share three letters, the only other similarity they have is that large entities have tried and failed miserably to stamp them out in the past. Emulation is the process of one system (such as a phone or computer) imitating another one (such as a video game console) to run programs designed for that system. Emus will now forever ravage the Australian wilderness, and emulation has been ruled to be legal in at least the United States.
Today, almost every popular system with games in demand has an emulator developed for them that works to some extent, allowing people to take their *rightfully owned* games and play them long after the original system has been discontinued or play them with mods to enhance their experience such as by increasing resolution.
In a nutshell, this means that if the Nintendo DS you owned as a kid suddenly broke one day, you can back up your cartridges and play Pokémon Black on your phone or computer instead!
### Cool, how do I try it out?
Modern-day emulators are nearly all FOSS, allowing them to be ported to most desktop and even mobile operating systems. We recommend the emulators below for their respective systems for a variety of reasons, including user-friendliness, ease of use, performance, and accessibility.
| Platform | PC | Android |
| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Sony PlayStation 2 | [PCSX2](https://pcsx2.net/) | [AetherSX2](https://www.aethersx2.com/) |
| Nintendo GameCube / Wii | [Dolphin](https://dolphin-emu.org/) | [Dolphin](https://dolphin-emu.org/) |
| Nintendo DS | [melonDS](https://melonds.kuribo64.net/) / [DeSmuME](https://desmume.org/download/) | [DraStic](https://play.google.com/store/apps/details?id=com.dsemu.drastic&gl=US) / [melonDS](https://github.com/rafaelvcaetano/melonDS-android) |
| Sony PlayStation 3 | [RPCS3](https://rpcs3.net/) | None |
| Nintendo 3DS | [Citra](https://citra-emu.org/) | [Citra](https://citra-emu.org/) / [Mikage](https://mikage.app/) |
| Nintendo Switch | [yuzu](https://yuzu-emu.org/) / [Ryujinx](https://ryujinx.org/) | [Skyline](https://github.com/skyline-emu/skyline) (WIP) |
Do note that emulators, unlike typical games, are *much* heavier on the CPU compared to the GPU because of all the translation required for the emulator to "convert" the game from the console's "language" to that of your phone or PC.
You can find more details about each emulator and other options for different consoles on the [Emulation General Wiki](https://emulation.gametechwiki.com/index.php/Main_Page).
### I want to learn more!
From stories about games relying on undocumented behaviour to *game-breaking* bugs cancelled out only by *console-breaking* bugs, emulation is a fascinating topic well-deserving of your interest if you're at all interested in low-level systems.
Modern emulators usually perform high-level emulation (HLE), where they emulate the functions that the system OS provides, compared to emulating each transistor like some monstrously complex Minecraft redstone contraption. As you might guess, this approach sacrifices some accuracy for greater performance — it's like translating a book character by character instead of word by word.
For further reading, there are plenty of blogs run by emulators outlining their tales in overcoming tricky obstacles, and we here at the *Albatross* strongly recommend you go check them out! [Dolphin](https://dolphin-emu.org/blog/) (GameCube / Wii), [yuzu](https://yuzu-emu.org/entry/) (Switch), [Ryujinx](https://blog.ryujinx.org/) (Switch), and [RPCS3](https://rpcs3.net/blog/) (PS3) all attempt to post regular progress reports on their respective blogs, linked above.

View File

@ -1,34 +0,0 @@
---
title: "Appreciate Your Browser!"
date: "2022-09-18"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/appreciate-your-browser-82d36a81a696)
*Click.* Milliseconds after you press a link, your screen flashes white. Elements slowly load in as a page full of search results appears in front of your eyes. How does this magic work? How does your computer know exactly what to show you when you press a button on your mouse? Let's go on a journey through your system to see exactly what happens.
<!-- more -->
------
The instant your finger pushes past a physical barrier, a switch connects a circuit and electrons go speeding through a wire (or over the air if your mouse is wireless) to your computer.
The moment the central processing unit (CPU) of your computer receives the electrons, it propagates that signal up to your operating system as a **hardware interrupt**, pulling all the brakes on whatever it's currently doing to handle the signal.
Eventually, your browser realises it's been clicked on and starts the process to fetch the page you're looking for from the internet. Through the operating system, your browser sends a small packet of information to your router, asking it where exactly https://en.wikipedia.org is through its **domain name system** (DNS)!
Your router kindly asks several other routers, which in turn ask even more routers until it gets back to you with a "208.80.154.224"!
Armed with this **internet protocol** (IP) address, your browser then asks your router to connect to it, which it happily does, informing you when it returns that the server with that address does in fact exist and is alive.
Now it's finally time to connect to the server. Your browser extends a handshake to the server, hoping it will reciprocate. Because Wikipedia is a trustworthy site that knows social expectations, it will return the handshake, whispering a secret only it knows through the **Transport Layer Security** (TLS) protocol.
Assured of Wikipedia's trustworthiness, your browser whispers secrets back, telling Wikipedia the information you're looking for. Wikipedia nods knowingly, but because they have other people to meet, they tell you everything you could ever need to know about parakeets in less than a millisecond with the power of **gzip** (compression) — you just need some time to decipher it.
Finally satisfied, your browser arranges the data prettily so that it's easy for you to read and holds it out to you expectantly, waiting for your praise.
Unfortunately, you snatch it out of your browser's hands, berating it for being so slow as you skim only the opening paragraph before yelling at it to fetch more information from Wikipedia, this time about parrots.

View File

@ -1,9 +0,0 @@
---
title: "Politics of Barin"
date: 2022-10-24
_draft: true
tags:
- barin
---

View File

@ -1,102 +0,0 @@
---
title: "Rust Changes How You Think And Code"
date: 2022-11-27
_draft: true
tags:
- tech
- rust
- albatross
---
This article is [also published in *The FOSS Albatross.*](https://medium.com/the-foss-albatross/rust-changes-how-you-think-and-code-2b5ee4d8def2)
Rust is the hot new language on the block (as new as a language from 2006 can be) that boasts reliability and efficiency.
How does it do this? Well, Rust has something that no other language does — it guarantees memory and thread safety while maintaining the same high performance of C or C++, all the while having high level features such as pattern matching and functional programming!
<!-- more -->
Some languages come close: Go is known for being both fast to run and to write, but its garbage collector and xenophobia toward other languages adds overhead that means that it is not suited for a systems programming language.
In safe Rust, there is *no such thing* as undefined behaviour. Everything your code says it does will happen — segfaults and NullPointerExceptions are impossible.
For simpler issues, the rustc compiler tells you more or less exactly what went wrong, along with a helpful error code, a link for examples on how to fix the error code, and even a suggestion that applies directly to your current code, which more times than not immediately fixes the issue.
```rust
error: format argument must be a string literal
--> helloworld.rs:3:14
|
3 | println!(123);
| ^^^
|
help: you might be missing a string literal to format with
|
3 | println!("{}", 123);
|
error[E0384]: cannot assign twice to immutable variable `a`
--> helloworld.rs:3:5
|
2 | let a = 123;
| -
| |
| first assignment to `a`
| help: consider making this binding mutable: `mut a`
3 | a *= 2;
| ^^^^^^ cannot assign twice to immutable variable
```
Thanks, rustc!
In time, you come to stop thinking less about the edges in the language and focus more on implementing what you want to implement. Rust makes it so that you don't have to stop and ask yourself these questions every minute:
- What if this variable isn't initialised or defined?
- What if this variable is already used?
- What if I'm modifying a variable that isn't supposed to be modified?
- What if another thread changes this data while I'm reading it?
- Did I forget to handle an error?
- Did I forget to check the error?
So how does it do this?
## Immutability by default
There are debates on whether immutable or mutable objects are better. Well, Rust provides both — but you have to *explicitly* tell Rust that you want your variables to be mutable. For example, the second error message in this article shows that you need the `mut` keyword to let the compiler let you change variable values.
```rust
let mut a = 1;
```
This applies to everything: from references to function arguments. If a variable isn't passed as `mut`, it's not mutable, and there is nothing else you can do to get around that. This isn't like JavaScript's `const`, either — the internal variables of a struct also have to be declared mutable in order to overwrite them.
This added friction to mutability means that developers tend to prefer immutable objects when possible, so it's very clear when a variable can change!
## The borrow checker
Perhaps Rust's flagship feature, this is how Rust manages memory without the complexity of manual memory management or the overhead of a garbage collector. In a nutshell, each variable is given an owner, and they may only have one owner.
You can "borrow" the value if you want to do something with it but give it back to use later, but the typical pitfalls of pointers don't exist in Rust because *there are no pointers in Rust!* (At least, not safe Rust.)
Here's an example of what Rust prevents — if you operated on vector B, it would change C, so Rust's safety guarantees would not hold. That's why the compiler doesn't let you run this in the first place.
```rust
let a = vec![1, 2, 3];
let b = a;
let c = a;
2 | let a = vec![1, 2, 3];
| - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
3 | let b = a;
| - value moved here
4 | let c = a;
| ^ value used here after move
```
And it's here that you really have to appreciate how much information the compiler gives you. It:
- tells you where the value originated from
- tells you where the value was used
- and tells you where the value was used *again*, which is not allowed
## Conclusion
Though there is a rather steep learning curve from just *how much* there is to unlearn about the finnicky things you can do in more traditional languages, Rust is a language that lets the computer calculate if your program is correct, letting you think purely on how to solve your problems.

View File

@ -1,38 +0,0 @@
---
title: "What's Wayland? Linux's \"New\" Display Server"
date: 2022-12-11
_draft: true
tags:
- tech
- albatross
---
Wayland is the shiny next-generation display server protocol that finally lets the Linux desktop move away from the cludgy abomination that is X. Although it was initially released in 2008, it's only recently that it has matured enough to the point that Linux distributions have begun to default to it.
<!-- more -->
## History
Ever since 1984, the Linux desktop has used the X Window System in order to output contents to a display.
38 years later, it's still alive and kicking in most Linux computers with all of its outdated features, such as slow compositing, built-in easy keylogging, and a lot of overhead just in case you want to operate your computer over the internet! Even with piled on extension (xrandr) after extension (xrender) and extension (composite), all of the bloat accumulated over time to the point that most of the X.Org server team moved to work on Wayland. As of today, X.Org is in maintenance mode, with few contributions and even fewer contributors because of all of the legacy code and practices that have to be worked with.
And that's exactly why Wayland was created — to be a simple, modern, and fast display protocol that narrows its scope to focus entirely on displaying windows efficiently and securely. Secondary priorities such as remote desktop, screen sharing, and screen tearing were implemented much later on.
No longer can any window catch every keypress without asking the user! No longer does shutting down the compositor crash nearly every program! No longer can any application decide to take over your screen and wreak havoc because it's allowed to do *literally anything!* No longer is workaround after workaround needed to maintain a *research project* that was never meant to be globally deployed!
Not to mention that because Wayland was designed from the ground up, it supports modern display technologies that X simply isn't able to due to technical limitations, such as different variable refresh rates over different displays at different resolutions.
## Adoption
Both Firefox and Chromium natively support Wayland. The GTK+, Qt, Electron, and SDL toolkits do too, letting thousands of applications "just work" by updating their dependencies.
In fact, the biggest desktop environments already support Wayland and all of its benefits:
- GNOME and KDE Plasma both have great support and even default to it on some distros.
- [Sway](https://swaywm.org) is a drop-in replacement for the i3 window manager if you're into tiling WMs.
- The Steam Deck uses Wayland to contain and sandbox games in its Gamescope compositor.
In addition, even for legacy apps such as games that can never be updated to support Wayland, a built-in compatibility layer called XWayland is there to run X applications in their very own contained X server. Even so, limitations in XWayland prevent it from being a one-size-fits-all solution to every X application.
Regardless, Wayland is still the future! Development on X has more or less completely stopped, so unless a party is desperate for a feature and is willing to invest a lot of time and money into navigating around the clunkier parts of the X.Org codebase, Wayland is the only available option for the future.

View File

@ -1,120 +0,0 @@
---
title: "Why Use Web Frameworks?"
date: 2022-10-30
_draft: true
tags:
- tech
- albatross
---
This article is [also published in *The FOSS Albatross*](https://medium.com/the-foss-albatross/why-use-a-web-framework-e1bdf1a8c1cf).
You're a web developer and you need to make a website. How should you build one? Do you start writing static files right away to be served immediately, or do you start setting up a project environment?
<!-- more -->
First, do you decide to use a framework? They're all the rage these days.
By far the biggest advantage of a web framework is its ability to make things declarative. Imagine you want to make a to-do list. You might write code like this to be able to add a new todo:
```html
<script>
function newTodo() {
const divBox = document.createElement("div")
const input = document.createElement("input")
input.type = "checkbox"
const p = document.createElement("p")
p.appendChild(document.createTextNode("Untitled todo"))
divBox.appendChild(input)
divBox.appendChild(p)
document.getElementById("button-box").appendChild(divBox)
}
</script>
<div id="button-box">
<div>
<input type="checkbox" />
<p>Do chores</p>
</div>
<button onclick="newTodo">New to-do</button>
</div>
```
...but then how would you make the whole system interactive? How could you delete todos, edit todos, or mark them as completed? You'd have to bring a whole state system that updates the document just to manage a simple todo app!
Meanwhile, frameworks abstract a lot of the element creation away so that you can focus on just writing components and how they *should* behave, not how to implement their behaviour.
For example, in Vue.js, you could do something like this:
```vue
<script setup>
import { ref } from "vue";
const items = ref([
{ title: "Do chores", completed: false }
]);
function newButton() {
items.push({ title: "Untitled to-do", completed: false );
}
function deleteButton(index) {
items.splice(index, 1);
}
</script>
<template>
<div>
<div v-for="(item, i) in items" :key="i">
<input type="checkbox" @click="item.completed = !item.completed" />
<p>{{ item.title }}</p>
<button @click="deleteButton(i)">Delete</button>
</div>
<button @click="newButton()">New to-do</button>
</div>
</template>
```
This short snippet makes it clear to the developer exactly what's happening and does way more than the pure version above. Not only can it add new todos, it can delete them and check them off too! At the cost of learning just a little more syntax, you can make the framework do much of the heavy lifting for you.
In this example, you tell Vue that you want a `div` for every item in your array with a checkbox, paragraph, and button. Whenever you add or remove an item to that array, Vue is responsible for making sure that your website matches the updated array so you don't have to fiddle with the document.
## Components
Working on files with hundreds of lines is never fun. Since HTML can only be sent in one file, this means that complex client-side applications tend to have too many lines to properly read and understand if they don't use a framework.
Once again, frameworks come to the rescue! Most of them have a component model that lets you reuse a lot of code, making it easier to read.
For example, once again in Vue:
```vue
<template>
<div>
<p>Hello</p>
<p>This is going to be used a lot!</p>
</div>
</template>
```
```vue
<script setup>
import UsedALot from "UsedALot.vue";
</script>
<template>
<UsedALot />
<UsedALot />
<UsedALot />
</template>
```
This splitting of logic makes it easier for your brain to focus on specific subchunks of code so it's easier to read and understand.
---
Web frameworks offer a lot of advantages over writing in a more imperative style. However, their abstractions do come at a cost — an extra minimum [16 KB](https://vuejs.org/about/faq.html#is-vue-lightweight) in JavaScript has to be fetched from your server, which can increase bandwidth costs and make your site slower.
Ultimately, in creating your website, much like when you do anything else, you should weigh the pros and cons of web frameworks before deciding to go with one or the other.

View File

@ -1,64 +0,0 @@
---
title: "Running Windows Apps on Mac and Linux"
date: "2022-10-16"
_draft: true
tags:
- tech
- albatross
---
This article is [also published in The FOSS Albatross.](https://medium.com/the-foss-albatross/running-windows-apps-on-mac-and-linux-c372996588af)
Windows is a beloved operating system with absolutely no flaws whatsoever. It is the pinnacle of engineering — sheer perfection in its design.
<!-- more -->
But say you like being objectively correct and actually think that Windows has its own problems, so you decide to switch to a Mac or to use Linux instead.
What happens to all of the programs you leave behind? Linux and macOS don't recognise .exe files as ones they can run, so you won't be able to run those incompatible with Linux without extra work. If you can find alternatives for all of them, that's great, but there still might be stragglers for beloved programs such as niche apps and games.
You could launch real Windows inside a virtual machine, which guarantees compatibility (except with certain anti-cheats), but tends to have a pretty big performance impact. If you're interested, check out [our article on running virtual machines](https://medium.com/the-foss-albatross/an-os-inside-an-os-how-to-run-virtual-machines-a3ddf6c8bbed)!
In this article, we'll be looking at Wine, a program that is practically magical by letting you run Windows apps natively on macOS or Linux!
## What is Wine?
Wine is a common alcoholic beverage —
Wine is a *compatibility layer* for Windows applications, translating Windows system calls into Mac or Linux ones.
Windows programs are actually quite similar to Linux and macOS programs. They all make calls to system APIs, and they all compile down to machine code. Because the different OSes run on the same x86_64 architecture (pre-Apple M1), there's no need to go through the expensive emulation of a whole other CPU like you see in game console emulators.
To be able to run the program, Wine hooks into the application and intercepts all of the calls it makes, passing it to its own reimplementation of the Windows filesystem and its various libraries or DLLs.
In fact, some of the APIs called are actually the same on all operating systems (such as OpenGL for graphics), so Wine can pass those through directly. In some cases, running an application through Wine can be even faster than on Windows!
Even if the APIs aren't exactly the same, Wine can still do a little bit of work to make them compatible. For example, plenty of work in making games run better has led to DirectX 12, 11, and 9 all translatable to the lower-level Vulkan, supported natively on Linux. On macOS, yet another translation layer takes the Vulkan output and turns it into the macOS-preferred API, Metal. Ironically, some games on Windows run *faster on Windows* if you run a DirectX-to-Vulkan translator! Combined with the general impression of a faster Linux, you can see how games can run *faster* under Wine than in Windows!
Wine's integration and familiarity with the host (Linux or macOS) means that it has some niceties that make it easier to use than a virtual machine, such as desktop integration! Shortcuts from installed Windows apps will appear on your desktop and in your launcher, and you can access all your files from within Wine. Pre-established shared Documents / Desktop / Videos / Music folders mean that getting started is super easy.
## Does it work?
Anyone who's tried to run a modern version of Office will be able to tell you that compatibility isn't perfect. Although Windows APIs are documented by Microsoft, many applications rely on undefined behaviour and quirks in Windows' implementation of those APIs, which Wine has to chase down and patch each time.
In addition, some anti-cheats fundamentally rely on the Windows kernel, and Wine's reimplementation isn't yet complete. Valve's work on the Steam Deck, which uses Wine extensively under the hood to run games on its Linux platform, has helped substantially in persuading developers to support Wine, but still many other games remain locked to Windows under the guise of fairness.
In general, howeve
r, you can expect many applications to at least start. Wine themselves [maintains a database](https://appdb.winehq.org/) of how well many applications run on their website. If it doesnt work—it was worth a shot, at least!
## How can I use it?
Wine is already in many Linux distributions' repositories, so installing it through your package manager should get you up and ready.
On macOS (pre-10.15), Wine can be installed using homebrew [as described on their website](https://wiki.winehq.org/MacOS).
Once Wine is installed, running a program is as easy as passing the path of the program you want to run into Wine:
```
wine path/to/program.exe
```
…or more commonly, you can just double-click the .exe file.
The decades spent on making the transition away from Windows easier have resulted in a marvel of a project capable of running proprietary software on a *different operating system* with a minimal performance cost. If it's helped you out, consider [getting involved](https://www.winehq.org/getinvolved) or [donating](https://www.winehq.org/donate)!

View File

@ -1,134 +0,0 @@
---
title: "Primoprod Progress Report 3"
date: 2023-12-29
tags:
- tech
- primoprod
- featured
---
Welcome back to another one of these development posts! It's been almost two years since [the last one](/blog/2022/primoprod-progress-report-2), so there are plenty of changes to talk about. Primoprod is more polished than ever, but a couple of questionable initial design decisions made it harder to work on than before.
<!-- more -->
## Pretty pretty pulls
There's a summary screen for 10-pulls now! It has that nice slide-in animation from the base game too, along with (largely) proper item alignment and a sorting algorithm that is not exactly like the base game's but works well enough to generalise outside of Genshin too.
The last step for this screen is to have the rush of particles in the base game for 4- and 5-star items, but that's incredibly difficult for someone not frontend-oriented like myself.
![(SPOILERS FOR FONTAINE'S ARCHON QUEST) Hydro Dragon acquired!](primoprod-10pull.webp)
Not only that, there are lots of small improvements to better mimick the base game! For example, weapons now have their weapon background behind them:
![What a beautiful sword.](primoprod-weapon-bgs.webp)
Banner headers are now dynamically generated instead of taken from screenshots, so now they can be nicely animated!
![No more screenshots >:(](primoprod-banner-headers.webp)
Version 3.0 of the base game brought a new book UI for the details and wish screens. I'm proud to announce that Primoprod was the very first simulator to incorporate it into its design!
![](primoprod-book.webp)
## Performance and prefetching
These are only a few of the design changes that make Primoprod a prettier and happier simulator. However, beauty means nothing if no one can see it. Luckily, update 1.2.2 of Primoprod brought some much-needed optimisations that make its web version much more palatable.
As of writing, Primoprod has around 75 MB of assets that it may need to show to users, the bulk of which is wish splash art. Previously, all of this was delivered as PNGs on demand, which resulted in noticeable lag waiting for the image when going through 10-pulls. By converting media to more modern formats, Primoprod gains nearly a *5x decrease in load times!*
Specifically, all PNGs were converted to WEBPs, MP4s to WEBMs (except for Safari, which doesn't support it), and MP3s to OGGs (except for Safari, which doesn't support it).
But that's not all! A 5x decrease in load time is still noticeable load time. The user doesn't want t to wait a few hundred milliseconds when they click the wish button, so we need as little latency as possible.
As it turns out, fetching the wish animation videos while the user is chilling on the main banner screen is both incredibly easy and incredibly rewarding — as long as the user doesn't wish right away, they can download the videos in the background so that when they start gambling, they don't have to wait at all!
Primoprod uses this same tactic to prefetch pull splash screens. Because rolls are determined the instant the user presses "Wish", it can prefetch the splash images required while the meteor animation plays, which means that splash screen animations are also instant! With a sufficiently fast internet connection (~1-2 MB/s), there ends up being *zero load time* for the user.
Of course, the downloadable versions of Primoprod (desktop/Android) will still always be faster, but this is such a noticeable decrease for users that it was a no-brainer.
## Quash the larvae before they hatch
### Oh, you sweet summer child
Things have changed a lot in the web development landscape since I began this project back in July 2021, and those changes have highlighted both the bad and the good in my initial designs.
I chose to use TypeScript and Vue 3, both decisions that hold up today. However, I opted for Vue's Options API over the new Composition API, which resulted in [a headache](https://github.com/potatoeggy/primoprod/pull/54) when I tried to read my old code — not helped at all by the fact that Primoprod was my first foray into web development, and there is some truly atrocious code:
```vue
<template>
<img
v-for="weapon in ['Bow', 'Catalyst', 'Claymore', 'Polearm', 'Sword']"
:key="weapon"
:src="getWeaponBgImage(weapon)"
:class="[
{
'active-bg-img': true,
nofilter: true,
'display-none': currentItem.element !== weapon || animationIndex < 0,
transparent: animationIndex <= 0,
'animate-weapon-bg': animationIndex === 1,
},
]"
/>
<img
:src="currentItemImage"
:class="{
'animate-image': animationIndex === 1,
'zoom-image': animationIndex === 0,
'active-img': true,
'active-img-weapon': currentItem.type === 'Weapon',
transparent: animationIndex < 0,
}"
:alt="currentItemImage"
@animationstart="playSfx"
@animationend="if (animationIndex < 2) nextAnimation();"
@load="nextAnimation"
/>
<!-- the reason why the double check is needed is
that the two animations for the drop shadow count
as two animations and trigger animationend twice -->
</template>
```
Another issue I didn't foresee but still ended up to be a real pain was Webpack. [Vite](https://vitejs.dev/) is the new kid on the block, built specifically for Vue, with the major advantage of being extremely fast. At Primoprod's scale — and Primoprod isn't even that big of a project — Webpack takes more than ten seconds to start the local dev server. Which is slow!
```
Done in 12.38s.
yarn build 57.47s user 9.66s system 535% cpu 12.528 total
```
### You will never take prop drilling away from me
Behind the scenes, a lot of systems have been tweaked and changed over the years as Primoprod grew in scope. [Pinia](https://pinia.vuejs.org/) is a global store for Vue (similar to Redux in React) that Primoprod now uses to hold information such as the current banner, inventory, and settings.
Previously, all of these were drilled deep into nested components, which is really not great.
What *you*, the user, gets out of this are a bunch of bug fixes and some really nice quality-of-life features:
![Why earn gems when you can just cheat?](primoprod-settings.webp)
Now you can choose to have infinite fates! And roll only Qiqi! And even go back to older banners, a long-overdue feature.
### Quests
Quests have been rather neglected since their release pre-1.0 a couple years ago, largely because I no longer use it to stay productive. Recently, they've received some love and a *lot* of patches to fix some really strange behaviour.
![](primoprod-quests-overhaul.webp)
First, there is a character limit in the title, and the box height has been slightly increased to allow multiline titles to properly overflow. Daily commissions now have icons to make it more obvious and also to copy the base game. Lastly, a bunch of bugs related to lists and quest ordering were squashed to avoid the janky horror that was pre-1.4 quests.
### For the mobile gamers in chat
Primoprod's mobile version has received the most love of all! Strangely, in WebKit-based engines (Chrome, Safari, Android WebView), using `background: fixed` with `transform: rotate(...)` causes the browser to ignore the `background-image` property. This broke mobile backgrounds on everything but Firefox Android, so that needed to be worked around.
On Android, things have tidied themselves up a bit as Primoprod comes ever closer to being able to fool the untrained eye. The notification bar used to annoy people by being ever present in the corner — now it's gone. There used to be a strange black flash right before playing videos — now that's gone. And video playback used to be very squashed on mobile — that's fixed too!
All in all, the squeaky platform got the grease.
## The future
As Primoprod approaches its two-and-a-half-year anniversary, it is slowly time to say goodbye. Updates have become more sporadic, and even I don't use it to be productive anymore. There is only so much one can polish something before it starts to blind them. This progress report may be its last.
But it was fun while it lasted!

View File

@ -1,53 +0,0 @@
---
title: "Sunsetting the Eifueo Project"
date: 2023-05-23
tags:
- eifueo
- retrospective
---
For three and a half years, the [Eifueo project](https://eifueo.eggworld.me) has dutifully carried out its task of collecting and organising notes in a way that would be quick and easy to review. Although this worked out wonderfully in high school, the method is both inefficient and insufficient for the pace of higher education.
So how can we make it better?
<!-- more -->
We can't.
At their core, engineering courses in university are about problem-solving. Instead of blindly memorising rules to be applied once to get you the answer, you blindly memorise rules to be applied *two or more times* to get you the answer.
If we have to do that, it's much easier to write plenty of practice problems instead of rewriting plenty of notes.
## It takes too loooooong
Reformatting notes is not an easy endeavour. We have to re-examine our old notes, research any ambiguities, and then write all of them up in a way that is clear, concise, and professional. On average, I'd say that it took a good hour or so per day to finish Eifueo for six courses. Imagine the number of practice problems I could finish if I allocated Eifueo's time slot to those instead!
## It's booooring
Me? A writer? Imagine.
This one isn't actually too bad, and doing practice problems instead isn't going to help much, but think of all the other fun things I could be doing instead. I already *have* the notes. If I need them, I'll just look back at them.
Anyway, by the end of Eifueo's lifespan, most of the content was regurgitated onto the site.
## It doesn't help nearly as much for exams
This is perhaps the biggest reason, and I have to say that I'm quite disappointed in the education system for this one.
High school had many courses that were "expression"-focused, and those were the courses that Eifueo excelled in. English, chemistry, and history all were less about getting the answer or precise process correct, and more about how well you can bullshit your way out of it. Even math was pretty easy to apply a shallow formula and get the right answer.
![We love nice TAs!](thanks-192-ta.webp)
Unfortunately, the physics courses are antithetical to everything Eifueo stands for. They have a rigid structure that you can't bullshit your way out of but are also flexible enough that you can't simply apply a formula. The best way to get good is simply to do more problems.
You'll have to understand that this greatly saddened me as a person who tries his hardest to do *less* problems. The cost-benefit ratio isn't worth it anymore.
## Retrospective
With a heavy heart, I must bid farewell to one of the first services I ever deployed to my server. Eifueo has tried its hardest to help me keep up, but I can only avoid doing practice for so much before it actually bites me in the butt.
o7 It has served me well.
![At this rate, I'm going to be an expert in perspective art!](assessment-art.webp)

View File

@ -1,81 +0,0 @@
---
title: The Dark Side
date: 2022-11-30
tags:
- nanowrimo
- u of t
---
**Content warning: Depictions of public bathrooms & potty humour.**
"They ran out of tofu!"
"What?" Yanfei whirls around in her chair, miserable dumpling forgotten. "But there was such a big tray out earlier!"
"People must have taken it all." Hu Tao shrugs. "That was fast. Maybe they'll have more later." A stomach gurgles, and she chuckles. "I guess I'll have to get something else — wait. That wasn't me."
"Bath…room…" Xingqiu's face is pale as he queasily stands, clutching his stomach. Without another word, he dashes off in the direction of the nearest restroom.
<!-- more -->
"Huh. He always had a sensitive stomach. I guess the fish did him dirty. Wait," Hu Tao pales, "*I* also had the fish…" Another stomach gurgles, and she bolts after Xingqiu.
"The chef must not have properly cooked it," Shinobu says. "Well, I'm pretty sure it's impossible to make rice give you food poisoning, and the fish was the only thing both of them ate."
Yanfei's stomach gurgles and she reflexively looks in the direction Hu Tao and Xingqiu hurried off to. She pales.
Shinobu snaps her fingers. "Oh, right. Also the tofu." She pats Yanfei's shoulder sympathetically. "Maybe you should catch up before it's too late. It'll come rushing out all at once."
------
Shinobu is a liar. It does not come rushing out all at once. Yanfei buries her face in her hands, butt planted firmly on the toilet seat as fluids intermittently fall into the toilet bowl. The yellow kind stopped falling long ago.
"Yanfei," Hu Tao croaks from the stall next to her. "The tofu got you too?" She flushes the toilet, but Yanfei knows that she won't be getting up anytime soon.
Yanfei empties her own bowl. It soon fills up again to accommodate the recent group of refugees from her body. "It's not the tofu," she insists weakly, squeezing her eyes shut. "It's *never* the tofu." Tofu wouldn't cause her physical pain to stand up. Tofu would embrace her and tell her everything's okay, that her stomach isn't the one cramping out and vomiting in the wrong direction, that the mouth on her other end isn't retching gravy and spitting all over the bowl of chocolate soup.
"I thought plants couldn't give you food poisoning!"
*It doesn't stop.* A river is flowing through her body. She imagines all of the microbes going whitewater rafting to exit her system. Only the water is neither white nor water. And the raft has spikes on the outside, as if designed to cause her the most suffering possible. She grits her teeth. "Hu Tao."
"Yeah?"
"Shut up."
"Gotcha."
Yanfei supposes she might be an avatar of sorts. Earth. Water. Air. The three elements lived together in harmony, expelling themselves one by one, until the Fire Nation attacked. Now there is nothing but pain and chaos. She wills it to stop.
Evidently she's still an avatar-in-training, because the elements don't obey her and continue to push past each other in a race to the finish line. Earth makes it first, but Air shoves right past it in a terrific blast of sound as Water tries to catch up.
The bathroom door opens. "Oh, *god* —" someone curses, and the bathroom door closes. She can't blame them.
Yanfei loses track of time. Has it been five minutes? Twenty? An hour? The occasional sound of ripping toilet paper and toilet flushes breaks the monotony of collective discharge. She's ascended to a higher plane, she feels. It's freeing — until her stomach brings her back to reality with a cheerful *mrrgle* as if taunting her.
"Yanfei?" Yanfei doesn't respond. "Do you have more toilet paper?"
There's a second roll inside the compartment, but she's already used up half of her current roll. "Yeah."
"Can you…pass it over?"
Struggling to concentrate in her fevered state, Yanfei manages to unclasp the toilet paper roll holder with some effort. "I…can't. Do you think you can —" she gasps as more of her temporary tenants evict themselves, "— get one from the next stall?" Where do they all come from? There never was this much space in the housing market in the first place.
"I can try." Hu Tao doesn't sound terribly enthused. "It…" she grunts, "it just doesn't stop…" A beat later, the stall door beside Yanfei's bursts open and she sees Hu Tao's shoes shuffle over awkwardly to the opposite stall. Her heart fills with dread when she hears a *drrbl* in the midst of Hu Tao fiddling with the toilet paper mechanism. "No, no, no —"
The stall door beside Yanfei *slams* shut and Hu Tao gasps with relief when she throws herself back in the stall. She can't even spare several seconds, Yanfei despairs. She's going to be trapped here forever. Here, in this dungeon, against a dragon inside of her that constantly feels the urge to breathe fire.
She hangs her head, resigning herself to her fate.
------
Hu Tao supports Yanfei after they wash their hands — thoroughly — and pulls them out of the women's bathroom. As they exit the bathroom together, Xingqiu stumbles out from the opposite door, eyes haunted. "I am never eating here ever again."
"Xingqiu," Hu Tao's eyes well up with tears as she embraces him. "*I understand*. You've been through *so much* alone."

View File

@ -1,92 +0,0 @@
---
title: "Emma the Narwhal"
date: 2024-12-02
tags:
- nanowrimo
- "monoceros (novel)"
- "emma the narwhal"
---
**Summary:** Emma the narwhal. April paused. For the first time in a long, long while, she saw it. In her mind's eye, she could see Emma's entire life, from her first narwhal date to her first beaching to her first narwhal war.
Holy shit. This was a *banger* of an idea. Who knew that a strange fish in a coffee shop would give her the laxatives she needed?
<!-- more -->
---
April almost made it four pages into Jane Austen's *Emma* before her mind wandered off back to Thailand where they had sessions to watch pineapples grow in real time that were more interesting than trying to follow Emma's ramblings.
She sighed, putting the book back on the shelf. If only Emma was like a narwhal, swimming in the skies, going on adventures to save the ocean from those toxic humans — maybe then it'd be a more interesting story.
Emma the narwhal. She paused. For the first time in a long, long while, she saw it. In her mind's eye, she could see Emma's entire life, from her first narwhal date to her first beaching to her first narwhal war.
Holy shit. This was a *banger* of an idea. Who knew that a strange fish in a coffee shop would give her the laxatives she needed?
---
*Emma sailed across the Herculean Sea, her tusk dipping in and out of the clouds flowing around her.*
No, that was too ambiguous.
*Emma the narwhal, freshly orphaned by the death of her parents in a tragic accident involving the betrayal of her best sky narwhal friend, moped around the Sea of Clouds.*
Too much fantasy. Also it spoiled the entire plot, and April couldn't have that, oh no, certainly not.
*Once upon a time, in a sky far far away...*
---
"It's only ten thousand gold," Emma insisted. "Come on, please?" She batted her eyelids this time.
"I'm sorry, miss," the bank teller said. "I can't make an exception for you, no matter who your mother is. Now, I must ask that you leave the premises." He lowered his tusk at them, marking the end of the discussion.
But Emma wasn't done with him yet, absolutely not. She had ten thousand gold in her bank account and she was not about to be swindled by some rainbow-headed narwhal with his head below the clouds.
Harriet nudged Emma's side before she could raise more objections. "It's not worth it, Emma. We'll find another way to get your treasure." She side-eyed the teller. "Mister Kingsley might know something."
Emma huffed, but followed Harriet back to their sky-cave. "What a dingus."
"I mean, you're four years old and definitely look it. But yeah. Fuck that guy."
---
And thus Emma and Harriet returned home to their sky caves, scheming under the faint rays of sun that seeped past the clouds around them.
"What are we looking for, Emma?" said Harriet.
Emma consulted the will once more. It was frustratingly unclear. What could "Chase the light that pierced the clouds" possibly mean? The sun was the only light she could imagine, and the sun went through every cloud.
Emma knew her parents had a fun sense of humour, but she thought they knew that there was a time and place. At least they could have told her what the reward was, just in case she didn't want to spend her teenage years chasing the gold at the end of the rainbow. She could stay in her cushy office job, pushing her cushy little buttons, and not risk a single thing. She was comfortable.
---
"I don't know who you are anymore," Emma whispered. "Harriet, how long did you hide this from me? From my parents?"
Harriet chortled, a strange, unnatural sound that Emma had never heard from her best friend before. "Oh, Emma, dear, did you really think *no one* knew about their will? Where there's a will, there's a way. For people to find out about the money."
---
"All of those years. Was it all for nothing? Was it ever real?" Emma said in a daze, floating without any real direction, letting the wind current take her as it pleased.
Harriet prodded her from behind. "Keep swimming. That's right, Emma. I never loved you one bit," she spat. "You should have listened to Lan. He was trying to warn you, you know." Her eyes glittered. "But you never listened. Pushed him away, even. He was protected when he was close to you. We couldn't touch him. But you...all I had to do was plant the smallest seed of doubt in your mind and you nurtured it, let it grow until it towered over any feelings you might have had for that boy," she crowed.
"What have I done?" Emma whispered.
---
The end of the journey was nearly here. Emma the narwhal had escaped her captor's grasp, betrayed and cast aside once she was no longer needed like her parents before her, and built her way back up in the underground. She was hardened. She was rugged. She wasn't the old Emma anymore. No, there was no light left for her in this world. The shadows of the criminal empire she'd created after overthrowing shark kingpin Jesse Pinkfong could not match the darkness in her heart.
She'd killed Harriet herself. She almost couldn't believe Emma had ever been captured by Harriet and her motley band of mercenaries. It had been downright easy to kill off every single one of them one by one.
The way Harriet had screamed, begged,* pleaded *with her when she'd had her brought before her had almost caused her to chuckle. She'd sawed off Harriet's tusk herself.
She had been at the peak of her revenge. Her enemies sortied, her power absolute, she was on top of the world. The earth bowed to her, her destiny manifest.
Yet no matter how high she rose, no matter how much influence she wielded — it could never bring the old Emma back. She had died when the hope had faded from her eyes long, long ago, and all that was left was a hollow monster puppeting her body. She was not Emma any longer. That name did not belong to her.
Although she was not Emma, perhaps she could fulfill some of the girl's dreams, in her honour. In memory of the narwhal who loved the world but the world did not love back, she would move heaven and earth for her.
She would bring to the narwhal race a new order. She would be christened…
Skyler, Monarch of the Sky Narwhals.

View File

@ -1,67 +0,0 @@
---
title: "Selected Excerpts from NaNoWriMo 2021"
date: 2024-09-23
tags:
- nanowrimo
- featured
---
You're lucky he hasn't spotted you, otherwise you might've had to talk to the man in the moustache. It's not that you're intimidated by his moustache, but adults — probably Mesa's father — are just hard to talk to. Especially if they have a glorious moustache like that. You rub the skin above your upper lip longingly. Only the tiniest of hairs there.
<!-- more -->
---
You nod politely in return, standing up straight to make use of your 162 (nearly 163) centimetres of height as best as possible.
---
How educated this man must be, to have such an open mind that he would even read the truth! And what courage to hide the forbidden book in such a copy!
Your respect for his moustache increases tenfold.
---
Chopsticks? Your eyes search for but fail to find a spoon, let alone a fork or knife. The two Baccaloreans in front of you are nomming away contentedly. Savan glances up first but returns to eating, your acting skills easily passing off your ignorance of the useless and convoluted sticks as genuine admiration of the dish.
---
Of course something is wrong, you're going to make a fool of yourself by not knowing how to use two sticks to pick up food! What's the point of sticks over straight-up using your own hands? At least refined utensils like the spoon provide extra functionality that you weren't naturally born with. How is he picking up that rice with those things!
---
Both of their eyes are on you now as you reach for the chopsticks. You can't lose face now. The handbook on Baccalorean included a section on using chopsticks, but you've never had any practical experience with them. You check that you're picking up the right side — why are they also unidirectional — and clutch them with your left hand, then deftly moving them so that they become clamped between your right thumb and index finger.
Success!
---
Ah. You'd forgotten he was asking for your opinion for the salmon. As your eyes flick to the block, your mind runs through calculations in the fraction of a second it takes for them to get there. _The salmon block is too big to fit in your mouth. Your chopsticks wouldn't be able to grip a block of that size, anyway. There is no way you can orient the block or your chopsticks to change the above two facts._
It's impossible. You have only one option.
You subtly stare at Mesa's chopsticks as they squeeze around her salmon block, forcing it into two, then elegantly twist to surround the smaller chunk and raise it to her mouth. It may be a technique you will never master.
But it will be enough for the current situation. Your chopsticks descend once more to your plate, squeezing the salmon pip until it nearly bursts, several tiny pieces that you are certain you will not be able to recover falling to your plate. A small sacrifice for the greater good. The chopsticks raise once more, this time precariously balancing a mutilated piece of salmon between their tips.
And they slide perfectly into your mouth, securing your prize once and for all, thereby ending the chopstick saga forever.
---
You keep your praise minimal so as not to inflate Savan's ego and to keep him humble.
---
"A _benevolent_ dictatorship," Savan corrects you. "Our goddess has a moderating effect on society so that no one gets into really heated debates because she's the ultimate mediator. She prevents problems before they get worse. That's compared to Constu, where you guys break things halfway through and revert to normalcy."
"Nonsense. We call that 'agile' development. It's the fastest way of finding out which things stick and which don't. My teachers always said that taking risks is an important life skill to have. Your goddess never takes risks and so you guys are all stuck in your small little bubble of stagnation."
---
"Hey, kid!"
You keep walking. They must be talking about someone else. Not only are you _not_ a child, you're doing very well collecting strawberries and nothing anyone can say is going to change your mind.
"Kid standing up with the funky hair!"
You whirl around to face the perpetrator of the grave insult, sending your sharpest glare his way. _"Excuse me?"_ Your hair is immaculately styled, not _funky_.

View File

@ -1,227 +0,0 @@
---
title: "Selected Excerpts from NaNoWriMo 2022"
date: 2024-09-24
tags:
- nanowrimo
- featured
---
Ganyu frowns as she pulls out a black leather straitjacket out of one of Yanfei's boxes. "Hey, Yanfei?" She holds it out in front of her. "What's this for?"
Yanfei looks up from organising her hats on the shelf. "What do you mean? Obviously, you wear it…?" Her expression is puzzled.
There's a small pause before the reply. "Never mind…"
<!-- more -->
Xiao stifles a snort. "That's right, Ganyu. Use your imagination. What else could you possibly use it for?" The straitjacket flies toward his face. Chuckling, he catches it and tosses it back at Ganyu.
---
"Uh oh, Xiao. You might want to reconsider biting into Jolly Ranchers around Yanfei," she teases. "She'll roast you on a spit."
Yanfei laughs while pinning pictures to the board on her closet. "The gummies get stuck on your teeth\! But imagine chewing a hard — wait." Her eyes narrow as her expression suddenly stills. "You meant the soft ones, right?"
Xiao looks away and proceeds to hang up a Drake poster.
_"You meant the soft ones, right?"_
"It's like a nutcracker going off every few seconds," Ganyu supplies.
Yanfei stares at Xiao, who is decidedly not looking at her. "How have your teeth not fallen out?"
---
"Nope. University math is not real math. There are no numbers."
---
_"Pink team\!"_ The sudden shout startles them, and they turn to see a man in a pink rabbit suit holding a megaphone. Yanfei's jaw drops. She's amazed she missed him in the first place. The chatter in their team stops. "Give me your attention\! Excellent. Now," he says authoritatively, pacing back and forth, "during this orientation, I am responsible for you. You will not like me. But you will _learn_. And you will understand, freshmen, that I speak for the university. From now on, you will only speak when spoken to. _Is that clear?"_
---
The rabbit man's mouth twitches but makes no comment. "Now, we head to the opening presentation. Do not lose me, or you will be severely beaten."
---
Miko leans in, smirking. "Don't go around underestimating UTI, now," she winks. "You'll be in for quite a bit of pain if you do."
---
"With free food as motivation, who could lose?"
---
Yanfei blanches. "Uh…" She scooches back. "You do make…food."
"Does she?" Xingqiu mutters. Hu Tao chops him again. "Ow\!"
---
"Where. Are. The. Vegetables?" He shudders. "I only saw _boiled carrots_."
They all look down at their plates. "There's napa in my _gyoza_," Shinobu says.
"Tofu has beans." Yanfei offers. "Those are vegetables, right?"
"What's a vegetable?" Hu Tao asks innocently.
---
Yanfei empties her own bowl. It soon fills up again to accommodate the recent group of refugees from her body. "It's not the tofu," she insists weakly, squeezing her eyes shut. "It's _never_ the tofu." Tofu wouldn't cause her physical pain to stand up. Tofu would embrace her and tell her everything's okay, that her stomach isn't the one cramping out and vomiting in the wrong direction, that the mouth on her other end isn't retching gravy and spitting all over the bowl of chocolate soup.
---
It doesn't stop. A river is flowing through her body. She imagines all of the microbes going whitewater rafting to exit her system. Only the water is neither white nor water. And the raft has spikes on the outside, as if designed to cause her the most suffering possible.
---
She's ascended to a higher plane, she feels. It's freeing — until her stomach brings her back to reality with a cheerful _mrrgle_ as if taunting her.
---
"Why is there so much work\! I have. Three. Tests. Next. Monday."
"Yeah," Keqing nods. "It's always easiest the first two weeks." Ganyu elbows her. "Oh? I mean — it's really rough the first two weeks."
---
Ganyu chuckles, eyes unfocused. For some reason, Yanfei feels a sense of dread looming behind her — oh, that's just Xiao.
---
"That's too much, Keqing."
"Ganyu, I need it\!" Keqing wails. "Are you really going to deny your girlfriend the only thing she truly loves?"
---
"Sorry, Yanfei. Kazuha's high again."
---
Sliding on her glasses, Ganyu reads the question aloud. "As _n_ approaches infinity, evaluate the limit of the *n*th root of the sine of pi over two _n_ times the sine of two pi over two _n_, all the way up to _n_ minus one pi over two _n_…" she murmurs. "Okay. What don't you get?"
---
"No, you messed up again here, I'm not sure how you got that. Five plus two isn't seven, it's… Oh. Wait, it is seven."
---
Xiao continues to watch television. "Yes. Yanfei helped. Your recipe is quite based — there's more left in the fridge for you."
Ganyu pauses. "Huh. Thanks. Nothing burned down, I hope?" She peeks around as if searching for scorch marks.
"No. Yanfei almost tried to grind the almonds with an egg beater though. That was cringe and unbased."
A few seconds pass in silence. Xiao looks up. "Ganyu?"
Ganyu stares at him with an expression of unbridled horror. "W-what happened to you?"
"Is there something that is sus? Yanfei taught me some common slang used by university students. That was very poggers of her."
A quiet _thump_ resounds as Ganyu sits down heavily on the nearest chair she can drag over. Eyes unfocused, she gazes into empty space. "No — just —" She abruptly gets up. "I'm going to talk to Yanfei."
"Kek-double-U," Xiao states.
---
"Good decision," Yanfei nodded. "If you don't overflow on CRIT Rate, it's your best-in-slot in freeze teams. Second BiS in melt, too."
---
Evidently, the fish did not want to be a new member of Yanfei's family and splashed out of the chest right onto her face.
---
Yanfei nodded agreeably. "Yeah, Magikarp kinda sucks. The only thing it does is splash around. Magikarp," she declared, "you have disappointed me for the last time. By the power invested in me by myself, I sentence you…to exile\!"
---
She shudders, imagining the explosion in her gut if she had to live off of dorm food. Then the state of the communal bathrooms for everyone who has to live off of dorm food.
Nope. She's _very_ glad to be living off-campus, actually.
---
She can only imagine the level of flex Hu Tao has by having the ability to hand out _bubble tea_ to people who come over.
---
Yanfei's fake moustache falls off from how long her jaw has been stuck to the table. She pushes up her sunglasses, rubbing her eyes as if she can't believe what she's seeing.
---
"I mean, I totally get why," Hu Tao says dreamily. "Yun Jin's a real piece of eye candy. I just want to _bite_ into her pompoms\! It's too bad she doesn't lean that way."
---
"Here in my apartment, we've just got this new blender, so don't mind Ganyu being vegetarian over there. But you know what I like a lot more than materialistic things?"
Yanfei points at the television. "Knowledge. And where else can you find more knowledge than in appreciating art?" She claps her hands. "So that's why we're gonna play Mario Kart\! I read in a book somewhere that competition nurtures the mind."
Hu Tao nods along like it all makes perfect sense. "So if I win, I get smarter?"
"Damn," Shinobu says. "We're all gonna be geniuses by the end of this. Except for Hu Tao."
---
He knows her much better — she wouldn't get him something mortifying like a _Link body pillow_. Ganyu's box is smaller than Yanfei's, which is a strong sign that it doesn't contain a Link body pillow.
---
"I noticed that your Pikachu pyjamas were starting to wear out. You must have had them for _years_ now. So I got you another pair\!"
---
"By the way," Yanfei says as Xiao takes his very first bite, "we knew you didn't want something too unhealthy for breakfast, so we tried out spinach as the main ingredient this time. What do you think?"
---
A girl and a boy sit in a Meet Fresh booth, its logo prominently displayed on the wall behind them. "Have a shaved ice," the girl whispers to the boy in the movie. "It's delicious. Made out of 100% fresh fruit. Just like me."
---
Yanfei averts her eyes until the subtitles stop saying \*\*SLURP SLURP SLURP\*\*.
---
"Then don't you want to eat me out?" the girl says huskily, caressing his cheek. "Like you eat out Meet Fresh's watermelon shaved ice, only available here for $9.99?"
"But isn't that expensive?" The girl gives him a look of utmost concern like he's just said that he's about to die.
"Our love is worth it," he reassures her. "Just like how the taro red bean soup is worth the $5.99 at Meet Fresh." He pulls out the dish from behind him. It looks overly bright and shiny, almost exactly like the picture in the menu. "Wouldn't you like to try one?" The boy takes a sip, then holds it up to the girl, who lovingly meets his gaze as she eats the rest of the spoonful. Both of them sigh with joy in unison.
---
Instead of the usual beach boy masquerade, today Xiao's hairdo looks like Morax decided to play cat's cradle with it but got bored before he finished.
---
"Welcome to the fourth meeting of the Debate Club. May we recognise that we are nothing but pawns to the great…Debate Club." She holds out a spiked metal bat to the skies.
---
"Objection\!" Yanfei buzzes. "Chewbacca override."
"Sustained. Sumeru, please be aware that the club formally forbade use of the Chewbacca Defense effective the 21st of November."
---
Yanfei spreads her arms. "Respectfully, Fontaine requests that the opposing counsel consider the implications of curves on pancakes. In reality, the inherent lack of structure _inside_ the pancake must lead to highly undesirable flopping, just like Mondstadt's tiny pp when he sees one\!"
Chongyun slaps the table, standing up and pointing at Yanfei. "Objection\! Inadmissible evidence\! The counsel from Fontaine…has highly exaggerated the size…of my colleague's…" Xingqiu practically drags him back down beside him, mildly red.
---
"It's okay. It's not actually losing if you lose against Numeron."
---
"They are. For this question, you're supposed to apply IBP twice. See how you can rearrange it with _u_\-substitution to make negative _x_ squared with _e_ to the negative _x_? That leaves you with another integral of negative _e_ to the negative _x_ by two _x · dx_. Then by doing IBP again, you end up with this negative _e_ and a quadratic."
---
"Is this really life, though? Dogs chasing their tails in circles over and over again?"
Yanfei nods firmly. "It is the very pinnacle of life. The epitome of all we strive for."

View File

@ -1,367 +0,0 @@
---
title: "Selected Excerpts from NaNoWriMo 2023"
date: 2024-09-25
tags:
- nanowrimo
- featured
---
My, little Peony must have such pain in his heart to so coldly shrug off an earnest request. Perhaps he suffered from childhood trauma in which his family was brutally murdered and thus he was forced to be independent, grew up much too fast, and now his heart is locked away, waiting for someone with a kind heart to bring him back to the world. But I digress.
<!-- more -->
---
A rather melancholic tune, if I do say so myself. If I were forced to speculate, I might say that he suffered through a traumatic in his adolescent years that closed him from the outside world. A troubled soul, lost and alone, dreaming of the golden years of his past\! But I digress.
---
"Sialia, humans are fascinating characters. Oftentimes quite dim, but fascinating nonetheless. Simply because _you_ have the brain the size of an earthworm — don't chortle on me now — does not mean that my _dear, cherished_ grandson isn't intelligent enough to desire a broader perspective."
---
Don't give me that, young sir\! If your wings are sore already, you'll be stuck in Los Angeles for the winter\! And what sort of self-respecting bluebird would let themselves stay in _LA_? The place is for lazy, sheltered, never-had-to-work-a-single-day-in-their-life cocks, that's what it's for. I shan't let you do it, not while these old bones can still slap you out of the sky\!
---
Are you still sore? Yes? Stick a worm in it. Here. Some nutrition. _Properly_ prepared earthworm, not like that bland, processed feed I came back to last night. I had thought your mother would have properly taught you how to feed yourself.
---
Keep an eye on the blue car beast. Humans feed them stinky earth juice, and in return, they regurgitate the humans when the human feels like it's traveled far enough.
---
Observe. This is one of the many human education institutions. Humans are incredibly stupid, so unlike us bluebirds, in order to do anything, they have to attend years of classes simply to learn what they can and cannot eat. See? They can't even eat nuts. Truly, I pity the poor species.
---
If there is one appendage to admire from the humans, I must say it has to be their nose. Not only can they smell far better than we can, it's so expressive when they wrinkle it so.
---
What a wonderful girl. When she wants something, she takes it. Be like her when you grow up. She also understands what power she has, and makes full use of it. If you never show off your skills and abilities, you'll never attract a good mate. It's important that every single bird around you knows just how competent, how amazing, how fearsome you are. _Oh, David…_
---
What's a little bloodshed between friends?
---
My, the poor girl must be suffering from whiplash more than the time I slammed into a car's windshield\!
---
"No, I can't\! Every time I even _think_ about being nice to that girl, I want to sock her so hard that her head springs back to knock both of us out so we don't have to interact. Please, Brooke. Be my Pamela shield."
---
They call it The Spanking. When a student and a teacher hate each other very much,
---
Lady, if your eyebrow lifts any higher, it might grow wings and migrate to Vancouver with us.
---
When you grow up, dearest Archie, desire nothing but to survive, thrive, and bear children. You'll be happier that way.
---
What is this nonsense? If you can back up anything you say by beating other birds up, you're right. Who's going to tell you otherwise? This isn't the first time I've heard this argument from humans. No wonder they bicker so uselessly among themselves so often and never get anything done.
---
Mind your wings — best not to get lost in the scent of Subway, lest you become addicted. Your great-grandfather was once a renowned human-watcher, but he strayed too close, too many times, and was Subway-ridden for the rest of his life. Couldn't fly a quarter mile away before his wings would lock up and he fell out of the sky.
---
Hm. Perhaps there is a flaw in this human. I do not believe that I have ever seen so many crosses.
---
We do not poke fun at those unable to fly — we can only look down upon them, sympathise, and offer our condolences.
---
Get up, or I'll make you live in Los Angeles for a week\!
---
I was once an engineer, you know. I was present at the founding gathering of the International Engineering Society. _Delicious_ seeds. Truly some of the best food I've ever had.
---
So what if you've heard it three times? This is an important cultural milestone of our species' history\! You should listen to it at least ten times\!
---
Perhaps I chose a flawed human. I do not believe that they are supposed to sprint across the middle of the road quite like that. Or be struck by their car companions like that.
---
Personally, I must interject to say that carrots are an abomination. Along with potatoes. No fruit, and you have to pull them out of the ground to eat them. And what do you get for all that effort? A bloody chore of a food, that's what you get\! Disgusting, starchy, barely juicy things, those are. Humans are a truly a different breed, they are. I'll forgive the child just this once for this transgression.
Bah. Mind your tongue. Simply because you hold objectively incorrect opinions close to your heart does not mean that you can spout off such nonsense in front of civilised birds such as myself. Didn't your father tell you to respect your elders? Be grateful that I refrain from using strong language in front of underage birds.
---
One of the any churches in the world. Legend has it that some idiot human strapped himself to the cross and got killed.
---
No, Elizabeth, snap yourself out of it\! Remember the vomiting. Remember the vomiting. Yes. Ahh…
---
What kind of stupid, arrogant, _deranged_ bird would voluntarily come to _Los Angeles_?
Oh, my. Ahem. What I mean to ask was — what kind of strong, dashing, chiselled, courageous, alluring, scarred-backstory bird would voluntarily come to _Los Angeles?_
---
"Liz, I swear, the next chance I get, I am going to take the gleeful, probably cancerous prick growing out of your head and ram it up your —"
---
"I still cannot believe that you're here because you wanted to check out a hot bird."
I very explicitly _did not_ say that, Sialia. Stop putting words into my beak.
"Right. How did you put it? 'The most incredible bird you've seen in years. His physique, his manner, his scars'? I can't possibly imagine how that could be construed as something even remotely romantic. No, not at all."
Your harsh words wound me. Still so sarcastic.
"She calls me harsh\! Archie, who do you think is harsher? Me or your grandmother? It's okay if you say me. Liz is completely harmless."
What did you say? Are you calling me _old?_
"Aren't I?"
Why, Sialia, if I weren't so generous, I would have your head pinned to the ground under my claw until you begged for mercy.
"Aw, thanks\! I have to say — you have better lines this time. If you want to get this William Swainson —"
That's William _John_ Swainson to you.
"— this William _John_ Swainson — between your legs, you have to try a little harder than _that_."
I have _years_ of experience, Sialia. I'm not a fledgling anymore.
---
Don't be so picky, child. Eat it. You heard Sialia. She'll be very much heartbroken if you don't try it, you know? She'll fall over, bawling her eyes out to the world, body wracked with sobs at the sheer offense brought to her by one small bluebird named Archie. But I digress.
---
Ah, young love. The boy and the girl look so happy together. You know, child, that in my youth, I was _hounded_ by men for who they thought I was? It is wonderful to see that today's human youth have moved on past such frivolities. To my knowledge, it is still an ongoing issue with us. If the boy and the girl were bluebirds, they would treat every interaction like a transaction, until they realise that it isn't worth being so on guard to every single person around them and decide to love each other unconditionally.
---
I have seen humans gleefully _stab_ each other simply because of infatuation, just like bluebirds. Literally _every single_ couple in human society has major issues that prevent them from being a perfectly functional unit. Every single one.
---
Ice cream is another food that will kill you. No matter how much sugar you detect, it's poison\! All poison. Humans should be ashamed, leaving out bait for good, honest birds to consume. And it's not like they eat them either\! We simply die for nothing. How incredibly rude.
---
"It exists. Therefore it's wrong. And because you're defending it, it must be wrong. See how everything logically ties in together so neatly?"
"I'm gonna throw you off the hill."
"With your noodle arms? Fat chance."
"These noodle arms picked up your skinny ass once before, Jeremy."
What did I tell you, Sialia? They're already threatening violence. We just skip the discussion bit and go straight to the violencing. Another way how birds are significantly more efficient than humans.
---
Every human relationship ends up like this eventually. They argue back and forth with each other until one of them breaks.
"Archie, don't listen to your grandmother. She doesn't understand a bit of friendly ribbing. Banter, if you will."
_Banter?_ You call this _banter?_ No wonder you don't have a partner, Sialia. If you consider this "friendly ribbing", I shudder to imagine what you must consider verbal abuse.
"Have you listened to yourself recently?"
---
"Just one question. Did it hurt?"
"What do you mean, sir?"
"When you fell…"
"I didn't fall?" An important lesson to you, child. Although the girl has a blissfully unaware expression on her face, you must hone your instinct to realise that we are moments before disaster. Sialia, if you don't let me leave, I will hide ants in your nest.
"…from heaven."
I'm going to vomit. Let me vomit, Sialia. You can't tell me what to do. I don't care how much seed will pour out of my beak. I cannot spend one more minute listening to this sappy nonsense.
"Uh, it's a metaphor. It means you're beautiful. Are you an angel?"
"…No. Thank you. Will that be all?"
---
"Yeah, you'd like that, wouldn't you? You dirty, dirty freak."
"Yes, I'm your dirty, _dirty_ freak\! I want it so, so much."
"Now get on your knees. The handcuffs stay on. That's an _order_."
"Ha… Yes, yes, of course\!"
"Did I say you could talk back to me?"
See? Now _this_ is proper flirting. Mind the whip. At this range, it could clip your wing off. If I were a human, I'd marry this human right now and here\!
What are you two looking at me like that for?
---
"Sorry about that. You must be tired."
"Yeah."
"After running around my head all day."
No, _do not smile, girl,_ what is wrong with you. I have had it with this couple\!
"That was terrible and you should feel terrible."
"Aw… But you love me anyway. You smiled\!"
"I did and I hate it. But I love you anyway."
---
"Liz, sometimes I get the feeling that you're not listening to me."
Of course I do. When have I ever not acknowledged anything you've said?
"I mean, I feel like you never really consider it."
I consider everything from everyone at great length. I am always correct, after all. In order to be so correct, I must acquire any new information as fast as possible.
---
If I hear that _inane_ word one more time, I might have to commit bodily assault on one of the humans here. Thank you, child, I do not need the earplugs.
"Dude\! You're so based. It's so fire, bro\!"
---
"Rio, pass me the laptop\! To save the dragons, I've got to hack into the Nomekop mainframe and eliminate all traces of Aderyn before we land\!"
---
I can only imagine the people at the ends of those sticks, poking and jabbing him in all the most sensitive places to make him squeal.
What do you mean, _you'd love that?_
---
"Maybe I should get a new cardigan for myself. Just in time for spring. How about this purple-and-yellow polka dotted one?"
Gah\! My eyes\! The contrast is too great\! Yet I can't tear my eyes away. It is — it is _objectively_ offensive to the eyes.
"Gah\! My eyes\! That is the most _offensive_ cardigan I've ever seen. I didn't even know they could make them like that. You should get it."
"You think so? I think it'd be funny to stroll around in this. Change up the look a little."
"I agree\! You should totally buy it."
"Hang on, let me get someone else's opinion on it. Hold my stuff while I change?"
I see. She must remove her existing outer layer of clothes before putting on a new outer layer of clothes. Such a hassle that they even have a dedicated private room for it.
Oh my goodness. I cannot look at her. I think I might go blind. My eyes feel like they're flying into a glass sliding door over and over again. It's horrifying.
"Honestly? It's better than I thought. For some reason, it doesn't look nearly as offensive on you as it did alone. They won't run you out of the store for this or anything. I'm still going to pretend that I don't know you." Pardon me? Madam? Do you need to see an eye doctor? Perhaps acquire some glasses? Are we looking at the same shirt? Did your eyes perhaps lock themselves into place looking at her face and steadfastly ignoring every other part of the outfit for the sake of their sanity?
"Strange. Don't be a scaredy-cat, Shayla. I thought it was abominable. Come on. Excuse me? Hi." She's roped in a new poor woman. May Garuda have mercy on your eyes. "So sorry to bother you, but on a scale from one to ten, how offensive is this outfit?"
"One. No contest."
"One being least offensive."
"Yeah, still a one. I feel like I can barely see it. It's pretty hard to notice." Her eyes are locked onto Mira's face. No wonder it's difficult to notice. The sight is elicits such a visceral reaction that their eyes dedicate all of their power toward self-preservation.
Mira must not be able to see the full thing, so when she looks down at her cardigan and back up, she doesn't get the full effect.
"Huh. Thank you very much. Shayla, I think I want a third opinion. I think maybe both of you are gaslighting me or something."
"It's fine, Mira. How could we both be gaslighting you?"
"I don't think I saw either of you actually look at the cardigan. It kinda felt like you were staring directly in my eyes the whole time."
"No way."
"Let me find someone else who might have functioning eyes. Ah. Excuse me\!"
"Hello, yes? How may I help you — _good glory\!_ My _eyes,_ my _EYES\!_ Ma'am, I am so sorry, but my brain is restraining me from looking in your direction — it's the cardigan, I swear, not you personally."
I knew it\! Finally, my opinion validated. I was beginning to wonder if our superior inhuman eyesight was the only thing that let us recognise truly how ugly that cardigan was.
"Thank god\! I was about to believe my friend when she said that it looked fine. How could dull yellow polka dots work on a purple fabric?"
"Absolutely — wait. Was that from _here_?"
"You bet. Picked it up from the bunch of cardigans over there."
"Yeah, no. That is not okay, ma'am. Sorry, but — ahem. In my professional opinion, I would advise you remove that cardigan and let me take it to the incinerator."
Such a wise employee.
"I kinda wanna take it home, though. It gets really good reactions."
"Look, ma'am, if you want to take it home, I'm not going to stop you. But I hope you know what you're doing."
"Of _course_ I do. Right, Shayla? When have I ever not known what I was doing?"
"Shockingly, very few times."
"Exactly. So let's go check out. I still want to visit the market on Main Street going on this week\!"
---
It's a classic\! A man and a woman meet in a bar. She comes here looking for a drink and an escape from her reality, but instead, she finds a man who, although he seems aloof, is actually the mask in front of a troubled soul who, after a great shift in his life, is trying to get his life back together.
---
All of your problems are solved now that you've found a man\!
---
I have seen _worms_ inching faster than these two progressing their relationship.
---
Look at the development. The progression. At this rate, they might even get together before I die.
---
That sputter is reminiscent of the tractor that killed your Uncle Jordan.
---
Now, some mouth-to-mouth action — that's what we're here for. The way the human lips lock together…the way the heads move as one as hands scrabble for grip… Even an old bird such as I can tell how much passion there is in a good, long kiss\! If birds had lips, Marty would be blown away by how much love I'd make to him.
---
"Let me show you how to use a carving knife…"
I wish he would show her how to carve out a future for them together instead.
---
"Son, maybe the times are changing. And I respect that. But no matter what happens, never lose that fighting spirit. Can't fight the girls? Fine. There's still a good half of the population you can beat some sense into. Now, if they say that _fighting is bad_ and that _no one should do it_ or whatever? That's when you put your fist down and screw the rules. Let no one tell you what you can or can't do."
"I'll do my best, dad\!"
"I know you will, son. Make me proud. Nothing like a good fist to the noggin to help loosen any lips."
Wonderful parenting. _This_ I can get behind one hundred percent. I know I have a lot of negative things to say about humans, but in reality, they're so diverse that there are so many different viewpoints to learn from. There are some that are objectively wrong, some that are objectively right, and then most are in the middle. It's rather refreshing to have one's opinions validated every once in a while.

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
---
title: "ECE 192 Words per Minute"
date: 2024-02-29
tags:
- featured
- shorts
- university
---
**Summary:** A student is mildly frustrated by his professor's pace of speaking.
<!-- more -->
---
"Even if we use one million, or two million, or even three million pieces, the additional tooling cost will remain constant. So you can see that in order to make a good economic analysis, you have to classify the costs related to the output activities as follows…"
Lento slammed his pencil down as the professor *finally* stopped speaking. The soot streaks on his notebook smoked from his rapid scribbling, and his wrist shook from the sheer exertion of trying to take notes from a professor who read off slides that looked like someone tried to squeeze a novel onto them.
Judging by the fire alarm going off around them, he wasn't the only one who nearly combusted his notes.
"You know," Atras murmured from beside him, "online lectures sound like a really good idea right now." His notebook was closed, his pencil pristine. The signs of a man who gave up long ago. The signs of a smart man.
"I," Lento hissed, "cannot take this anymore."
"What is he even saying?" Atras said, calmer but still exasperated. "What's all this about costs and benefits and graphs?"
"Who *cares?* Why does this *matter?* Has this man *ever had to deliver a presentation before?* I *don't need this to pass my exam.*"
Atras patted his back, an understanding but exasperated expression on his face. "Calm down. It's not that bad. It's just a humanities course."
"I'm not seeing the humanity," Lento said grimly.
"It's the bird course. The easy course. The course you don't even have to take notes in. Why are you trying so hard, anyway?"
"Says the guy who isn't taking notes!"
Atras snorted. "The prof posted all of his slides online. Why *should* you take notes? I'd rather not develop carpal tunnel in the first week."
A clock *tick*ed and Lento glanced over to the clock. The professor starts talking again, the sound like a drill burrowing directly into Lento's ears as the added knowledge of *incompetence* makes the emotional damage all too clear.
"How is he still talking?" Lento's voice steadily rose in pitch. "What is there left to talk about? Why can't I go home? Why am I here? Just to *suffer??"*
"And that's it!" the professor said brightly. "You are now free to go. Tomorrow, we'll be looking at cost estimation models. There are practice problems on LEARN if you want to apply what we covered today."
A rush of cool wind blew from somewhere out the exit, even though that would make no logical sense whatsoever, but conveniently masked the students' collective sigh of relief.
Lento stood up, dumped his notebook and pencil straight into his backpack, and promptly dragged Atras out the lecture hall with him. "Out," he demanded. "We are out of here."
"For the last time?"
"Do you even need to ask?"
"I thought it was interesting," said Atras. "The professor sounded like he knew what he was talking about. He just covered things a bit fast, that's all. And kinda derailed sometimes."
"…And he went *on and on* ***and on and on*** <u>***and on and on*** <span class="text-xl">***and on and on***<span></u> to say the equivalent of a small glossary and four lines of notes, except you don't know what four lines you need so you write down all of them anyway."
"You're too bitter," Atras observed. He held out a red rectangle. "Want a KitKat?"
"…Yes." Lento snatched the candy out of his friend's hands and ripped the wrapper open. He chewed methodically on the chocolate.
"Feeling better?"
"A little," Lento admitted. "But still. I'm not going back to that class. "
"You should," Atras coaxed, holding out a Coffee Crisp. "You always learn things better when lectures can hold you accountable. Here, do you think you can talk about the course without hating on the professor for one second?"
"Who's gonna hold the professor accountable?" Lento grumbled. Atras gave him a look. "Yeah, yeah, I know. Fine. One more class. He has *one more chance."*
---
Addendum:
"If you have three horses, the magnetic flux through each horse actually approaches zero as we move farther and farther away. Combined with Gauss' law, given that we know that the flux density of each horse is, in an ideal world, equal to that of free space, this lets us cancel out the electric flux density factor on both sides here, which results in seven horses!"
The hissing sprinklers and wailing fire alarm do little to stop the madman from his lecture. Lento rests his head on his arm on his desk, his pencil having been vaporised long ago. "Surely this isn't on the exam. What kind of econ is this?"
"Be sure to remember this, because it'll be a major part of your midterm!"
Atras pats his head consolingly.

View File

@ -1,296 +0,0 @@
---
title: Glorious Pain
date: "2024-11-22"
tags:
- birdseye
- nanowrimo
- featured
---
**Summary:** Liz, Archie, Sialia, and William J. Swainson watch a human who insists that what doesn't kill you makes you stronger. And, well, who wouldn't want to be stronger?
<!-- more -->
---
Good morning to you, child, Sialia, Mr. Swainson. Shall we start the day?
"Why, but of course. Are you all prepared for human-watching? Have you everything you need?"
Of course. Let us travel across the skies of Winnipeg!
"Excellent. Please follow me. The Forks are rather busy this time of year. If I ever needed a quick human, the Forks were a fine place to find one."
What accessible architecture! The highs and tumbles all mesh together beautifully. A bird could hide or swoop around this area anywhere!
"Another reason why it is such a perfect location for birds. Look at those humans arguing over there. That's usually a good sign to find interesting people."
Let us listen in, then. What an angry woman, pulling her friend close to her like that. That other man might be getting a little too close to them for comfort.
"Get your hands off of him! How _dare_ you insult him like that? Do you know what he's been through?"
"Woah, dude. Take a chill pill. I didn't even touch your friend there. I just called him out for being rich. Y'know, got his whole life sorted out before the age of ten by his parents and all that. You don't gotta act like I slept with your mom last night."
"Um, Sera, it's okay. Isn't this a bit of an overreaction…?"
"No! Absolutely not, Leo. If anything, I can't believe that you aren't reacting more! How can you let him say that to you? You lived in poverty since you were three. You scrimped and saved and worked as hard as you could just so you could feed both yourself and your family while going to school. _You deserve nice things._ It's okay to want for things."
"Damn, man. I didn't know you had a backstory like that. Sorry, bro."
"Yeah, well, you should apologise! Don't judge people by how they look, loser."
"Come on, Sera. I'm sure he didn't mean any harm. People are staring. Let's just go."
"Hmph. You value yourself _way_ too little. This world is full of injustices. I just want to see you succeed, Leo."
I daresay that this might be the most interesting human yet, this _Sera_. A blunt and direct person, isn't she? Let us follow these two as they leave the malls.
"Seraphina!" A new girl.
"Oh, hey, Amara! You can totally call me Sera, you know that, right? What're you doing here? Oh, this is Leo, by the way. Leo, this is Amara. We've been friends since high school."
"Heya. Great to meet you!"
"Nice to meet you too, Leo. Seraphi — sorry, I mean, _Sera_, I was gonna go shopping with Phoebe today. Wanna join us?"
Out of all of the noses I've seen, Sera's nose is up there for most expressive. That wrinkling is remarkably clear, even to birds such as myself.
"Phoebe? Phoebe Sinclair?"
"…Yeah. Is something wrong with Phoebe?"
"Not at all." That sniff says otherwise. "She's perfectly fine the way she is. I just wish I understood how she got to where she is today."
"Huh. Okay. Well, maybe you'll get to talk to her at Ethan's birthday party today. You're going, right?" Birthday? Oh, we must follow this girl.
"Of course! Wouldn't miss it for anything."
"Cool, cool. Phoebe's been waiting for me at Zara for a while now, so I'm gonna dip. See you tonight?"
"Yeah, for sure. Bye!"
"Nice meeting ya."
Child, this is a once-in-a-year opportunity! Humans' birthdays are incredibly significant to them, and the particularly interesting ones make a big fuss out of it and throw a party. You're incredibly lucky to see something so special at your age.
Mr. Swainson, please don't raise his ego. Garuda knows it's flying too close to the sun already. The humble bird gets the worm, as they say.
---
One more piece of advice to you, child: You can easily tell if a house contains a lot of humans by looking at the number of cars in the driveway. Usually, those with more guests have more cars, as the cars refuse to leave without their owners. From there, you can use the information in a variety of different ways. You could track the humans entering and leaving the home based on what cars they take and how many humans each car holds. You could also link the cars to the home and build a network of humans. The possibilities are endless!
In this case, we can use the information to easily verify that this is indeed the correct house. The richer humans with the larger houses are particularly nice because they usually have at least one open window somewhere that is suitable for human-watching. Additionally, the density of humans in the house is lower, so your chances of getting caught are much lower.
For now, let us find a nice open window to eavesdrop from. Oh! Actually, we can approach the window later. A new car is pulling up to the house!
"Hey Ethan — happy birthday! And Sera! When was the last time I saw you guys?"
"Phoebe! C'mere. Oh my god, it's been way too long. Love the necklace, by the way."
"Thanks! My mom helped pick it out for me last week."
"Hmph."
"Hm? Sera?"
"Nothing. Don't mind me. Why don't you come in?"
It's going to be difficult to squeeze by them. Shall we head to the window to continue their conversation?
"…and then I told my mom, so she was like, 'Do you need a new one?' And of _course_ I'm not gonna say no to a new phone, right? Sera, is something wrong? You've been kinda smug this whole time. I know that we've had our disagreements sometimes, but _surely_ you're over it now?"
"Oh, but of course. How could our _little princess_ here be troubled? _Everything_ must end up perfectly for her. Oh, the horror? How could you possibly be bothered by something as trivial as _disagreements?_ 'No,' she says, 'look at me! I'm so perfect and smart and pretty and I have so many friends!' Even though you haven't done a single _damn_ thing to deserve it. Acting so high and mighty like that — it disgusts me."
"What are you on about? Did I do something to you?"
" _'Did I do something to you,'_ she asks. More like what you _didn't_ do. _You're_ probably just here because you're Amara's friend. Honestly, I don't know what she sees in you. Have you ever been grateful for anything or worked a _single_ day of hard work in your entire life?"
"Hey! Don't mock me. Look, I don't know what your problem is, but this is getting out of hand."
_"My_ problem is that _you_ don't realise just how good you've got it while you brag about all of the _nice things_ you have to other people. Actually _good_ other people, unlike you. See Amara here? She _chooses_ to be kind even though she's experienced first-hand how cruel the world is. She lost the bright, innocent spark in the eyes of her childhood when her parents died, when _no one_ wanted to help her, and when her closest friend betrayed her. Yet _still —_ still she has ten times the heart that you do."
"Sera, _please_ calm down…"
What a proud human. But strangely…not for herself. She's proud of the people around her. Quite refreshing. I'd say that I've rather had enough of the usual narcissists. And, if I may say, with rather strong, correct opinions too. Listen closely to every word she says, child. There is much you can take from her insights.
"I will _not_ calm down, Amara! How can you possibly be so calm when there's someone like _her_ right in front of you, spouting things off like she knows everything?"
"I'm just a normal girl, Sera. It's not that big of a deal."
"Have you seen her _house_, Amara? She practically lives in a mansion. Her whole life, she's never had to worry about food, about having a roof over her head, about if she'll be alive tomorrow. And now she _dares_ enter into your lives without even a single sacrifice?"
All excellent points. Child, no matter how old you may be, you will remain a child in my eyes until you suffer true hardship. Learn that there is no free lunch in this world. Learn that if you truly want something, you need to _work_ for it. If you don't work for it, you won't get it. It's as simple as that.
There is no sense believing that all of the puzzle pieces will align one day, and suddenly everything will fall into place. That's at best a fantasy that should be relegated to stories. How can you possibly be happy if you've never been truly sad? How can you recognise success if you've never failed?
…Respectfully, _William_, I must disagree. Life is nothing without suffering. If one does not suffer, they cannot understand how other people who truly _do_ suffer feel. Those who experience more suffering are objectively better. Not knowing that only means that you have not experienced enough to understand the incredibly large range of emotions and experiences one can go through. I'd recommend going out and travelling more.
"Woah, woah! What's going on here? Ladies, ladies, calm down! It's a birthday party — let's not get too aggressive." Oh, go away, new boy. Don't break up the debate _now_. It was just starting to get interesting!
"Even if you're the birthday boy, Ethan, this isn't something I can back down on. Look, Phoebe. If Amara has her own reasons why she keeps you around, fine. I'll respect that. But why should you, someone who's been sheltered all their life by _mommy_ and _daddy_, knowing nothing but their love, never having to worry about food or shelter or survival be here over someone like Leo?"
"I gotta say, Sera, I'm on Phoebe's side here. It's not _wrong_ to be normal. In fact, I think that normal people are great! I love normal people. I feel like it'd be better if people _didn't_ have to go through things just to have nice things, y'know?"
"Huh? That makes no sense. What about all of the people who _do_ go through things? How is that fair? I disagree with my parents on a lot of things, but being grateful for what you have is something that we both share an opinion on."
"Why would you ever want to want to bring people down?"
"Amara?"
"I get trying to lift up people in pain, Sera. I do. But why would you ever want to push down happy people? I don't think that life is transactional like that. Phoebe and I equally don't deserve to get murdered."
"I agree. _Murder_ might be a stretch. But it's not equal. Things should be equal. Why aren't they equal?"
"If you really want to have this conversation, why don't we have it in the room over there?"
"Only if everyone hears."
"Oh my god, Sera. Why are you such a drama queen?"
"Ex*cuse* me? How am _I_ the drama queen? What about you? You chose to defend Phoebe by _yourself._"
"Sera, I like you a lot, I really do — I might reconsider after this conversation though, depending on how it goes — but you gotta come back down from your outlandish opinions, girl."
"All of the people you've talked to, Ethan and me and Chelsea and Ken and the many, many more I'm sure I don't know, we're all really grateful that you're so understanding toward us. But — well, I don't want to assume, but for me personally — I don't want to be treated differently. I just want what happened to go away. I'd rather not talk about it, y'know?"
"Why not? It should be a badge of honour. You should totally share it! You'd be way cooler to other people. Dark and brooding. _So_ interesting."
"…Is this how you thought the entire time?"
"Duh? I don't know why you're trying to stop me, Amara. You're all the way up there with so many more worldly experiences and perspectives, but I'm just here trying to get us lowly peasants up there so we can understand you better. It's hard to do that when you keep pushing us back down."
"Oh, Sera. Please tell me you're kidding. I didn't — there's no way you could possibly be _below_ me. It's…it's not helpful. At all. All I want is to just be a normal person in a normal world. That's it. You don't need to be that person for me. Don't — don't hurt yourself doing that. It's not healthy. And it's never worth it."
"There is no such thing as normal in this world. Everyone has their perspective, their side, their story. Everyone is different."
"Oh, no. Trust me. There is _absolutely_ a normal. And I strived for that for _so very long_, Sera. Way before I met you. Please trust me when I say that no one wants to experience trauma. It's _never_ a good thing."
"You're telling me that what I've been through wasn't _real_ trauma? When I asked my dad to shove my head underwater for fifteen seconds? When I asked George to tie me up against a board for a few hours? Drat. Maybe I should poison myself instead, that might have a stronger lasting impact…"
"You did _what??"_
"Oh, whew. You didn't know. Thank god. I thought it wasn't gonna count and I'd have to pull out all the stops to join the cool kids club."
"No, no, that's not what I meant. I — I think I might need to take a seat just to comprehend what exactly is going on. Maybe we could continue this conversation later."
"Yeah, yeah, no problem. By the looks of it, I might not be at your level, Amara, do you think I've suffered enough to beat Ethan, maybe? Maybe an Ethan and a half?"
"I…I can't. I'm sorry. I have to go."
"Oh, shit, Amara. I'm sorry. Did I trigger your latent trauma?"
"No, no, please — please leave me alone for a moment. Please."
"Ooh. Gotcha. Lemme know if you level up again!"
"Yo, Sera, what'd you do to Amara to make her run out like that?"
"She taught me that I have a lot of room to improve. Not as much as you, Phoebe, but there is still a great distance between me and her."
"Er… That's not _bad_, I think. So why was making an expression like she wanted to vomit?"
"Oh, y'know. People with checkered pasts often relapse into it, they get sad after something reminds them of it, and it's a true journey and a clear example of humans thriving through adversity that lets them overcome it. I'm really impressed by how she handled it, myself."
"Huh. There's…a lot to unpack here. Um."
All of these humans are so strange. They bear such strange expressions toward each other, as if they cannot understand each other. Bluebirds do not have this problem at all. Why don't they stare at each other and immediately comprehend what the other is thinking?
Or fight it out. That's always a clean and decisive way to determine any winners or losers. Hell, if I could, I'd fight on Sera's behalf myself. I've never met a human who so clearly understood our perspective.
When you grow up, go adventuring more. See the world. See its people, face its challenges, and suffer until you can experience the full range of bluebird emotion. All of these pussycat humans are cowards. Probably never worked a single day in their life. Never had to forage for food in the winter, or watch another human die.
To hurt is to live. How can one possibly know happiness if they are never sad? How can one possibly know pleasure if they are never in pain? These humans will never reach the heights of emotion, never achieve their true potential.
"Sera, I'm on your side!"
Ah, another sane human.
"Eh. Lucas, you don't count. You're not even at my level, let alone _them_. Glad you have the right mindset though. If you listen to me, you'll be able to understand the world more. Understand people more. And how could that possibly be a bad thing? I simply want people to broaden their perspective."
The other girl returns.
"Sera, could we talk about this later? It's Ethan's special day, and sometimes it seems like you talk about nothing but how people would be doing so much better if they just stabbed themselves sometimes."
"But they should! It'd be a learning experience."
"Sera…"
"Oh, right. Fine. Ugh, what a spoilsport. Right, guys?"
Hey. These are Sera's friends, aren't they? Why aren't they sticking up for her? Just because they share an objectively incorrect opinion doesn't mean that they can dismiss their friend like that. How rude.
---
"How was the birthday party?"
"Not great. Some sheltered rich girl was there and she was being a jerk. That kinda ruined the whole thing."
"You should be grateful that you even have the opportunity to go to such a frivolous event. When I was your age, I was already married and working, not fooling around and spending lavishly on snacks and treats. Consider yourself lucky."
"You keep telling me over and over again. I _get_ it, ma. Unlike some other people."
"Oh, sweetie. I know. There's not much you can do about it if they really don't want to change. You have to be willing to look at the flaws inside you, and it seems like these people just don't want to do that. It's a shame that there are so many like them out in the world."
"I told one of them that they should broaden their perspective and be more considerate, and she almost punched me!"
"Hmph. Ungrateful rats. Their parents must have been too protective of them. Didn't want them to get their hands dirty in the real world. Probably only went to the _sanitised_ plastic playgrounds. No, they were the ones _sanitising_ the playgrounds."
"They gotta be."
---
Sialia, I know that _you_ never wanted kids, but Mr. Swainson, I cannot believe you. I thought that as a fine, distinguished gentleman, you would have had the orthodox mentality that one must experience as many things in life as possible. This is an impossibility.
"Elizabeth, let me be frank. I have seen enough of the world, and I would rather my children not have to see the parts that they do not need to see. There are some things better left unsaid."
You are much too protective.
"There are things that birds _should not_ experience. It would be incredibly traumatic and have a terrible effect on their mental health."
Mental health? What are you talking about? Birds can function perfectly fine no matter what Garuda throws at them. It's how we thrive as a species. Why, my eldest daughter flew straight into a travelling car's windshield and she values her life all the more for it. I myself tried the same — with a slower car, to minimise the risk of injury — and found myself with a greater appreciation with the world.
"Why would you do that to yourself?"
To understand her and the experience. How could you be so aghast about this?
"Liz, you're an affront to all that pain stands for. Things hurt for a reason."
If one never hurts, how can one love? Emotions are relative. A bird with the emotional range as wide as a feather will never feel true, unadulterated joy. Birds — and humans for that matter — have to hurt sometimes.
That is what pain is — a reflection of happiness. Pain _helps_ us feel happy, Sialia, Mr. Swainson. It is a very good thing.
"Elizabeth. Let me ask you this. I understand that it may be difficult to change your mind —"
Absolutely.
"— but if you could put yourself in a situation where you would never hurt or feel sad again, would you?"
No! Didn't you hear a single word I said?
"Liz, I almost forgot to bring this up because of all the other crazy philosophical stuff you went on, but let me remind you that Juliette is _not okay._ I have no doubt that if you asked her, she would agree in a heartbeat to not have had her beak crushed in. She didn't and still doesn't _want_ that memory, Liz. Pain is something Garuda blessed us with so that we know what to avoid."
She can absolutely have memories that she'd rather not have but still are better for her in the long run. Children never want to do work around the nest, but you would still encourage them to do that, wouldn't you?
"That's what I'm trying to say. It's _not_ better for her in the long run. I can't believe I have to explain to you why making your children do chores is not at all comparable to She's deathly afraid of any moving object now. Don't you know that that's why she stopped human-watching with you? Why she avoids flying? Why she moved to Florida? She's so afraid that she never wants to experience anything like that again. She barely talks to the other birds, Liz. When was the last time you visited her?"
I… It must have been nearly three years now. I was not aware of this. Regardless, if she tries harder, she can overcome any obstacle. Give it some more time and she will surely rise up to the occasion and rise through the ashes like a phoenix to her new self. Stronger than ever before.
"Help me out here, William. She's not on my wavelength. Got any solid arguments to stop her from putting through Archie here through some sort of torture machine later on in his life? I wasn't worried before, but now I definitely am."
"How many years have you been human-watching, Elizabeth?"
Almost ten. Why?
"And in those ten years, how many humans have you seen that were hurt?"
Quite a few. Why?
"Most humans who are hurt don't express it. To my understand, instead, they actively try to hide it to reintegrate with society. There are a lot of them — both humans and bluebirds — that aren't able to fully. Maybe an equal number that aren't able to at all."
Suppose you're right. These people are harder to see in the world. But —
"Maybe we should drop this topic. Clearly we aren't getting anywhere. William, I'm sure you must want to get home by now. We've kept you for far too long. I'll stay with Liz, don't worry. At least until we reach the great mountain range. Help her keep an eye on Archie, too."
"My thanks for your companionship the way here."
No, no, the honour is all ours! Sialia and I, we've loved having you here. You've provided such a great perspective that we've learned a lot from. Perhaps in the future we could meet up and have more…insightful discussions in the future. I'd love to visit you in Montreal.

View File

@ -1,286 +0,0 @@
---
title: "Illusion of Solitude"
date: 2023-12-29
tags:
- birdseye
- nanowrimo
- featured
---
**Summary:** An old bluebird takes her grandson human-watching in Vancouver. This time, they find a young child dealing with grown-ups who just don't understand.
<!-- more -->
---
Keep to the left. Mind the seagulls. We're approaching the coast. Those bastards appear far too often. One of the only reasons why there isn't a permanent bluebird population in Vancouver.
We've almost reached our destination. I suppose we could fit _one_ more experiment here. Reach out to one last human. For this last one, how about you pick? You've seen me do it a couple of times. If you need assistance, I'll be right here.
That building? That could be anything. If I were to guess, judging by the number of residential buildings in the area, that might be a school. Good timing. School should be in session by this time in the morning.
Ah, these are younger children. Perhaps no older than two hundred times your age. An excellent choice, any of these. I don't believe we've watched any humans so young. It'll be more difficult, though. Usually you see their parents hovering around them when they're so young. Perhaps not at school, but once outside the compound, humans become fiercely protective of their young. Like no other species I have ever seen.
These particular children over here playing outside. Mind the adult. If he sees you, he'll chase you away and keep a more careful eye out. They must be in recess from learning.
Which one do you like the most? The one talking to the wall in the corner away from all of the other children? You have good taste.
"Zoe, do you want a cup of tea? Here. I made it nice and cold for you. Do you like it?"
She is truly talking to the wall with nothing in her hands. Is the wall named Zoe?
"Ruth, are you talking to nothing again? Why don't you play with the rest of the kids?"
"Mrs. Pernumble, I'm having a tea party with Zoe! And _you're_ not invited. So go away."
"Right. Zoe. Your…"
"My friend. She's waving at you. Oh — be careful, Zoe! You'll spill the tea if you wave your hand like that."
I do not see a child waving with a cup of tea.
"I…see." As a trained expert in recognising human patterns and mannerisms, I, Elizabeth von Turdidae, can attest that the woman is lying. Kindly lying, but lying nonetheless.
"Surely Zoe wouldn't mind if you spent a few recesses playing with Jeremy and Sheila. Doesn't it sound fun to play soccer? They're all laughing in the field. It sounds to me like they're having the time of their lives!"
Children are such mysterious creatures. This one might be staring daggers into the woman. "I can't leave Zoe here. She doesn't like soccer. And she gets scared without me. And I haven't finished my cup of tea!"
I would like to re-attest that there is, in fact, a lack of any tea or anything resembling tea in the immediate vicinity.
"I could keep Zoe company. She's got a lot of questions for me, right? So perhaps we could have a conversation while you play soccer."
"I don't think so, Mrs. Pernumble."
"Why not?"
"Because you haven't said a word to her and now she's very upset. It's okay, Zoe. I'll never leave you. Have another cup of tea."
I know that I'm getting along in years, but I _do not_ see a human child. Several worm children that look very tasty, yes, but no human child. Or tea. Do you see a human child?
Where is it?
Interesting. Perhaps this is a special human child. I have not known any human child that could hide themselves from other people, but humans still have plenty of surprises in them yet.
…But where's the tea?
"Oh, Ruth. Please. I'm sure the other kids would love to play with you. Can I tell you a little secret?"
"La la la I can't hear you. Can you hear a Mrs. Pernumble talking, Zoe? Yeah, me neither. Oh, thank you for the biscuit! Let me refill your tea again. You're a fast drinker!"
Heh. If there's one thing that is common between humans and bluebirds, children exasperating elders is universal across species.
Although I certainly wouldn't sigh and walk away like her. No, misbehaving children must be punished so they don't do it again.
"Thank you for the biscuit, Zoe. Have you heard from Miss Piggy recently? I heard that Miss Froggy and her had the most delicious of teas the other day. Mm. You're right. That _is_ very interesting."
I must admit, it is rather strange to watch a conversation happening with a human I cannot perceive in any way. I hope you're learning more than I am.
"Um, Ruth?"
That sigh does not belong on a child her age. How adorable — perhaps she thinks that if she's as petulant as one, others will see her as an adult.
"I'm _so_ sorry, Zoe. I know you don't like it when our tea parties get interrupted. What _is_ it, Peter?"
"Who are you talking to?"
"Zoe, of course. My best friend. She says hi, by the way. Now, get to the point. What do you want?"
Ha! Another victim of Zoe's invisibility! He looks so confused — oh, my sides.
"Mrs. Pernumble said that maybe you wanted to play with me and Alfred over there? We're playing cards."
"Oh. She — um. I… I can't. Zoe needs me to keep her company. She doesn't like it when I leave her alone."
"Who? I don't see her."
"I _told_ you, Zoe's my best friend. It's not _her_ fault that you can't see her."
That hesitant wave — the worm on top! Glorious. I might have to start observing the younger humans more. They're such a racket! Two inexperienced creatures learning about the world.
"Are you sure she's real?"
"Of _course_ she's real! Say sorry to Zoe, right now! I can't believe you'd say that. I'm sorry, Zoe. He didn't mean it. He just doesn't know better. Right?"
"Uh, I'm sorry!"
"Zoe's over _here_. Look at her properly when you say sorry."
"…Sorry."
"Hmph. She says she forgives you this time."
"If she wants, she can play with us too?"
"Nah. Zoe doesn't like cards."
"Okay then. If she doesn't want to. Bye bye."
"Bye bye."
My scientific mind is racing at the possibilities. The child couldn't see her. The human couldn't see her. I can't see her. What are the criteria for who can and cannot see Zoe?
---
"Be sure to finish the letters worksheet — I expect to see perfect 'A's from everyone! Now, children, fetch your bags — it's time to go home!"
The chatter of children after school is the same regardless of their age. It's always so relaxing to immerse oneself in the wave of conversations taking place left and right.
"Sheila, Sheila, are you still coming to my house after school?"
"I got this super cool fire truck for my birthday! Leo, you gotta bring your cars!"
"Nooo! My mom grounded me. You have to beat the boss without me, Dylan! You have to!"
"Come on, everyone. Less talking, more moving! Once you've changed into your outdoor shoes, line up against the wall outside the classroom!"
---
Well done, child. You're following your humans quite well. I barely had to help you at all.
"How was school, honey? Did you learn a lot of new things?"
"We learned about the alphabet! I can draw lots of little 'A's now. Today we learned about the big 'A'."
"Hey! It's my favourite kiddo! Ruth! Ruthie. Beat up any boys today?"
"Zoe almost. Hmph. Peter was being mean to Zoe. I feel so bad for Zoe, daddy. No one understands her and they're all so…so mean to her!"
"There's cookies and juice for you on the dining table, Ruth. Make sure to wash your hands."
"Aw, that sucks. Does Zoe want a glass of orange juice, too? Maybe it'll help her feel better?"
"Daddy! Zoe is _allergic_ to orange juice, remember? I told you _yesterday!_ She'll have her unicorn hair tea like she always does. Mommy, can I eat my cookies upstairs? Me and Zoe are having a tea party again."
"All right, but don't spill any of the crumbs! We don't want ants moving into our house, don't we?"
Oh! How unfortunate. Child, I must interject — allergies are new to you, yes? Bluebirds don't particularly have the horrid disease. If some humans — and it's impossible to tell which humans before they actually eat it — eat certain foods, like peanuts! Or fruits, or nearly anything — they could _die_. That's called an allergic reaction.
To have an allergy toward a fruit — truly a pitiable existence it must be.
"Tea party time! Zoe, here is your unicorn hair tea. Freshly stirred! Only the best for my best friend. Oh, thank you! Yes, I'm doing great. Can you help me with my homework after this? You're always so good at drawing those weird lines. Mrs. Prenumble says that they're part of letters, which are part of words.
"Zoe… Why does everyone hate you so much? They never want to talk to you. Even Mrs. Prenumble. They all pretend that you're not a _real_ person. But don't worry. _I_ know that you're real. No matter what everyone else says. You're my best friend, right? I can't leave you alone. If you want, I'll stay with you, forever and ever!
"Will you also stay with me, forever and ever?"
Human children. So adorable! Already forming pacts for life in the tender young stage of pre-adolescence.
---
Finally some change. Pardon me, but I can only listen to a child have a multi-hour tea party go on for so long before even _my_ patience wanes. Let us investigate the commotion at the door. Ooh. An older boy. A family! Human families are so small. Their babies don't die nearly as often as bluebird babies, but there are just so few of them in the world. I suppose that explains the parents' protectiveness. But if they want their children to succeed, why don't they simply have more children? That would maximise the probability of successful children reproducing in the future.
"Mom, dad, I'm home."
"Welcome home, Jacob! Dinner will be ready in just a minute. Could you call Ruth downstairs from her room?"
"Hey, kiddo! How was school? Beat up any girls today?"
"Oh my god, you can't _do_ that, dad!"
"Hmph. All these fancy schmancy new norms are stifling. Back in my day, you could hit whoever you wanted, and the other guy would just hit you back! None of this 'no hitting girls' nonsense."
I knew that humans discriminated between their sexes, but I didn't realise that they couldn't hit females. All kerfuffle and waffle, if you ask me. If someone has wronged you in any way, giving them a good knock in the old noggin is always an excellent first move. Really sets the atmosphere for a full-out fight.
"They're weaker, so it's not fair. They can't hit back, so it's up to us men to show other men who's boss."
Nonsense! Excuse _me?_ I don't know about _humans_, but female _bluebirds_ pack a pretty punch in their wings. It's true that males usually only fight males and females usually only fight females — because, let's be honest, why would a female ever need to fight a male? — but I did not realise that there was _no_ cross-sex combat in human world. Strange, too. I could have sworn that I'd seen human males fighting human females multiple times over my many years.
"Son, maybe the times are changing. And I respect that. But no matter what happens, never lose that fighting spirit. Can't fight the girls? Fine. There's still a good half of the population you can beat some sense into. Now, if they say that _fighting is bad_ and that _no one should do it_ or whatever? That's when you put your fist down and screw the rules. Let no one tell you what you can or can't do."
"I'll do my best, dad!"
"I know you will, son. Make me proud. Nothing like a good fist to the noggin to help loosen any lips."
Wonderful parenting. _This_ I can get behind one hundred percent. I know I have a lot of negative things to say about humans, but in reality, they're so diverse that there are so many different viewpoints to learn from. There are some that are objectively wrong, some that are objectively right, and then most are in the middle. It's rather refreshing to have one's opinions validated every once in a while.
And what camaraderie! Certainly bluebird children are never so close to their parents. Or their grandparents, for that matter.
"Now bring Ruth downstairs like your mom said, will you?"
"Yessir! Ruth!"
"You might have to go upstairs to bring her down. I think she said that she was having a tea party with Zoe again."
"Zoe? Ugh. How long are we gonna entertain her, dad?"
"As long as she wants."
"Hmph. Ruth! Open up! Mom says it's time for dinner!"
I wonder why she isn't responding. Drat! If only we could be invisible and incorporeal like Zoe must be, so we could position ourselves _in_ the door and see both sides of the conversation. Having to move around to the back of the house just to see the hallway is _so_ irritating.
"Ruth! If you don't say anything, I'm coming in in three…two…"
"I'm having a tea party! Go away, Jacob."
My. She sounds aggravated. What kind of dirt landed on her head while we were away?
"I'm not gonna wait here for you to finish your prissy tea party. I'm comin' in!"
This is actually quite nice. It means if we circle around to the other side of the house, we should get a nice and proper view of everything that is happening.
"HEY! I didn't say you could come in! Zoe doesn't like you, you know. She says that you're big and fat and dumb and stupid for interrupting her tea party. Get out."
"Oi. I just came to pass on a message. Why do you have to get so pissy?"
"This is _my_ room." How funny. Ruth trying to push Jacob out of her room. Certainly it isn't happening unless it's under his own volition. Valiant effort, though. I would applaud like the humans do if I had hands. "Can't you read the sign? It says NO JACOBS!"
"Do you even know how to read?"
"Shut _up!_ Zoe said that you can't be here, and that means you can't be here! Zoe needs her time to herself. She's has a very tiring day and she needs her tea and biscuits —"
"Zoe this and Zoe that. Jeez, don't you have any _real_ people to back you up?"
Oh. That one might have hit her harder than him slamming the door open. What is that expression on her face, I wonder?
"Yeah? Don't have anything to say, dontcha? I wonder why?"
"Say sorry to Zoe right now. She's my _best friend."_
"Oh my god, Ruth. How are you still so stuck on her? Zoe's not real! She's in your _mind!_ She's one of those _imaginary friends!"_
Certainly not. I find it rather unlikely that the human adults and the human children spoke to her if she wasn't real. That Mrs. Pernumble or whatever it was wanted to have a conversation with her, too.
However, judging by the blankness of Ruth's face, she might believe him.
"No."
"Yes." Rather gleeful of him. "You're _imagining_ her. Probably because no one likes you enough for you to have _real_ friends."
"That's not true. Shut _up._"
"Oh, yeah? What's her favourite colour?"
"Yellow!"
"What's her favourite food?"
"Unicorn hair tea with rainbow biscuits!"
An eyebrow raised. In his defense, I didn't think that those were real either. But it makes sense to me. What else would an invisible person eat? Oh! It just clicked for me. That must be _why_ she's invisible! All of these exotic ingredients must have an effect on the body that makes her difficult to perceive. And Ruth must be consuming enough that she can perceive her but not turn invisible herself.
My cleverness and intelligence scare me sometimes. But I digress.
"What's her last name?"
"It's! Um…"
"Where does she live?"
"I… She must have told me…" A fearful glance to her right. Is she losing the fight? Come on, how difficult could it be to prove that a human exists?
"Exactly. What does she do when she's not with you?"
"…Stop it…" Hm. Personally, I would prefer physical combat over verbal combat. Not nearly as emotionally messy. Much easier to know when the damage is done and when they've learned their lesson. Most importantly — much easier to restrain oneself. I suppose she's been thoroughly beaten. Her father will be proud — Jacob finally beat up a girl.
"When did you meet her?"
Oh?
"When grandmama went home! She's _real_, Jacob! I _know_ I met her. She was outside on the swing outside grandmama's house when the sun was setting and I was sad and we went on the swing together and we were friends ever since. Zoe's _real!"_ And here comes the crying. If she was sobbing before, she's bawling now.
Hm? Why isn't he saying anything else? Are tears so effective against physical and verbal combat? He seems shocked. How could this be surprising? Bluebirds meet new bluebirds all the time. Is this not true for humans?
"Jacob. Come over here, please." Oh, my. All of the tension in the air and I didn't even notice the mother in the doorway.
"Oh! Um. Mom, I can explain. I was just…"

View File

@ -1,96 +0,0 @@
---
title: "My Precious"
date: 2024-02-05
tags:
- shorts
- psychological
- featured
---
**Summary:** Max tries to save his dog, but it's not enough.
<!-- more -->
**A/N: we take some creative liberties re: symptoms of cancer / its rate of progression!**
The day you got your dog was the happiest day of your life. Your dog didn't yell at you whenever you delivered a pizza five minutes late. Your dog never complained when you didn't add enough sugar to her coffee. No matter how you complained over and over again how you weren't getting enough sleep, Susie was always there at the end of the day to greet you, a welcome bark and an expectant gaze ready for treats and a run. For every high and every low, your little bundle of joy was right by your side.
The day your dog became sick was the saddest day of your life.
The first signs were small: she didn't eat as much, and you noticed that she shed more fur than usual. But she was still the same playful golden retriever you knew.
Out of an abundance of caution, you decided to get her checked out at your local vet.
"There's a cancerous tumour at the base of her right lung." The vet shakes her head, her tone grave. You cast a worried glance at Susie's sleeping form on the examination table. "I'm sorry, Mr. Haltmann. You're lucky you caught it this early, but it's growing fast. My diagnosis is that it'll become terminal in a few months."
Your mouth dries. "What can I do?"
The vet taps her clipboard. "She'll need surgery. I can direct you to a place, but the cost can be upwards of five thousand dollars."
"Anything for Susie," you say, shaking your head. You're already crunching the numbers, but at the very least, you'll have to scrimp and save and start working a third job to save her. But it's worth it.
All of this is for Susie, the beloved dog who kept you company for the last four years.
---
"I suppose that that's settled, Mr. Haltmann. Welcome to Hotel Trivago. You'll be starting Monday."
"Thank you!" Your cheeks hurt from the grin you're restraining from spreading across your face, but you keep it professional long enough to shake your interviewer's hand. As you leave the building, there's a bounce in your step and you're humming that pop song you heard over the radio in your eleventh-hand car.
You trip over a bag of dog food and end up skidding to a stop before Susie's lethargic figure. "I promised you, Susie," you whisper in her ear. "I got a job. And that means that we're on our way there." You squeeze her paws. Susie lifts her head and tilts it at you, before she sets it down again, closing her eyes.
"Hang on just a little longer, please."
The hotel housekeeping work pays you $500, after which you'll be one-tenth of the way there. You haven't fallen over yet, although juggling four part-time jobs at once is still a struggle.
All of this is for Susie, your life and joy that kept you going for so long. You can't wait until the day you can play fetch with her once again.
---
It's not enough, you realise. You need more. You read online that taking care of yourself was most important, no matter what you might be going through, but you can't take your mind off of Susie. It's with a heavy heart that you make sure to feed yourself a nutritious meal every day while you know how much she's suffering.
A customer at the coffee shop you work at mentioned that tech is the place to be for veterans and newcomers alike, with plenty of jobs at many different skill levels. It'll be a time investment. Time that you might not have, but it's your best shot.
After you come home from your cashier gig at Walmart every evening, you go straight to the library and learn web development until closing time.
All of this is for Susie, your lovely little cat that needs a new leg. You can't wait to see her climbing up everywhere and gleefully shredding furniture with her claws once again.
---
"Already?" your manager says, her brow furrowed as she squints at your resignation papers. "You've only been working here for a year. You've been doing good work, too. Bradley hardly ever complains about your code."
"Sorry, Joyce. I got an offer from Google. They're paying me triple what you guys do, and I need the money." Even though you didn't get along too well with your colleagues, you feel a twinge of regret in your gut. These guys treated you well, and you learned so much. You almost feel ready for the big step.
She sighs, setting down the documents. "I understand. Software engineers," she muses. "They all come and go like the wind. Always chasing the rainbow. We're going to need you to document your work these last two weeks. Bradley'll take point for the knowledge transfer."
"I appreciate it, Joyce." Internally, you let out a sigh of relief. She took it better than you'd expected. You thought the crabby woman would have tried to hold you back. Hope blossoms in your chest for the future as you make your way up in the world.
All of this is for Susie, your estranged daughter who left you until you could fix your life. You can't wait to see her expression when she sees who you've become.
---
She doesn't move. You stare ever more intently at her still form, waiting. It's all out of your hands now. If your calculations were correct, then…
"Mr. Haltmann, sir! Mr. Haltmann! I have urgent news!" Your office door clatters open. The glass walls around you let the midday sun shine into the hallway, illuminating a young man waving a sheaf of documents.
You chuckle. "Mr. Borparner, all news is urgent to the right ears. But do go on. What is it?"
"Their board of directors agreed! They're willing to sell you NVIDIA at market valuation, sir — I can't believe it!"
You lace your fingers together, resting them on the mahogany desk before you. "Excellent. Prepare a press release right away. I want the deal finalised before the day ends."
"Yes, sir! Right away, sir!"
The door slams shuts behind Borparner. You return to the chessboard sitting on your desk in front of you. The opposing queen wobbles, then falls over, knocking over the king in the process. "I suppose that that's over, then."
All of this is for Susie Inc, your heart and soul. You can't wait to see how her stock will jump once the trade opens tomorrow morning.
---
It's midday when you return to your empty house. You should buy a new house. Move somewhere nicer. This one holds a lot of sentimental value to you, but you can afford better now. You deserve better now. It holds a lot of sentimental value to you, but you can only fiddle with the keyhole so many times before you replace it. Day after day, the wasted time adds up.
A voice from the lawn next door calls out to you. "Max! Heya, neighbour. I heard you were raising money for your dog. How's she doing?"
You stare at her blankly. "What dog?"
The key finally clicks, letting you inside. Absently, you kick a persistently heavy towel away. It's starting to smell, too. How long has it been since you last did laundry? You tell your new servants to clean it up.

View File

@ -1,134 +0,0 @@
---
title: "I Found A Magical Fish While Fishing With My Cousin (In Another World)!"
date: 2022-11-14
_draft: true
tags:
- uoft
- nanowrimo
---
**Notes:** This was written as part of *University of Teyvat* for NaNoWriMo 2022, and also submitted to the WatSFiC × CWC Short Story Contest.
---
A wooden rowboat drifted over a lake. Its two occupants sat facing each other on their respective benches, wearing matching wide brim hats as they relaxed in the bright summer sun. Two fishing lines were mounted on opposite ends of the boat, completely still in the water.
<!-- more -->
All was quiet but for the light brush of wind ruffling their clothing, and the water gently lapping against the side of the boat. Yanfei tipped her head back, adjusting her cap so that it would sit over her eyes. "Thanks again for coming out with me, Ganyu. How's work, by the way?"
"Oh, it's light right now, don't worry," Glancing at the rods floating around the water, Ganyu waved the matter aside. "I should be asking about you. I hear your legal consultancy has gotten a lot of attention lately."
"Yup! Although," Yanfei sighed, "there's so much conflict between Vision-holders and the common folk lately. So many people are suing each other left and right… The divorce cases are the *worst.* No one's ever always right, and *I* have to be the one to…to… I wish society was more black and white," she said, slumping further back against the wall.
Ganyu chuckled, her eyes darkening. "You don't say."
"You've lived a lot longer than I have." Yanfei glanced up at Ganyu. "What do you think?"
"Hmm…" Ganyu said. "Do you know an old book from Mondstadt written by wind-worshippers?
"*Lost Prayers to the Sacred Winds*, right? It's supposed to be insightful — I've been meaning to check it out sometime. I wish I had one, though."
"You should give it a read. It's not going to help you very much with dealing with people, but it's still a good book. Personally, I think experience is what helped me the most. Visit new countries, meet new people, throw yourself into very different situations…" Her voice trailed off as she stared into the depths of the lake. The murky water made it hard to see past a few centimetres, but the slight wiggling of the line sent unmistakable ripples through the previously still water. "Yanfei, do you see that?"
"We got something!" Yanfei grunted, pulling hard on the fishing rod as she tried to reel it back in. "I…think this one's…a big one! Ganyu…help?"
Ganyu reached over and effortlessly *yanked* the fishing line up with her hands. A mossy treasure chest flew out of the water and landed perfectly in the centre of the boat, splashing lake water all over their shoes. More water continuously streamed out of the chest and onto the base of the boat. Ganyu wrinkled her nose as she turned on the Automatic Magic Canoe Water Drainer™.
Yanfei stared. "How'd *that* get caught on the line?" She poked the chest using the other end of the fishing rod.
The chest did not poke back.
"It's kinda heavy," Yanfei reported. "Maybe it has treasure! I'm gonna open it."
"Are you sure? Something this old at the bottom of a lake would have a larger chance of being an evil creature that wants to eat your soul. Although," Ganyu mused, "if you're lucky, it could instead be some legendary magical weapon that has the power to freeze a whole ocean."
The rusty silver lock on the chest was broken, inviting the two to pry it open for the mystical contents inside. With a lowly, mysterious *creak*, Yanfei pushed open the lid of the chest. She and Ganyu stared inside. "Is that…a bow?"
Carefully, Ganyu removed the large, shining archery implement, avoiding the sharp blue spikes along its body. As she ran a hand over its aged wooden frame, Ganyu inspected the glowing runes all around the grip and belly of the bow, giving it an experimental flex and draw. "It says…Polar Star," she read, squinting to make out the ancient language. "Seems like a good bow. I'll keep it."
"Good decision," Yanfei nodded. "If you don't overflow on CRIT Rate, it's your best-in-slot in freeze teams. Second BiS in melt, too."
"Huh?" Ganyu asked.
"Huh?" Yanfei asked. "I mean, you're the archer girl, not me. I'm not gonna be able to use it. It's all yours."
Turning the bow over one last time, Ganyu swung the bow behind her. Yanfei watched it disappear into pretty golden sparks into the secret dimensional subspace where all of them kept their weapons. "I think there was something else in the chest."
Indeed, they heard a *flop-flop-flop* coming from the chest. There was still one more item in the chest. Something…alive.
Yanfei creeped closer, eventually poking her head over the lip of the chest to peek inside.
An orange fish with bulging eyes and a mouth that looked like it was used to sucking bananas all day greeted her. Yanfei gaped. "It's so cute! Is this a koi fish, Ganyu? It's orange, so that means it has pyro powers, right? Oh, I'll name you…magic koi — Magikoi!"
"Actually, I think it's a different kind of carp."
"Oh. Magikarp, then. Come with me! I'll take care of you. You're going to grow up to be big and strong one day," Yanfei said gently, a warm smile on her face as she reached out with both hands to welcome the fish into her extended family.
Evidently, the fish did not want to be a new member of Yanfei's family and *splashed* out of the chest right onto her face.
*"Blergh!* Get it off, get it off!" Yanfei batted the fish away as she turned her head out to spit fish water, *eugh*, out of her mouth. The fish went flying toward Ganyu, who dodged it instinctively.
"It's getting away! No, Magikarp, stop!"
In one rapid movement, Ganyu drew an arrow from her quiver and fired, ice energy gathering at the arrowhead for a millisecond before she released it to trap the fish in a solid block of ice. It plummeted back to the bench beside where Yanfei was sitting.
Once she felt sufficiently less unclean, Yanfei proceeded to take out a worn music notebook and rip out one of its pages to set it on fire. The ice around the fish promptly melted and returned to reveal a fish. "It's not dead," Yanfei observed. "I think it's just fainted. That's one hardy fish."
Ganyu continued to aim the Polar Star at it. "Do you *want* it dead?"
Yanfei considered the idea. "Actually, do you mind holding off on that for now? I've always wanted to try something."
---
Ganyu and Yanfei stood on opposite ends of the small boat, which barely wobbled thanks to the Automatic Magic Boat Stabiliser™ 9000 that Ganyu activated. Yanfei thrust out her hand, kicking Magikarp out from beside her to take the field. "Go, Magikarp! I choose you!" she cried, waiting expectantly.
Like a fish out of water, Magikarp flopped onto the floor pathetically.
"Magikarp, you can do it!" Yanfei tried again.
Like someone imitating a dead fish, Magikarp floundered on the floor uselessly.
"Magikarp, I'm begging you! I'll give you snacks!" Yanfei pleaded.
Like a child throwing a temper tantrum because they didn't want to eat fish, Magikarp wiggled on the floor pitifully.
"I see. " Yanfei clenched her fist, staring down at the floor.
Like a Water-Type being electrocuted by an Electric-Type but not really caring, Magikarp jerked about on the floor woefully.
"I'm so sorry for not listening to you, partner," Yanfei whispered, falling to her knees.
Like a student just seeing the second page of the midterm paper for the first time, Magikarp drooped onto the floor anemically.
"It's my fault. I never treasured our bond enough," Yanfei said, squeezing her eyes shut. A single tear trailed down her cheek.
Like a joke that went on for far too long and was reanimated several times, Magikarp lurched about on the floor feebly.
Flames blazing around her to represent her determination, Yanfei fist-pumped the air, gesturing wildly before pointing at Ganyu. "I understand you now. Magikarp, *use Splash!"*
Like *it was the weakest and most pathetic* fish in the world, Magikarp splashed about on the floor aimlessly!
But nothing happened. Yanfei stood in silence for a few seconds. Ganyu returned from her fighting stance to a normal standing position, frowning. "How useless."
Yanfei nodded agreeably. "Yeah, Magikarp kinda sucks. The only thing it does is splash around. Magikarp," she declared, "you have disappointed me for the last time. By the power invested in me by myself, I sentence you…to exile!"
Ganyu pointed her bow at Magikarp.
"Wait! Do it outside the boat." Yanfei tossed Magikarp off the edge of the boat. Before it could land in the water, the trail of a fully charged ice arrow *schoom*ed past her and slammed into the fish, blasting it straight up. The fish comet left behind a beautiful trail of white that vanished as quickly as it appeared. "Nice shot."
"Thanks."
The two shielded their eyes, watching and waiting for the fish to come back down. "That might be a little bit farther than exile," Yanfei commented after a while.
"It's in a whole new world now," Ganyu said. "Nothing we can do about that."
"Nope. Not a thing." Yanfei settled back on her seat, lounging as they waited for another fish to bite the hook. Snowflakes gently fluttered down around them, melting and sending ripples where they landed in the water. A slight fishy scent filled the air.
"Snow in July," Ganyu observed. "That's new."
Yanfei glanced up. "There's not a cloud in the sky, either."
"Climate change, huh?"
"It's gotta be," Yanfei agreed.

View File

@ -1,38 +0,0 @@
---
title: "Transition to Universe City"
date: 2022-10-12
tags:
- barin
---
Porter Hall\
Universe City, Leeco
Brian Wright\
Chancellor\
10077 Seascout Avenue\
Cekendery, Leeco
<!-- more -->
Dear Chancellor Wright,
Leeco's Board of Directors convened last night and have appointed me to share with you
their decision regarding the expansion of Universe City. Token resistance from the district
boards were swiftly overturned with immense support from the populace.
Universe City, the "second capital" of Leeco has grown tremendously in cultural and
economic value to the nation over the past several years. Effective 1 October 2022,
Universe City will be designated the official capital city of Leeco. District boards have
already been instructed to begin the process of migrating, and Administration are roughly
one-third of the way done the transition.
Because the decision was made unanimously, consider it impossible to revoke the will of
the Board. Cekendery must maintain good standing with the Board during the transitory
period.
I wish you the best of luck in maintaining unity.
Your Studious Pupil,\
Ira Hagey\
Vice Chancellor of Leeco\
28 September 2022

View File

@ -1,60 +0,0 @@
---
title: "A Triden(t) Against the World"
date: 2024-02-29
_draft: true
tags:
- shorts
- "content warning: political fluff"
- horror
- u.s. politics
---
**Disclaimer: This was mentally painful to write and I hope equally repulsive to read.**
"Is it yet another left-wing liberal conspiracy, or has President Trump finally taken back control of the White House? His unannounced visit is a show of strength against the authoritarian measures the Biden administration has imposed upon us all."
<!-- more -->
---
"President Biden shows his patience in entertaining former President Trump upon his unauthorised entry to the White House. Reliable sources tell us that the two are discussing the change and continuity in their policies toward China."
---
Two men stared at each other from opposite sides of the Oval Office.
"Donald." The man at the desk stood, moving to the front of the desk.
"Joe," the other man said coolly. "It's been a while."
A pause.
"Darn right it has!" Joe grinned. "Come here, Donald!" he said, spreading his arms. "I can't believe it's really you!"
It took just three large strides before Donald was wrapping his arms around Joe, laughing. They held each other for nearly a minute, doing nothing but basking in the other's touch after so long.
Eventually, Joe pulled back, leaving his hands on Donald's shoulders, staring proudly into his eyes. Donald was the first to break eye contact. "I see you haven't changed the room much," he said. "Why don't you tell me what you've been up to?" He sat and patted the cushion beside him.
Joe chuckled, capitulating by plopping down by the armrest. "Two years in and you're acting like you own the place," he said, scooching over to press closer to Donald.
Donald waggled his bushy blonde eyebrows. "I *did* own the place."
Joe's face shadowed, and Donald pulled him closer when he noticed. "I missed you. The real you. You don't have to keep it up anymore, you know." Joe shook his head. "You've done it. It's over."
"Eight years," Donald said solemnly. "I promised that I would give you eight years. I'll run in 2024. It'll anger half the country just enough to let you clinch another term."
"You don't have to," Joe argued. "Kamala already said that she'd find someone else to be VP. I know how much effort you've put in for me already."
"Oh, my little robin." said Donald affectionately, patting Joe's head. "You know that's not going to be enough to convince them."
Joe made a face at the pet name, but he leaned into the touch all the same. "You know I hate it when you call me that," he groaned. A smile tugged at his lips nonetheless. "I wish we could be like this forever."
"I wish we could, too." Donald sighed forlornly. He ran his fingers through Joe's white locks. "But you know what the media's like. They're already on my case about today. By the way, are you using a new shampoo?"
"You noticed?" Joe said, pleased. "I smelled it off of this high schooler from Iowa. It reminded me of you. What do you think?"
"Keep it," Donald decided. "The chamomile smells so soothing."
They sat there, leaning against each other, simply enjoying the shared warmth of the other's presence. Finally, Joe spoke up. "Want to come up with a cover story together?"
Donald rubbed his hands together. "You're on. I'm thinking of asking Pingping to cover for us with a trade deal or two…"

View File

@ -1,41 +0,0 @@
---
title: "Bienvenue au Ciers!"
date: 2020-06-17
tags:
- barin
- unstagnation
---
_“Vous êtes maintenant à la station dEscribe. Cest la dernière station de la ligne de train CiersXunil._
_“Les portes vont ouvrir: à gauche._
_“Veuillez vous tenir à lécart des portes.”_
<!-- more -->
---
Bienvenue au Ciers! Veuillez donc vous assurer que vous avez lune des documents suivantes:
- Si vous êtes un résident permanent ou un citoyen de Ciers, vous devez avoir votre étiquette didentification de Ciers.
- Autrement, si vous êtes un citoyen dune autre tribu dans le zone de voyage de Farele, vous devez avoir identification valide de votre gouvernement de votre tribu. Ceci peut inclure:
- La licence étudiant de Leeco
- La licence professeur de Leeco
- La licence Non de Leeco
- Le billet intertribal de Demauge
- La carte de transports Farele de Xunil
- Autrement, si vous êtes un citoyen dune tribu de lAlliance Énigma, vous devez avoir le document de voyage FE1-D vous issue par votre tribu.
- Autrement, si vous êtes un citoyen dune tribu de lAlliance Preton, vous devez être accompagné par un fonctionnaire de votre tribu.
- Autrement, si vous êtes du continent de Barin ou tout ses îles (Voir le document de voyage 6-B pour une list complète des îles), vous devez remplir le document de voyage 6-C avant vous allez aux services frontières.
- Autrement, vous devez remplir le document de voyage 6-D avant vous allez aux services frontières.
Malheureusement, à cause de létat actuel des choses intertribal, les passeports intertribaux ne sont pas acceptées comme identification. Nous nous excusons pour tout inconvénients.
Merci pour votre coopération!

View File

@ -1,41 +0,0 @@
---
title: "Welcome to Ciers!"
date: 2020-06-14
tags:
- barin
- unstagnation
---
“_You are now at: Escribe Station. This is the last stop on the CiersXunil Line._
_“The doors will be opening on the: left side._
_“Please stand clear of the doors.”_
<!-- more -->
---
Welcome to Ciers! Please ensure that you have at least one of the following before you leave the train:
- If you are a permanent resident or citizen of Ciers, or if you are a tribal representative with a Ciersian Identification Tag, you must have your Ciersian Identification Tag.
- Otherwise, if you are a citizen of another tribe in the Farele Free Travel Area, you must have valid government identification from your tribe. These include:
- Leecan Student Licenses
- Leecan Teacher Licenses
- Leecan Non Licenses
- Demaugian Intertribal Tickets
- Xunilean Farele Travel Passes
- Otherwise, if you are a citizen of a tribe in the Enigma Alliance, you must have Travel Document FE1-D issued by your tribe.
- Otherwise, if you are a citizen of a tribe in the Preton Alliance, you must be accompanied by a government official from your tribe.
- Otherwise, if you are from the continent of Barin or any of its islands (see Travel Document 6-B for a list of all islands considered by Ciers to be as part of Barin), please fill out Travel Document 6-C prior to meeting with Border Services.
- Otherwise, please fill out Travel Document 6-D prior to meeting with Border Services.
Unfortunately, due to the current state of intertribal affairs, Ciers will not be accepting Intertribal Passports as a valid form of identification. We apologise for any inconvenience.
Thank you for your cooperation!

View File

@ -1,117 +0,0 @@
---
title: "The Birds on Censorship"
date: 2021-07-09
tags:
- birds
- unstagnation
---
**Summary:** Sudden news rocks the Birds' world as they reminisce on their past and their future.
<!-- more -->
---
All is well in the Bird residence. Brandy has come over to hang out today and is kindly preparing breakfast for Skoomer Bird and Noodle Bird, who sit across from each other at the wooden dining table. Their buddy Mango is also in the basement, chilling and playing video games.
Skoomer chuckles as he flips through a particularly interesting page in the newspaper. "Noodle," he says, turning the paper around and leaning forward to show her its contents. "Take a look at these things they banned recently."
Noodle raises her attention from her phone to Skoomer, squinting to read the tiny inked letters. "Wow. Damn."
"And this is just a small section, the rest of the pages are…completely expected." Skoomer sighs. "Some of these I expected too. Algorithms nowadays are incredible at filtering these out, and there is human review as well. I guess to the *common* person this…sounds incredibly scary, doesn't it?" he says, smiling and shaking his head.
"Mm," Noodle agrees. "What happens if you break these rules?" She shifts her gaze back to her phone, brow furrowed. "What if I accidentally posted hentai? Will I go to jail?"
Skoomer's reply is prompt and direct. "Instant deletion and maybe an account ban. Keep in mind, since your account is connected to your ID number, they know who posted it as well. *Exactly* who posted it."
Noodle's face pales for an unknown reason. "Uh oh. Uh…wait, doesn't League count as lewd content? They have 'sexy characters' — like a lot of them basically wearing bikinis." She rapidly types on her phone as she says this.
Skoomer raps his fingers against the table. "League's problem is more of a copyright issue, I would say," he hums. "Bikinis are fine, I think…in practice."
"This is Janna." Noodle raises an eyebrow, holding her phone up to Skoomer, which is showing a picture of a fantastic (d.: "of or relating to fantasy") woman wielding a spear in very revealing attire.
Skoomer nods. "Yeah, this is fine. Nothing wrong at all."
Confusion shows itself on Noodle's face as she slightly lowers her phone. "Oh…okay, never mind — maybe I don't understand what 'lewd' means."
At that moment, Brandy comes in, setting a plate of eggs and bacon in front of both of them. He groans exasperatedly. "Guys, it's too early for this debate."
Skoomer waggles his eyebrows. "Not for me."
Brandy thinks about this for a moment. "True," he decides. "Carry on, then." He steps away back to the kitchen for the other still-sleeping members of the Bird household.
Skoomer puts his newspaper away and now considers Noodle's earlier statement. "Lewd…it's a bit more blurry, I guess. But I think the interesting part is like," he waves away the matter, "the ban on LGBTQ content and underage dating."
"I mean, it *is*, but I'm not surprised about that," Noodle waves away the wave.
"…Because it's reflective of the policies in…many other fields," Skoomer continues.
This piques Noodle's interest. "Oh?"
"At the end of the day, it's not LGBTQ that is being prohibited," Skoomer argues, "but actually the organisations that advocate for it."
Brandy suddenly pops his head back in from the kitchen, frying pan in one hand. "Oh yeah, is underage dating illegal? I remember Skoomer got someone expelled for doing that." He pauses. "Maybe," he adds.
"*Technically*," Skoomer states matter-of-factly, raising a finger in the air, "underage dating is not forbidden as a law, but as local school or district policies."
Brandy shrugs. "Basically a law, then. A by-law, you could say."
Noodle looks disappointed but not terribly surprised. "Skoomer. Why."
Skoomer clasps his hands together and looks straight in Noodle's eyes. "It's my duty." He smiles.
"Oh," Brandy starts, "I remembered that correctly?"
"Just change 'someone' to a plural and yeah."
"Well, of course," Brandy says, amused. "It takes two of them."
"Ah, well, more than two," Skoomer corrects him. "Also, I designed a policy that actually doesn't do it in pairs."
Noodle lets out a gasp of horror and utter shock, eyes wide and hands cupped around her mouth. "Skoomer! You were in a *threesome?"*
Brandy laughs. Skoomer stares at her pointedly. "Ma'am, excuse me *what*? What are you *thinking?*"
Noodle's expression is one of purely innocent confusion.
"Noodle asking the real questions! Ah, Mango, you're up — let me grab some breakfast for you." Brandy turns to head back to cooking, occasionally letting out a chuckle. "A threesome…heh."
The two at the dining table turn to see Mango up from the basement with a blank expression.
"My disappointment is immeasurable and I am questioning my friendships," he states.
At this point, Noodle gives up on restraining herself and laughs whole-heartedly. "Bwa ha ha!"
Skoomer throws his hands up in the air, grumbling indecipherable noises.
Calming herself down, Noodle is still smiling widely as she teases Skoomer further. "I don't know, I just kinda assumed Skoomer got into a relationship to expose the other person — and then he said 'more than two', and I was like…" She squints suspiciously.
Skoomer crosses his arms defensively. "Sir, we didn't play undercover, it was elementary school."
"I don't know about that, Skoomer…"
"Even our counter-espionage didn't go that far!"
"Sus."
"Fine! *One* thing I did was uh…we only expelled one person in a pair, but the pair had to choose who got expelled." He smirks self-assuredly.
"Mate," Mango interjects, staring at Noodle, "'more than two'…are you cheating on me?"
Noodle looks at him sheepishly as she slowly slides down in her chair until only her eyes peek above the table. Mango's expression is one of pure devastation.
Skoomer chuckles. "Nah, but Noodle, wouldn't you agree that my policy is highly effective?" he says proudly. "The *speed* that couples just *disintegrated* amazed me at the time."
"Do you know what else is effective?" Mango directs a side-eye glance at Skoomer.
Skoomer tilts his head away and side-eyes him right back.
Mango smirks.
Skoomer dips his head.
Mango smirks harder.
Skoomer begins to sweat nervously.
To Noodle's dismay, any possible resolution to the tension between them is broken by Runo crashing down the stairs. "Yo guys, did you see the newspaper?" He shoves a finger at a tiny line on the newspaper clutched in his other hand. "Any action that damages ethic unity," he quotes. "WHAT THE FRESH FUCK!"

View File

@ -1,135 +0,0 @@
---
title: "The Birds on Language and Tea"
date: 2021-07-10
tags:
- birds
- unstagnation
---
**Summary:** The Birds discover Asia and its many variants of leaf juice. Waffle Bird is innocent.
<!-- more -->
---
The living room is a mess to Noodle Bird's eyes. Papers are strewn across the rug and hardwood floor with Runo lying face down and limbs splayed. There are no words to describe what must have happened.
"What happened to Runo? Why is he talking about cum?"
Runo's giggles are muffled from the floor. "Cum," he slowly enunciates.
Brandy Bird sighs from his corner, reaching down from his spinny chair to give Runo's head a solid bonk. "Bonk — go to horny jail."
Noodle's gaze flits over to Skoomer Bird, who shifts further into his desk by his open laptop as if to disassociate himself from Runo. "Well, uh…maybe he is high," he offers.
Between fits of laughter, Runo defends himself. "I'm not horny!" he protests. "It's just a *funny* word. Especially since CANAMOO used it in their official solutions…as a short form for 'cumulative'."
Noodle nods in understanding. "Oh…I see. That's the *worst abbreviation ever!"* She lapses into giggles along with Runo who pounds a fist on the rug.
"I know, right? Waffle is just perpetually horny though, I dunno what's up with her."
Brandy snorts. "Brand new phrase right there."
At the same time, from the mention of her name, Waffle pokes her head around the corner from the neighbouring room. "Woah, wait — what. What?" she demands.
Runo hits a button on his phone, waving away the matter. "It's okay, nobody cares. Also, Brandy, I don't think that's new — that's a very old sentence and I've heard it at least, like, seven times."
*"Uwu cumsy wumsy!"* Waffle's tinny but clearly cheerful voice blares through Runo's phone speaker.
"Bruh — now I've been called 'perpetually horny' *and* 'universally *moist*'," Waffle sniffs. "I don't know what is *up* with you people!"
Runo pushes himself into a sitting position, shrugging smoothly. "If it happens multiple times, it's probably you."
"No!" Waffle vehemently denies. "I think they are just *bad* because I am innocent!"
"Nobody innocent would innocently say 'uwu cumsy wumsy'," Runo points out. "You can't *do* that."
Waffle turns away from them and huffs an annoyed huff. "Well, I am gonna blame it on the lack of outside time messing with my brain!"
Skoomer decides to offer his own opinion on the matter. "Consider decreasing your caffeine overdose," he suggests helpfully.
"Come on, it was *one* coffee I bought yesterday," Waffle insists, "and I'm still not done."
"She doesn't like coffee, she said." Runo also reminds Skoomer. "It's boba."
Skoomer squints suspiciously at Waffle, who throws her hands up and gestures wildly at his accusations. "I literally drank half of the coffee and couldn't continue! Also I was really tired! And jittery. And tired!"
Skoomer considers his past experiences with Waffle. "You are perpetually jittery," he notes.
"Goddammit!"
Runo laughs. "I mean, coffee tastes *good* cold."
There is a noise of unadulterated disgust from Brandy's corner. He slowly turns and stares into the depths of Runo's soul with an unsatisfactory expression. "How do you expel the landlord?"
Waffle sticks her tongue out. "Coffee tastes terrible," she generalises. "No amount of sugar can cover how terrible coffee is. And it doesn't even work!"
This grave insult to their dignities goes unnoticed by both Brandy and Runo as they stare each other down. "What?" Runo demands. "Cold coffee is literally a thing you can buy at most places. You're just *uncultured* — not my problem."
"Like Bappachino or something?" Brandy asks.
"Moondollars!" Waffle interjects with the name of a popular coffee chain.
"I don't know coffee," Runo puts out as a disclaimer, palms held outward. "Just that cold coffee is good."
"Bruh," says Brandy. "Well, I guess that's fine — but I thought you meant hot coffee that went cold." The tension slowly dissipates as the misunderstanding is resolved.
"I mean, that's fine as well," Runo amends.
Waffle's eyes sparkle as she gasps when she remembers something amazing. "$1 iced coffee at McBirb's!"
The group only notices at this time that Skoomer has been shaking with visible anger in his seat, his fingers frozen above his keyboard.
"Calm down, green tea enjoyer," Runo faces away from him but turns back soon after. "Okay, I'm sorry — green tea is good as well…sometimes."
Skoomer returns to his work, appeased.
"Green tea good!" Waffle chirps. Noodle returns and cleanly bonks her from the side. "Yes! Black tea also good!"
"Green tea good!" Noodle agrees and leaves again.
"Orange pekoe can die in a hole!"
Runo makes an indescribable face.
"Literally *so bad!"* Waffle continues. "Worse than Earl Grey! And that already *sucks!"*
Skoomer sighs as he sips his own cup of tea. "Xihu Longjing for the win, by the way," he declares smugly.
Runo looks at him blankly. "The fuck is that?"
Skoomer shakes his head at Runo's lack of knowledge of Skoomer customs, heaving out truly the most disappointed of sighs, then launches into what would be a multi-minute explanation of its origin, benefits, and superior flavour and attributes.
He doesn't even reach ten seconds when Runo decides that he'd rather listen to something more interesting. "LMAO, okay."
Waffle flops backward onto the couch, arms out in either direction. "This cup looks so *thick*…" She points at the bubble tea clipart plastered on the ceiling of the room. "I want a thick cup of bubble tea…" Her whisper embodies longing rivalling that of the attraction between the sun and the Earth.
"It's just short," Runo dismisses.
"I want to buy some bubble tea right now…" Tears leak out of the poor girl's eyes as her bubble hopes and dreams lay crushed, malnourished, and emptied.
Skoomer notices this and doubles down. "Short…" he agrees, "like Waffle."
Waffle instantly jumps up, hair flying as she uses the full extent of her height to refute Skoomer. "No! Wrong!"
Runo shakes his head in mock disapproval. "Skoomer," he chides, "you're the only tall one here." He scooches a little closer. "We out*number* you…"
Skoomer trains his eyes on Runo, slowly rolling his spinny chair back an inch for each inch Runo approaches. "Bread!" he calls. "Save me!"
Bread Bird crashes down the stairs and freezes when greeted by the sight of Runo and Waffle staring hungrily at Skoomer. "What the fuck is going on."
Runo ignores the newcomer. "We will take your headphones first!" he declares.
"Take all his headphones!" Waffle joins in, flanking Skoomer's evacuation path. "He can't stop us!"
"He probably has enough for all of us — so rich!"
"N-no," Skoomer nervously denies, flicking his eyes occasionally to Bread in a plea for help.
Bread shakes his head sadly and salutes. "Skoomer, I cannot defend you in this scenario. Your YN-2000YN4 is too good."
"Nooo!"
Granted implicit permission, Waffle cheers and tackles Skoomer clear off of his chair, scrabbling for the headphones around his head.
Bread looks on sadly, but with no regrets.

View File

@ -1,143 +0,0 @@
---
title: "The Birds on Posterior Acoustics"
date: 2021-07-12
tags:
- birds
- unstagnation
---
**Summary:** The Birds are confronted with a dilemma that they must resolve. Curiosity of human flesh knows no bounds.
<!-- more -->
---
'Tis but a normal evening in the Bird household. Waffle Bird once again rants about the injustices of the education system by the dining table as Muffin Bird and Egg listen attentively. At the same time, Brandy Bird and Noodle Bird pretend to listen attentively while playing a racing game together on the TV.
Soup Bird doesn't bother pretending as he scribbles on papers for the upcoming school year.
"I'm so scared of accidentally unmuting in Frances's class," Waffle finishes, breathing hard as she concludes her latest rant. Muffin and Eggy nod along in complete agreement as Runo chuckles at his phone from the couch.
*"I'm so scared of accidentally unmuting in Frances'* ass." The surprise on Runo's face is completely fake as Waffle's mangled words pierce through even the racing game's music and Soup's focus on work.
There is silence except for the slowly quieting *vroom*s from the bots that overtake Brandy's and Noodle's cars.
Muffin is the first to speak up. "Runo," he says. "Kill yourself."
Soup snorts and is unable to hold in laughter until an urgent thought strikes him, a potential misunderstanding that must be resolved in his mind. "But…" he ponders, "how do you unmute…in someone's ass? How does that work?"
Attention shifts from Runo as now everyone focuses on Soup's incomprehensible question.
"Runo…" Brandy says slowly, "you can meme him."
Eggy thinks it over and comes to a conclusion. "How *doesn't* it work?" he asks quizzically but without elaboration.
"It doesn't make logical sense?" Soup's confusion is not shared by the other members in the household. "Like," he tries to explain, "the only way I can think of —"
What the only way Soup can think of will never be known as Eggy interrupts him. "Getting it *in* there might not make sense, but if it was already there, what's stopping you from unmuting?"
An understanding "ah" is followed by a nod from Soup as he follows along. "Ohh. So —"
"What the fuck." Runo's sentiment is completely agreed with by everyone else as Eggy and Soup continue to discuss the merits of an electronic device in the human body.
Soup continues, "— there means that *Waffle* is in *Frances'* ass, and then…she talks?"
As the mental image slowly dawns upon everyone in the room to varying degrees of disgust, Eggy's expression makes it clear he's suddenly changed his mind. "I advise you stop thinking about it."
Noodle clutches her head, shaking it frantically, her controller having dropped to the ground. Her eyes attempt to roll into the back of her head but fail. "Oh my god please delete this from my eyes — i can't — I just imagined it, now it's stuck…"
"I mean…good acoustics?" Waffle's expression is frozen in a gentle smile as she tries to wrap and simultaneously unwrap the idea around her head. "What even…"
"Can I censor Soup for the good of our sanity?" Brandy asks everyone.
"No." Eggy makes it seem like they're having a perfectly normal discussion.
"Yes," Brandy insists.
"What the fuck do you mean by 'acoustics'?" Muffin says accusingly after finally letting the conversation sink in, tempting further discussion.
"It's a small enclosed space," Eggy reminds him in a sensible tone, receiving an incredulous face in return.
"But who would be listening?" Morbid curiosity fills Noodle's voice as she dares to go further. Her question goes unanswered, however, as the others pile on to correct Eggy's acoustic sense.
"As an audiophile, I feel offended." The indignation of Muffin's declaration is unparalleled. He opens his mouth to continue, but —
"But it's like a tube?" Soup's innocent question leaves Muffin's mouth hanging open.
"True," Eggy concedes. "There might be an echo."
"Censor Soup, *right now*," Muffin demands, ripping off a strip of duct tape.
"It's the large intestine, right?" Soup carries on, oblivious to potential death threats behind him.
"Yeah."
The tubular description helps Waffle realise something. "Like, you know how practising your instrument in the washroom makes it, like, sound okay? Decently?"
"But, like," Soup starts, "I don't think sound is very reflective on flesh."
"I dunno," Waffle frowns, thinking it over. "I practised in the bathroom with my friend once. Practised an instrumental, I mean."
"Human tissue is soft and absorbs stuff really easily," Eggy adds helpfully.
The sheer urge to provide concrete facts stalls Muffin long enough to prevent him from performing violent actions on Soup for the time being. "It is in fact not," he confirms, then steps menacingly closer. "I call upon the pope to strike Soup with lightning."
"Please do," Waffle groans, face in palm once she realises she's meaningfully taking part in the discussion. She joins the others in being unable to turn away but desiring to be as far removed as possible.
"Also, there are other substances in the large intestine that absorb the sound," Soup realises.
Muffin glowers at him.
"…So the acoustics aren't good probably," Eggy concludes, nodding to himself.
Unable to help herself, Waffle reluctantly returns to the shining pillar that is Soup slowly reasoning in the moat of implications of their current topic. "Okay, so many not good acoustics."
"Yeah." Soup nods in satisfaction. "URK —" In a bout of desperation to stop him from ruining the others' evening, Muffin takes it upon himself to strangle Soup from behind.
"Soup," he says sadly, "please die in a hole."
"Maybe," Waffle agrees, looking on but not moving. "LOL!"
Using the underside of his chair as leverage, Soup in a moment of clarity forces his head forward and grips Muffin's arms to throw him up and over. Surprised, Muffin's grip tightens and Soup follows along as they spin twice together before collapsing into a heap on the floor.
Inadvertently releasing his neck, Muffin glares angrily but frozen in place as Soup pins him down with his knees and an arm, the other being used to rub his throat. "I don't know… It doesn't make much sense. Okay," he nods at Muffin, "I'm high. I should stop."
Muffin sighs in relief as both the topic of conversation ends and he's released from the Soup's restraints. "Did she ever say that she spoke in his ass?" he wonders.
Muffin's duct tape he dropped is picked up by Brandy. He turns it over in his hands, examining it. "Am I justified in censoring Soup if he keeps talking about this?"
"Yes."
"Soup's EE —" Muffin jokes, brushing himself off. "An acoustic study of sound fields in the ass of Mr. Frances."
"Get Frances to supervise," Brandy adds, unable to resist.
A shiver runs through Soup as he considers this. "…Gonna get *roasted*. Hm, actually, what do you think if I — Mmph!"
Any of Soup's further inquiries are locked in his mind as Brandy finally slaps the duct tape around his mouth to a standing ovation.
------
Extra:
"Shit." Soup Bird buries his head in his hands. "Agggh…"
"What is it?" Noodle Bird leans over to see Soup Bird's screen, then winces as she reads the text. "Ah, you got *him* as your mentor? RIP — What topic are you doing?" She turns her eyes to the subject and topic submitted for approval, and her eyes widen.
"Ah." Noodle bursts out laughing, falling backward into her chair.
Soup groans, rubbing his head in pain and defeat as his eyes rescan the introductory message from his Extended Essay mentor.
*Hi Soup,*
*I took a look at your topic and found it quite interesting. However, you should consider expanding the scope of your experiment to asses in general.*
*Speaking of people in front of your computer, you might want to recruit some others so that you have a wide range of data over multiple repeats. You also would have to provide sufficient controls such as diet and routine, ensuring that the substances in each of your research locations are clearly known, or risk losing all marks for not having a proper methodology in your experiment.*
*I've already approved and locked in your topic. Please let me know of your research question and we can further discuss your research and methodology at our first formal meeting tomorrow.*
*Mr. Frances*

View File

@ -1,110 +0,0 @@
---
title: "The Birds on Waffle Supremacy"
date: 2021-11-01
tags:
- birds
- unstagnation
- featured
---
**Summary:** The Birds enter a debate at school over the supremacy of waffles over pancakes. Obviously, one of them is the better food, but it's up to them to prove it.
<!-- more -->
---
In the student-lined halls of Vaybiew Secondary School, a lone poster hangs on a bulletin board, its top-right corner limply drooping in front of it. Colours faded from hours of abuse, a singular golden arrow labelled "waffle supremacy" directs any offendees to room 233.
Let us head into the room to observe the intellectual debate occurring between the factions.
Room 233 is styled as a traditional court. Dimly lit, intricately designed mahogany furnishes the room, from the chairs to the desks to the court podiums that are illuminated by spotlights. A substantial audience listens to the four people debating, raptured by the engaging arguments flying across the room.
"The only reason Egg hates pancakes," Noodle Bird is declaring, pounding a fist on the podium before her, "is because there are eggs in pancakes. I'm gonna cook your entire family, you twat."
Egg of the waffle camp glares at her.
The spotlight suddenly switches to Bean Bird as she slams the objection buzzer. "There are eggs in waffles too!" A pause. "But waffles are better than pancakes," she adds.
Noodle recoils at this new evidence, staggering back as if she's been shot. She grips her podium tighter.
Emboldened by this turn of events, Bean goes on the offensive. "The cubes are a better vessel for syrup!" she fires. "You're just bland, Noodle."
Noodle's argument is in shambles and she needs a moment to collect her thoughts — a moment taken by the audience to lean more in favour of the waffle camp.
"No! Pancakes are better!" Noodle racks her brain for any argument while she quickly distracts the audience.
Bean smirks knowingly, sensing victory. "Imagine being so wrong."
Noodle sighs. It's time for their secret weapon — a shame to lose it so early on, though. She nods almost imperceptibly to a shadowy figure at the back of the courtroom.
Coloured confetti is shot from both sides behind Noodle while a large banner with the pancake emblem unfurls from the ceiling as she spreads her arms, beaming. "Pancakes!" she announces righteously.
Bean can only stare at the effective tactic that earns applause from the audience. "Noodle," she says sadly, shaking her head disappointedly.
Sensing that the waffle camp is losing control of the narrative, Egg jumps in desperately to provide reinforcement behind Bean. "Pancakes," he says loudly, quieting the applause, "are just slabs of *cooked dough*. Waffles are elegantly shaped for optimum tastiness."
In front of their emblem, the pancake faction regains their momentum. "No," Noodle retorts, "y'all are so cubed. Imagine not being round!"
"Bruh, what the hell." Runo as the moderator makes a disgusted face at the image of a waffle filled with syrup. "Are you supposed to put that much syrup?"
Noodle takes the opportunity, signaling again to her spy in the audience. "Pancakes have *curves!"* Jets of confetti again fly behind her at the last word. The audience cheers as celebratory music plays, and some of them are already holding up their vote for pancakes.
"Waffles also have curves!" Egg interjects, looking to steal the spotlight.
Runo frowns. "Wait, so you think they have sex appeal?" The cheering, music, and atmosphere in the room immediately falls apart, to be filled with awkward silence.
"Where'd you get that from?" Egg finally asks.
"Isn't that what 'curves' means?"
"No," Bean recovers, answering Runo's first question after a delay. "Waffles have more sex appeal because…cubes…you can…"
"Hol' up," someone in the audience says, to universal agreement.
The debate mood is completely stifled until Egg fiddles with the projector enough to beam an image of a glorious syrup-filled waffle topped with butter and cream onto the debate screen. "The beautiful waffle!" he declares, gesturing at the golden dish. The music is restored and the audience cheers — some of them even change their vote.
"It's super sexy — I'm getting hard already!" Waffle Bird pokes her head out from backstage, to general laughter. "Hi! Help!"
"That's so hot, I'm gonna cum," Bean swoons, starry-eyed, her hands clasped in admiration.
Noodle taps the microphone, creating feedback that reverberates around the room, restoring balance. Satisfied that she is the centre of attention, she begins attacking the golden food. "Can squares roll around?" She takes the microphone out of its holder and steps in front of the podium. "No, I don't think so. Circle supremacy!" Her fist pumped in the air at the last line, a whole tub of confetti pours out behind the curtains, which gets the audience up and excited again. The waffle camp frowns.
"Waffles roll better than pancakes do," Egg corrects Noodle. "They have thicker edges." To reinforce his point, he puts a second image on the screen — a stack of perfectly browned pancakes topped with a square of butter dripping with syrup, outlining their limpness and impractical rollability. "Boring pancake."
"Right?" Bean turns to the audience, nodding. The audience nods along.
"What do you mean — the pancake looks beautiful!" Noodle protests.
Waffle takes this time to poke her head out again from backstage, stepping firmly on the side of the waffle camp. She glances at the screen and shivers. "Ew… my pp just shriveled up." Noodle gapes at her as the audience laughs.
"Pancakes will flop over," Egg says. The debate has returned to normal and the two parties are once again at each other's throats in a normal fashion.
"Like my pp when I see one," Waffle adds.
"They double as wagon wheels!" Bean concludes. The pancake camp is once again in shambles. Noodle gestures at the moderator for their last secret weapon.
Runo from his moderator chair, quieting the audience. To the waffle camp's dismay, he strides dramatically to the pancake podium. There is a sharp gasp from someone in the crowd. "I personally think…" pause for dramatic effect, "*pancakes* are better because they have more *fluff*."
This abdication of responsibility has the waffle team on full offensive, their rage and passion for waffles on full display.
"Nah," Bean dismisses.
"But it feels *dry* in your mouth!" Waffle brushes him aside.
"Unless you consume them a millisecond after they're cooked," Bean agrees. "They flop down."
"Wha —" The pancake faction clearly expected a bigger reaction, and Runo scrambles to counter. "Wait, what do you mean, 'flop'? I have never heard of this."
"They compress," Bean says matter-of-factly.
"Wait, really?" It's almost as if Runo is a paid actor for the pancake camp by how surprised he is at this nonsense.
"Because the heat and steam hold them up."
"They *deflate,* yeah!" Waffle interjects.
"Right!" Bean nods along. Right on cue, the screen somehow falls off with the pancake still on it and limply folds into itself like a bathroom towel.
"I've heard enough." The judge at the other end hammers his gavel, and all debate stops. "I hereby declare — that the waffle camp has won this debate! This meeting is now adjourned."
"You're just a grid lover — that's all you'll ever be," Noodle grumbles as she steps off the darkened stage.

View File

@ -1,100 +0,0 @@
---
title: "A is for Alcohol and IAs"
date: 2022-10-24
tags:
- birds
- unstagnation
- featured
---
**Summary:** Bean Bird and Noodle Bird enjoy a chat together on a quiet night slaving away before they leave in the summer. Bean wishes she had a stronger drink.
<!-- more -->
---
Quiet keys clack and pencils scribble as the Bird family finds itself working, scrambling to tie up loose ends in their final months together. Their upcoming move to Universe City weighs upon all of their minds. There is no room for frivolous discussion, no time for anything but the epitome of productivity.
"Guys, I hate my AIF. With a *passion*." Bean Bird sets down a half-filled mug and she glares all around, slamming her hands on the table. "AIF sucks *ass*. But, like, not good ass."
Noodle Bird blinks, her attention suddenly lifted from her 50k-word real person fic. "Oh."
Bean continues her tirade, invigorated. "Poopy crusty ass! Like, straight white male unwashed ass." Sighing, she lays her head down on her arm for only a second before she sits upright again, strangling thin air with her bare hands. "I'm fucking *losing my mind* *I hate this IA so much."*
"Why?" For the life of her, Noodle can't imagine what difficulties one could possibly have with the Internal Assessment. The soul-wrenching dread of the IA has avoided her completely.
"I never thought I had to listen to a British guy appealing to the crowds to work with the *USSR*." She peeks at the video between her fingers like it's out to doom her and her alone. "NOOOOOO!"
"Oh, god," Noodle says sadly. There is nothing she can do. Bean must walk her own path down this chosen path, or die trying.
"It's okay," Egg assures her, with the confidence of one who has yet to experience true suffering. "Get a level 5 and get it over with."
"I *can't!"* Bean bemoans. "I did so much research! There are *so many things* in my brain!" She grabs the mug and chugs furiously. "Why won't Wroscell let me get drunk and spew out all the data to him?"
"Bro," Noodle says, patting her, "I was literally procrastinating on researching my IA until, like, yesterday! And here I am!" — she gestures at her computer, now filled with lines upon lines of words no one could possibly know was a 55k-word real person fic.
Bean thumbs through a textbook, gazing at page after page of notes. "The sticky notes in my books are so colourful…" she says wistfully, her eyes lighting up, "…and so *toxic!"*
"Eat it! Maybe it'll taste sweet!" Noodle says, eyeing the textbook stuffed with solid, packed handwriting and the tantalising aroma of adhesive.
Bean leans in beside Noodle. "I'm gonna eat you," she whispers.
"I…don't think I'm very delicious." A chair subtly scooches away.
Returning to her mug, Bean cradles it once again and drinks deeply, leaning back against her chair. She sighs. "Rose-flavoured tea is disgusting."
"I agree."
"I have to pretend I like it because my mother bought it for me. And it's like, three dollars." Bean makes a face as she sips at her cup, staring longingly into it as if hoping it were something else.
Sensing the family crisis to be just about over, Egg chimes in, "Human meat tastes like chicken." He looks as if he's been dying to join the discussion the whole time.
"Wrong," Bean scoffs. "It tastes like pork."
Egg is firmly removed from the conversation from sheer embarrassment. "Yeah, that," he says, slinking away, never to be seen again.
A thought occurs to Bean — she taps her chin thoughtfully. "Human flesh is commonly called 'long pig'. And calamari is often pig anus."
"What."
"Yuh," Bean nods, "I have really weird taste in podcasts."
Noodle seriously considers the topic. "We *are* technically longer than pigs…most of us."
"Nood you're not," Bean frowns. "You're tiny!" She notices the glare sent her way and her expression softens pityingly. "I love you, Noodle, but you're *teeny tiny*."
Bean's sincerity moves Noodle's heart and she deflates. "I know… I love you too."
"I would drink all the rose tea if it meant you didn't have to…" Bean swoons, occasionally stopping to sip out of her mug. "It's okay, you'll grow."
Noodle looks up. She knows.
Evidently, Soup also wanted to jump in earlier but was dissuaded by Egg's shutdown. Now he takes his opportunity. "Any…cannibals in the chat?"
Soup is utterly ignored as Bean continues her musings with Noodle. "I think a lack of gravity in heaven elongates the joints." She laughs. "See what I did there?"
Soup laughs along.
Bean shakes her head. "I swear to god, the day before IAs are due, I'm just delirious." As if to illustrate her point, her face plants into her keyboard.
"…IA is due tomorrow?" Soup ventures.
Bean turns her head to face him, eyes bleary and hair falling in front of her face. "Do you have any idea how many times I stayed up until four in the morning to finish my chem IA?" She pushes herself up. "And it wasn't even the day before the IA was due either! It was like, three days in advance!" She grabs another mug and chugs the whole thing down. "I just stressed myself out and dragged Snac with me to explain hydrogen bonding sites in hydrolysed sugar — that's when I learned that you can physically break bonds with hands."
To demonstrate, Bean mimes a karate chop and smashes the wooden table. Various sheets of paper fly into the air while laptops fly to the ground.
Noodle stares. "Huh. That's cool."
Soup wordlessly picks up his cracked laptop and leaves to cry in a corner.
Bean doesn't notice. "I feel like half the things I say here today can be in an archive." She shrugs. "I dunno, I feel delirious."
Dusting off her screen, Noodle places her laptop on her lap and continues to work away at her 60k word real person fic."Nothing like learning good ol' hydrogen bonding to have a great bonding experience at 4 am."
Bean nods, swaying in her chair. "I got drunk once off peach soju and this was the same experience, except I didn't have a *history IA* to write," she murmurs.
"It's the stress plus adrenaline! But it's fun!"
Bean's eyes droop. "So. Much. Fun." With her last words, Bean Bird falls out of her chair and crashes on the ground, never to be woken again…
…until the next morning, when she realises that her IA is due tomorrow and she still has to write two body paragraphs and a conclusion.

View File

@ -1,97 +0,0 @@
---
title: "High Crimes and Misdemeanours"
date: 2022-10-28
tags:
- birds
- unstagnation
---
**Summary:** An egg catches the Birds in a dastardly scheme. They must take their revenge by public humiliation. There will be no escape.
<!-- more -->
---
An egg stands up on the stage by the corner of the road, adjusting his tie. He's ready to campaign. It'll be the biggest advance in politics in the history of politics. It'll be the crowning achievement of his whole career. His magnum opus.
By the end of the day, he *will* have passed his referendum.
"If you think poutine is great, sign here!"
The masses turn as one. For one time-stopping moment, the egg knows he has their attention, and he intends to use it. They see nothing but an innocent man in a tie, gesturing at a sheet of paper on the board. Several neon arrows flash to make it extra clear.
Indeed, it does say, *Poutine appreciation board!*
Noodle Bird immediately brandishes her pen and signs the sheet.
"Yes! Poutine is so *good!"* Soup wastes no time, pushing through the crowd to have his voice heard.
"*Yes!*" Bread Bird practically throws himself in front of the paper to put his name down.
Other passersby stop to sign their support for the rich food. The egg smiles. All according to plan.
"Fantastic." Once he reaches seven signatures, it's over. He studies the list of names, smirking. They don't know.
Slowly, in front of the star-struck poutine fans, the egg peels off the tape on his sheet to reveal the actual title of the signature sheet:
*IB appreciation board!*
Instantly, the crowd roars in outrage. The sight of their dedication to the best food ever being turned to an advertisement for some snooty high school program drives them into a frenzy.
"BAN HIM!"
"THIS TREACHERY!"
The egg takes a step back, wiping sweat off of his forehead. Perhaps he should have secured himself before unveiling his scam political maneuver.
"Yo yo yo *what!* I got *scammed!"* Soup's anger is palpable and it rouses the crowd to further raise their pitchforks. "I can prove my innocence though!" He waves a picture of the paper from before the egg turned traitor. "I said poutine!"
Faced with unmistakably the truth, people begin to settle down, knowing that this egg will be made a fool of in the news. Unfortunately for him, he has yet to leave the frying pan yet. "But this egg," Soup turns to face him, eyes blazing. "He needs to stand on *trial."*
"We must stand him on trial!" Bread cheers.
"For high crimes!"
"Yes!" Soup roars. There is nothing but passion now, passion and hatred for the egg who dared to bait their beloved food.
"I wanna be the judge, jury, *and* executioner!" Noodle shouts.
"This is unprecedented," Soup declares, spreading his arms. Somehow, he's made it to the stage and has found a soapbox to stand on.
"We must make a witch trial for his crimes!" Bread joins him on the stage. "I propose we open a court!" Someone lugs a judge's desk in front of him as he and Soup put on their judicial gowns.
Noodle raises her hand. "I propose scrambled eggs!"
The egg pales.
"I second!" says Brandy.
"Yes," Soup nods, considering the motion. "That's good…but isn't boiling him better?"
The egg wrinkles his nose. "Ew. Boiled egg."
"Scramble him with ketchup…" Bread muses, stroking his fake white beard. Almost immediately, the enthusiasm becomes mixed.
"What the fuck?" Noodle questions Bread's age. "Who puts ketchup on scrambled eggs?"
Bread tries to get the trial back on track, but somehow persistent, no-wrong-answer controversies must take precedent.
The egg sees an opportunity. He squints knowingly, waiting for his moment to strike.
"Yes!" Brandy waves his arms harder. "Scrambled eggs and ketchup are good!"
"And pepper!" the egg helpfully adds. "IKEA breakfast." The egg's carefully crafted statement suddenly turns the people's attention away. Bread glares at him, about to strike the gavel for order, but to his shock, the small hammer suddenly disappears. The chattering among the people grows.
"Oh, okay." Noodle nods. "Should we add salt?"
Much to his horror, Bread finds himself thinking about the concept. "IKEA meatballs?" he gasps, realising the egg's plan. He shakes his head rapidly to rid himself of the tangent. Seeing the audience's anger begin to decline, Bread comes to a decision. "We hold another trial!" he declares, trying to speak over everyone else.
It's no use. The unified front has broken down, killed by infighting and squabbling over meaningless, irrelevant topics. Already his judge's chair and gown have been returned to their original owners.
The egg's injustice will go unpunished. He confidently strides away, knowing that there is no one who can stop him now. He holds power now that he's no longer the centre of attention.
Bread desperately reaches out, trying to rip the signature sheet out of the egg's hand, but someone from the crowd pulls him back. As he's questioned about drugs and integration, he looks helplessly to the egg who ruined them all.
Bread clenches his fist. He will not forget this. One day, he will have his revenge. His heart has hardened. From this day onward, no longer will he sign any such "poutine appreciation board". No longer will he trust others so unconditionally. The egg has done something that he will never forget, destroyed something inside Bread that will never return.
A single tear falls from the side of his cheek.

View File

@ -1,117 +0,0 @@
---
title: "Soup's Egirl Discord Status"
date: 2022-10-25
tags:
- birds
- unstagnation
---
**Summary:** Mango reveals a hidden secret of Soup's past. The Birds listen in and offer their own opinions. Runo wants more.
<!-- more -->
---
Soup sits in the Bird residence living room, once again playing League. All is well in the world.
Mango taps his shoulder behind him. "Did you find our Clash team yet?"
"Monkeys," Runo sniffs haughtily at the game as he passes by.
Mango pulls out a seat beside Soup. "Ask your e-girls," he insists. "You should ask."
"*Fiiiine.* But I don't think they know you too well…"
"What's her name?" Mango taps his chin, racking his brain to remember the list. "Christina?"
"Most e-girls are too great." *For you* stays unsaid. Runo comes along again and pauses.
"Yeah, I don't care." Mango waves away the matter. "You should ask the Bronze I one, to lower our MMR." He spreads his hand, wiggling his eyebrows. "Genius?"
Runo is frozen at this newest revelation to his life.
"Okay," Soup chuckles, "let me go ask."
Finally over his shock, Runo manages to force his mouth open enough to express his disbelief. "There are *multiple?*"
"Uh…" Soup's eyes dart around shiftily.
"Oh," Mango snorts, "multiple is an *understatement*."
"Uh oh," Runo says, squinting at Soup.
All eyes are on him now. There is no opportunity to escape. All of the exits are conveniently blocked off, and already more people are entering the living room with their own work. Did they hear? Soup briefly considers the amount of space available underground to store several bodies.
In the end, he decides to take the politician approach: deflect, gaslight, and get outraged. "WHAT?"
"Like, you count them in dozens! Wrong unit, mate." Heedless of the inner turmoil going on inside Soup's head, Mango shakes his head as he continues to sabotage his friend.
Runo squints harder.
"Zero dozens!" Soup tries to shut it down, but it's too late now.
"A platoon!" Muffin suggests.
Mango's eyes light up. "A concentration camp! Hmm…"
Muffin eyes him knowingly. "HMMM…"
Soup makes a general noise of disagreement.
Noodle Bird joins the group. "I have a folder just for his e-girls," she taunts, waving a manila envelope.
"What the fuck?" Hungrily eying the envelope, Runo dashes after Noodle who bolts away, cackling as she clutches it to her chest. "I'm kidding! The folder is just for his girl friends!"
"WHAT?" Soup tries outrage again, sure it will work this time.
Evidently not.
"Yeah! Like, he has like, at least 20 —" Before Mango can go on, Soup decides that one casualty is acceptable for the cost and begins to strangle him. "— 15! 15 egirls." Soup releases his neck. "At least."Mango dodges around Soup's attempt to slice fruit, smirking. "And it's increasing every day! Poggers!"
"Exponentially?" Muffin leans in.
"No sir. *Factorial."* Mango winks.
"Oh, *shit*."
Runo returns only to hear that and immediately prostrate himself at Soup's feet, inadvertently restraining him from commiting a crime.
"True!" Mango joins him, the two kneeling and bowing to their hero.
Slightly flustered by the sudden change in attitude, Soup tones down his murder tendencies and drops his knife. "Um…what? This is false. I know, like, *negative* girls."
"That's the most bullshit statement I have *ever* heard." There's no keeping secrets when Mango's around.
"I thought you had a girlfriend," Runo frowns.
It pains Soup to admit it, but it's the only way to counteract the slander. "I'm…single right now."
Rain starts to pour outside like the pathetic fallacy it is. The fanatic light in Runo's eyes fades away. "Wait, really? Um…oof?"
"False!" Mango declares as the sun pokes through the clouds. "I'm *literally* your boyfriend!" He spreads his arms, beaming like the rainbow forming outside.
"True!" Soup returns the embrace.
Runo turns away, uninterested. "F," he says flatly. "Wait..."
Muffin joins this celebration of LGBT rights by playing a kazoo.
"No, he's not!" Runo points an accusing finger at the duo. "I didn't get the joke! Fuck!"
Mango sighs theatrically, caressing Soup's face with his hand, gazing longingly into his eyes. He's drowning in the wave of beauty of those pearlescent orbs. A sea of feeling, of affection, of love, all of it wells up inside him. An **emocean.**
"If you're gonna break up with me," he says sadly, "at least do it in private."
"Wait, he *is!*" Assuaged by the display of true love, Runo falls to his knees to repent. Mango bows.
Soup steps back and laughs. "Anyways, Mango, I don't really have many 'e-girls' to ask. I asked Christina, but I'm pretty sure her answer is going to be no."
"Ask *what*?" Runo interjects.
"I'm confused too." The humble Brandy wears a befuddled expression as he stands in the doorway, freshly arriving into the conversation of e-girls.
"I don't," Soup brushes the matter away. "Mango asked."
And that was the end of that conversation. Mango never brought up the topic again, Runo moved on to complaining about politics, and Soup never had to share his list of e-girl friends.
All was well.

View File

@ -1,196 +0,0 @@
---
title: "Miraidon the Dongo"
date: 2024-11-14
tags:
- birds
- unstagnation
- featured
---
![Dongo is love. Dongo is life.](/dongo-party.png)
<!-- more -->
The boy falls back against his couch, dropping his controller in his lap. The video game on his TV blares cheerful adventurous music. "The game is sooooo slow."
"Fuck," the girl says over video chat. "You're on emulator, though. 2.5x it?"
"The computer isn't quite powerful enough."
"L. Ratio. Cringe PC gamer."
The boy turns his attention back to the game, adding a new monster to his current party. "Dongo disagrees. Do you have a Dongo? Exactly."
On the other side of the world, the girl has little to say to that. "Dongo isn't _real,_ he's _not\!"_
"Dongo is life."
"It's time to snap back to reality — car doggo is a myth."
"I will write Dongo fanfic. He will be real."
She makes a face. "I'm so sorry — this sounds like the biggest innuendo…"
He nods absently. "Hm, hm, yes, sex the Dongo."
She pauses. _"What?"_
He frowns. "Absolutely not. Dongo is too precious."
Her jaw drops. "You're the one who said to sex it\! Every time I settle down to play Pokémon, I end up playing League instead. I think I've been corrupted by the impure." She shudders.
"Oh, no\! League is not fun."
"But it is," she says sadly.
"It's boring\! You click things, it's barely real time nor turn-based. It's as if tower defense and Civ did a Dongo."
She takes a moment to parse the mystery word. "Why is it an _adjective_ now?"
"Dongo disapproves." He shakes his head.
"Oh, yeah? Well, I've spoken to Dongo and he said he doesn't like you." She sticks her tongue out, folds her arms, and turns away.
"Lies\!" he cries. "You don't have Dongo. Dongo is _mine\!"_
"I have him right here," she gloats, peeking off-camera. "He's right in front of me right now. He just doesn't want to see you."
"Let's see 'em."
"But he doesn't want to see you."
"Pics or it didn't happen."
Some shuffling from her background. "Every time I pull out my camera, he hides behind the couch and mutters, 'no'. And he can talk. And I'd know because I've talked to him."
"I think you met an impostor Dongo…" he starts, concerned.
"I think _you_ met an impostor Dongo," she counters.
"…because Pokémon can't talk, duh?" He sounds befuddled.
"Not to you," she says smugly. She pauses. "I feel like such a kid…ahh…"
"Embrace it," he encourages. "Embrace the Dongo."
"…I'd like to remind you of the innuendo you set up not 40 seconds ago."
"Well, it was an…accident."
"Dongo disapproves."
"No, _your_ Dongo disapproves."
"It's not worth arguing with a Dongo flat earther, so I'll agree to disagree."
"I think you should get your head checked out because Dongo isn't real? He's from this Pokémon game."
_"What?"_ she screeches. "No — heathen — _hypocrite\!_ I am _awake_, I am _alive_, I am _correct\!"_
"Dongo disagrees."
"Dongo is _right here,_ I —" Some shuffling. She sounds defeated. "I can't win." One last stand. "If he's real, then I'm right and you're wrong. But if he's fake you're right but you're right because you heard from Dongo."
"Touch the Dongo," he eggs. A simple test. "I dare you."
"…What the _fuck_ is going on? I'm not _coherent_ enough for this?" She sounds like she's in hysterics.
"More like you're _too_ coherent for this. I'm making innuendo jokes, obviously. Can't you tell? Dong get it?"
_"AHHHHHHHHHHH\!"_ The sound of a head smashing a wall comes through the speaker.
"No. No, I refuse to accept this. Dongo is — one: real, two: not real, three: an innuendo, four: I need a psych eval, five: _you_ need a psych eval."
He frowns. "Three of those criteria contradict each other."
"…I am _not prepared_ for this multiple choice test."
"You see, if I need an eval, then Dongo must not be not real nor real — and simultaneously you don't need an eval because Dongo is therefore real and not real. This is according to Dongo over here."
Silence.
"Dongo says hi…" he adds.
A pause. "I am going to lose my mind."
"…in Dongonese."
"What the _fuck_ is _Dongonese?_ You said Pokémon can't talk\!"
"They can — what do you mean? Pikachu talks all the time."
A slow realisation. "I'm being fucking gaslit\!"
"Can't you hear them? They make all sorts of sounds in the game."
She falls over. She considers whether to go batshit crazy or lie on the ground. She decides to lie on the ground.
"They even talk to each other," he continues. "Here, lemme find a pic."
A ping. With dread in her heart, she slides down the notification.
![](/dongo-gaslight.jpg)
It's a picture of a Victorian lamp. Its flame cheerfully dances, burning the gas. "Shut the fuck up."
"Stare into it," he encourages.
Against her will, her eyes track the still image. "Oh," she realises.
"You can hear whispers."
"_Oh._ I can _see,"_ she whispers.
" 'Dongo dong dong dongo.' "
"I can _hear_ it. The voices. Of _Dongo_. They're telling me…they're telling me to go see a therapist." She pushes herself up with her elbows.
"Dongo agrees."
"_No\!"_ She is fed up. She will not let him take it back from her. "Let him speak for _himself."_
" 'Cause that's a gas light, y'know. It's not good for your brain. Has fumes and all that."
She looks back to the picture with horror in her eyes. "I feel like I'm forgetting how to communicate like a functional human being," she says.
"It's okay\! Dongo feels that way too."
She closes her eyes. "Maybe I'll wake up tomorrow and this will all have been a big, elaborate dream."
"Yep."
"_He's. Not. Real."_
"That's right. He can't hurt you."
Something in that resonates with her. "H-he can't hurt me," she says, dazed. Then more confidently, "He can't hurt me." She nods. "The voices are gone."
"Good."
She takes a deep breath. "I am about to have a psychotic break on the bathroom floor at 1:47 AM over hearing the voices of Miraidon, box legendary of hit new Pokémon game Violet, and maybe this other nerd's voice, I'm not sure."
"While you're at it, say hi to Dongo for me."
"I'll tell him you hate him."
This shakes him up. His tone changes. "Noooo\!" More confidence. She pulls the middle finger to no one in particular. But then, "That's okay. I have the real Dongo."
She refuses to be sucked into his insanity. "I'm _not_ starting this again, I'm not\!"
He sighs. It must have been a long night for him, too. "I'd agree, actually."
"Ha\! I can finally win\!"
"I've run out of circles to Dongo," he concedes.
The sense of victory makes it easier for her to assert her place in reality. "That doesn't even make sense\!"
"So? Does Dongo make sense? No."
"The message I'm taking away from this conversation is that I'm always right and you're always wrong and Schrodinger's Dongo."
"Sounds about right." A pause. "Good night\!"
"Night\!"
!["Don-dongo. Dongodon dong dongodon?"](dongo.jpg)

23
create Executable file
View File

@ -0,0 +1,23 @@
#/bin/bash
TITLE=$@
TITLEF=$(echo $TITLE | tr " " "-")
YEAR=$(date +"%Y")
MONTH=$(date +"%m")
mkdir -p "src/posts/$YEAR/$MONTH"
FILENAME="src/posts/$YEAR/$MONTH/$TITLEF.md"
cat <<EOF > $FILENAME
---
title: "$TITLE"
date: "$(date '+%Y-%m-%d')"
tags:
-
---
<!-- excerpt -->
EOF
echo "Created new post at $FILENAME"

View File

@ -1,7 +0,0 @@
export const navItems = [
{ href: "/#about", title: "About" },
{ href: "/blog", title: "Blog" },
{ href: "/stories", title: "Stories" },
];
export default navItems;

View File

@ -1,129 +0,0 @@
export type Language =
| "python"
| "javascript"
| "java"
| "typescript"
| "vue"
| "react"
| "markdown"
| "flutter"
| "android"
| "rust"
| "golang";
export interface Project {
name: string;
href: string;
img?: string;
description?: string;
longDescription?: string;
langs: Language[];
license?: "AGPL-3.0" | "GPL-3.0" | "MIT" | "LGPL-3.0";
type: "web" | "tool" | "embedded" | "service";
}
export const projects: Project[] = [
{
name: "Mandown",
href: "https://github.com/potatoeggy/mandown",
description:
"A comic downloader and converter to CBZ / EPUB / PDF for my Kobo.",
longDescription: "Available via CLI and a Qt GUI!",
langs: ["python"],
license: "AGPL-3.0",
img: "mandown.webp",
type: "tool",
},
{
name: "Noveldown",
href: "https://github.com/potatoeggy/noveldown",
langs: ["python"],
license: "LGPL-3.0",
description:
"A webnovel downloader and EPUB converter for my Kobo, with lots of metadata!",
longDescription: "Heavily borrows Mandown's design.",
type: "tool",
},
{
name: "Jeopardy",
href: "https://github.com/potatoeggy/jeopardy",
img: "jeopardy.webp",
langs: ["typescript", "vue"],
license: "AGPL-3.0",
description: "Kahoot-inspired Jeopardy! game, including Final Jeopardy!",
longDescription: "Created for Bayview's Computer Club.",
type: "web",
},
{
name: "Primoprod",
href: "https://github.com/potatoeggy/primoprod",
img: "primoprod.webp",
langs: ["typescript", "vue"],
license: "AGPL-3.0",
description:
"A game simulator to increase productivity with quests and gambling.",
longDescription: "My first project with a JS framework!",
type: "web",
},
{
name: "PillowⓇ",
href: "https://github.com/potatoeggy/ece198",
description:
"A water quality statistics aggregator written for the STM32 microcontroller with a display and keypad.",
langs: ["rust"],
license: "GPL-3.0",
type: "embedded",
img: "pillow.webp",
},
{
name: "Napbot",
href: "https://github.com/potatoeggy/napbot",
langs: ["python"],
license: "AGPL-3.0",
description:
"A Discord music bot with synchronised lyrics, originally a sleep tracking bot to encourage sleeping.",
img: "napbot.webp",
type: "service",
},
{
name: "AutoFicFare",
href: "https://github.com/potatoeggy/autoficfare",
langs: ["python"],
license: "GPL-3.0",
description:
"Automatically update fanfiction in a Calibre database to instantly update them on your Kobo.",
type: "tool",
},
];
const unreleasedProjects: Project[] = [
{
name: "Aleister",
href: "https://github.com/potatoeggy/aleister",
langs: ["rust"],
license: "AGPL-3.0",
type: "service",
},
{
name: "Aoto",
href: "https://github.com/potatoeggy/aoto",
langs: ["golang", "typescript", "react"],
license: "AGPL-3.0",
type: "web",
},
{
name: "Kobink",
href: "https://github.com/potatoeggy/kobink",
langs: ["rust"],
license: "AGPL-3.0",
type: "service",
},
{
name: "GBARR",
href: "https://github.com/potatoeggy/gbarr",
langs: ["rust"],
license: "GPL-3.0",
type: "embedded",
},
];
export default projects;

View File

@ -1,13 +0,0 @@
interface SiteRevision {
title: string;
url: string;
}
export const revisions: SiteRevision[] = [
{
title: "Nuxt 3 (2022)",
url: "https://eggworld.me",
},
{ title: "Eleventy (2021)", url: "https://2021.eggworld.me" },
{ title: "Vanilla (2019-2020)", url: "https://2020.eggworld.me" },
];

View File

@ -1,3 +0,0 @@
export const SpecialTags: string[] = [
"featured",
];

View File

@ -1,79 +0,0 @@
export interface TagData {
name?: string;
description?: string;
}
export const tagInfo: Record<string, TagData> = {
barin: {
name: "Barin",
description:
"Welcome to Barin — a world in constant conflict between productivity and procrastination.",
},
bsscc: {
name: "BSSCC",
description: "Posts related to Bayview's Computer Club.",
},
ibia: {
name: "Ibia",
description:
"A Kurious child struggles to fight the misinformation brought by the Six Goddesses of the Subjects.",
},
misc: { name: "Miscellaneous" },
poetry: {
name: "Poetry",
description:
"Poetry is interesting in that there is a lot of implied stuff that is normally said directly in prose.",
},
primoprod: {
name: "Primoprod",
description:
'Reports following the development of <a href="https://github.com/potatoeggy/primoprod">Primoprod</a>.',
},
tech: { name: "Technology" },
unstagnation: {
name: "Unstagnation Short",
description:
"A collection of very short stories written to do something productive during JuneAugust 2020 and August 2021.",
},
albatross: {
name: "The FOSS Albatross",
description:
'Articles about free and open source software. Also available on <a href="https://medium.com/the-foss-albatross">Medium</a>.',
},
birds: {
name: "Bird Family",
description:
"A large, loving family of birds who have found in each other a kindred soul for eternal suffering.",
},
birdseye: {
name: "Bird's-Eye View",
description: "What's the world like to a pair of human-watching bluebirds?",
},
uoft: {
name: "University of Teyvat",
description: "A <em>Genshin Impact</em> university AU.",
},
nanowrimo: {
name: "NaNoWriMo",
description:
"Story snippets written during National Novel Writing Month as part of a larger work.",
},
skyprojections: {
name: "Projections in the Sky",
description: "Dreams or reality — what is the difference?",
},
featured: {
name: "Featured",
description: "Works that are less rambly and more actually good!",
},
"monoceros (novel)": {
name: "Monoceros (novel)",
description: "A coffee shop where six students meet and become friends.",
},
"emma the narwhal": {
name: "Emma the Narwhal",
description:
'A mystery-betrayal story written by April Evans in <a href="/tags/stories/monoceros (novel)"><em>Monoceros</em> (novel)</a>.',
},
};
export default tagInfo;

View File

@ -1,110 +0,0 @@
<script setup lang="ts">
import { revisions } from "@/data/siteRevisions";
useHead({ title: "Oeufs?" });
</script>
<template>
<div class="flex flex-col items-center w-full h-full justify-between">
<Navbar />
<slot />
<footer
class="flex items-center justify-between p-3 bg-gray-100 w-full text-sm dark:bg-gray-800 flex-col md:flex-row gap-2"
>
<label class="flex items-center gap-2">
<p>Revision:</p>
<!--
the onchange is so bad - i'd rather it be done through vue
but nuxt is genuinely screwing me over here
ig r4 has to be in next.js
-->
<select
class="p-2 border rounded-lg dark:bg-[#222]"
onchange="location = this.value"
>
<option v-for="(r, i) in revisions" :key="i" :value="r.url">
{{ r.title }}
</option>
</select>
</label>
<div class="flex flex-col items-center">
<p>
Licensed under the AGPL-3.0 on
<a class="underline" href="https://github.com/potatoeggy/public">
GitHub</a
>
and
<a class="underline" href="https://git.eggworld.me/eggy/public">
Gitea
</a>
</p>
</div>
<div class="w-36"></div>
</footer>
</div>
<slot name="top-button" />
</template>
<style>
html {
background: white;
color: black;
transition:
color 0.2s ease,
background 0.2s ease;
overflow-x: hidden;
overflow-y: scroll;
scroll-behavior: smooth;
}
html.dark {
background: #222;
color: white;
}
html::before {
content: "";
position: fixed;
height: 100%;
width: 100%;
background: #222;
transform: translateX(-100%);
transition: transform 0.2s ease;
z-index: 0;
}
/* div#__nuxt {
min-height: 100vh;
}
it's better if everything is sort of long but that is not the case
*/
html.dark::before {
transform: translateX(0);
}
main {
width: 80%;
max-width: 60rem;
margin: auto;
padding-top: 2rem;
}
footer {
--footer-drop-color: lightgray;
transition: background 0.2s ease;
box-shadow: 0 -0.05rem 0.75rem 0 var(--footer-drop-color);
margin-top: 2rem;
}
html.dark footer {
--footer-drop-color: black;
}
@media screen and (max-width: 600px) {
main {
width: 90%;
}
}
</style>

View File

@ -1,17 +0,0 @@
<script setup lang="ts">
import Default from "./default.vue";
</script>
<template>
<Default>
<slot />
<template #top-button> <ButtonToTop /> </template>
</Default>
</template>
<style>
div#__nuxt {
display: grid;
grid-template-columns: auto 0;
}
</style>

View File

@ -1,113 +0,0 @@
import { defineNuxtConfig } from "nuxt/config";
import svgLoader from "vite-svg-loader";
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
compatibilityDate: "2024-10-16",
app: {
head: {
htmlAttrs: {
lang: "en",
},
meta: [
{ name: "viewport", content: " width=device-width,initial-scale=1" },
{ name: "theme-color", content: "#ffffff" },
],
link: [
{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
{
rel: "stylesheet",
href: "https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css",
},
],
script: [
{
defer: true,
src: "/script.js",
hid: "stupidEmergencyScript",
type: "module",
},
],
},
},
modules: [
"@nuxt/content",
"@nuxtjs/tailwindcss",
"@nuxtjs/color-mode",
"@nuxtjs/sitemap",
],
css: ["@/assets/css/main.scss"],
nitro: {
prerender: {
routes: ["/sitemap.xml"],
},
},
typescript: {
shim: false,
},
site: {
url: process.env.BASE_URL || "https://eggworld.me",
},
sitemap: {
strictNuxtContentPaths: true,
},
tailwindcss: {},
colorMode: {
classSuffix: "",
},
vite: {
plugins: [svgLoader()],
css: {
preprocessorOptions: {
scss: {
api: "modern",
},
},
},
},
content: {
documentDriven: false,
highlight: {
theme: "dracula",
preload: [
"python",
"ts",
"js",
"sh",
"batch",
"c",
"cpp",
"dart",
"diff",
"docker",
"git-commit",
"git-rebase",
"go",
"ini",
"java",
"json",
"jsx",
"latex",
"md",
"nginx",
"rs",
"sql",
"toml",
"tsx",
"vue-html",
"vue",
"yaml",
"xml",
],
},
markdown: {
remarkPlugins: ["remark-math"],
rehypePlugins: [["rehype-katex", { output: "html" }]],
},
},
experimental: {
sharedPrerenderData: true,
},
features: {
noScripts: true,
},
});

View File

@ -1,26 +1,29 @@
{
"private": true,
"name": "my-blog",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
"start": "npx @11ty/eleventy --serve & postcss ./tailwind.css --o _site/assets/styles/tailwind.css --watch",
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"build": "npx @11ty/eleventy & postcss ./tailwind.css --o _site/assets/styles/tailwind.css"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@nuxt/content": "^2.13.4",
"@nuxtjs/color-mode": "^3.5.1",
"@nuxtjs/sitemap": "^6.1.2",
"@nuxtjs/tailwindcss": "^6.12.1",
"@tailwindcss/typography": "^0.5.15",
"@types/node": "^22.7.5",
"dayjs": "^1.11.13",
"nuxt": "3.13.2",
"prettier": "^3.3.3",
"reading-time": "^2.0.0-1",
"rehype-katex": "^7.0.1",
"remark-math": "^6.0.0",
"sass": "^1.79.5",
"typescript": "^5.6.3",
"vite-svg-loader": "^5.1.0"
"@11ty/eleventy": ">=0.11.1",
"@11ty/eleventy-plugin-syntaxhighlight": ">=3.0.4",
"eslint": ">=7.12.1",
"html-minifier": ">=3.5.21"
},
"dependencies": {
"@tailwindcss/typography": "^0.4.0",
"autoprefixer": "^10.2.4",
"markdown-it-anchor": "^7.0.1",
"postcss-cli": "^8.3.1",
"tailwindcss": ">=2.0.2"
}
}

View File

@ -1,13 +0,0 @@
<script setup lang="ts">
useTitle("404 - Not Found", "You're lost!");
</script>
<template>
<main class="prose dark:prose-invert max-w-3xl transition">
<h1 class="mb-1">404 - Not Found</h1>
<p>
You're lost! Don't worry, here's a link
<a href="/">back to the home page.</a>
</p>
</main>
</template>

View File

@ -1,78 +0,0 @@
<script setup lang="ts">
import type { AnyParsedContent } from "@/shared/types";
import { calcReadingTime } from "@/shared/metadata";
const route = useRoute();
// definePageMeta({
// layout: "withtop",
// });
// we're not using ContentDoc because i need control
const doc = await queryContent<AnyParsedContent>(route.path).findOne();
const type = route.path.startsWith("/stories")
? "stories"
: route.path.startsWith("/blog")
? "blog"
: "unknown";
const descText =
type === "stories"
? `${calcReadingTime(doc).words.total} words`
: `${calcReadingTime(doc).minutes} min read`;
useTitle(doc.title, doc.description);
const captionText =
type === "stories" ? "Story" : type === "blog" ? "Blog post" : "";
</script>
<template>
<main class="container prose dark:prose-invert w-full">
<p class="m-0 uppercase font-mono text-sm" v-if="captionText">
{{ captionText }}
</p>
<h1 class="m-0">{{ doc.title }}</h1>
<p class="my-2"><Date :doc="doc" /> · {{ descText }}</p>
<div class="flex flex-wrap">
<Tag
v-for="(tag, index) in doc.tags"
:dest="`/tags/${type}/${tag}`"
:key="index"
:name="tag"
/>
</div>
<ContentRenderer :value="doc" tag="article" class="pt-0 w-full">
<template #empty>
<p>No description found.</p>
</template>
<template #not-found>
<h1>404 - Not Found</h1>
<p>
Thanks for dropping by! But the page you're looking for can't be
found.
</p>
</template>
</ContentRenderer>
</main>
</template>
<style scoped>
.container {
width: 80%;
max-width: 80ch;
padding-top: 2rem;
}
@media screen and (max-width: 600px) {
.container {
width: 90%;
}
.container h1 {
overflow-wrap: break-word;
}
}
* {
transition: color 0.2s ease;
}
</style>

View File

@ -1,42 +0,0 @@
<script setup lang="ts">
import type { BlogParsedContent } from "@/shared/types";
useTitle("Blog", "Ramblings and ideas");
//definePageMeta({ layout: "withtop" });
// TODO: paginate stories
const docs = await queryContent<BlogParsedContent>("/blog")
.sort({ date: -1 })
.where({ _draft: false })
.find();
const tags = new Set(
docs
.map((p) => p.tags)
.flat()
.sort()
);
</script>
<template>
<main
class="flex flex-col grow prose dark:prose-invert max-w-3xl gap-6 transition"
>
<h1 class="mb-0">Blog</h1>
<div class="m-0">
Filter:
<Tag
:dest="`/tags/blog/${tag}`"
v-for="(tag, index) in tags"
:key="index"
:name="tag"
/>
</div>
<PostPreviewCard
v-for="(post, index) in docs"
:key="index"
:post
type="blog"
/>
</main>
</template>

View File

@ -1,39 +0,0 @@
<script setup lang="ts">
import Services from "@/components/index/services.vue";
import About from "@/components/index/about.vue";
//definePageMeta({ layout: "withtop" });
useTitle("Home", "Personal website!");
const welcomeStrings = ["Welcome!", "Bienvenue!", "欢迎!"];
</script>
<template>
<main class="flex flex-col items-center justify-around gap-8">
<div class="flex flex-col items-center">
<HeaderLoop class="text-bitter font-bold" :strings="welcomeStrings" />
<p>What are you here to see?</p>
<p>
For my portfolio, please visit
<a class="underline" href="https://github.com/potatoeggy">GitHub</a>
instead.
</p>
</div>
<div
class="flex justify-around items-start w-full flex-wrap gap-x-8 gap-y-10"
>
<BlogStatBox />
<StoryStatBox />
<CommitStatBox />
</div>
<Services />
<About />
</main>
</template>
<style scoped>
h1 {
font-size: 3rem;
}
</style>

View File

@ -1,42 +0,0 @@
<script setup lang="ts">
import type { StoryParsedContent } from "@/shared/types";
useTitle("Stories", "Fantasies and worlds");
//definePageMeta({ layout: "withtop" });
// TODO: paginate stories
const docs = await queryContent<StoryParsedContent>("/stories")
.sort({ date: -1 })
.where({ _draft: false })
.find();
const tags = new Set(
docs
.map((p) => p.tags)
.flat()
.sort()
);
</script>
<template>
<main
class="flex flex-col grow prose dark:prose-invert max-w-3xl gap-6 transition"
>
<h1 class="mb-0">Stories</h1>
<div class="m-0">
Filter:
<Tag
:dest="`/tags/stories/${tag}`"
v-for="(tag, index) in tags"
:key="index"
:name="tag"
/>
</div>
<PostPreviewCard
v-for="(story, index) in docs"
:key="index"
:post="story"
type="stories"
/>
</main>
</template>

View File

@ -1,42 +0,0 @@
<script setup lang="ts">
import { tagInfo, type TagData } from "@/data/tagInfo";
import type { BlogParsedContent } from "@/shared/types";
const route = useRoute();
//definePageMeta({ layout: "withtop" });
const tag =
typeof route.params.tag === "string" ? route.params.tag : route.params.tag[0];
const details: TagData = tagInfo[tag] ?? {};
const docs = await queryContent<BlogParsedContent>("/blog")
.sort({ date: -1 })
.where({ _draft: false, tags: { $contains: tag } })
.find();
const title = details.name ?? `"${tag}"`;
useTitle(title + " Posts", details.description);
</script>
<template>
<main
class="prose dark:prose-invert max-w-3xl flex flex-col grow gap-6 transition"
>
<div>
<h1 class="mb-0">{{ title }} Posts</h1>
<p
v-if="details.description"
v-html="details.description"
class="mt-2"
></p>
</div>
<PostPreviewCard
v-for="(post, index) in docs"
:key="index"
:post
:highlighttags="[tag]"
type="blog"
/>
</main>
</template>

View File

@ -1,42 +0,0 @@
<script setup lang="ts">
import { tagInfo, type TagData } from "@/data/tagInfo";
import type { StoryParsedContent } from "@/shared/types";
const route = useRoute();
//definePageMeta({ layout: "withtop" });
const tag =
typeof route.params.tag === "string" ? route.params.tag : route.params.tag[0];
const details: TagData = tagInfo[tag] ?? {};
const docs = await queryContent<StoryParsedContent>("/stories")
.sort({ date: -1 })
.where({ _draft: false, tags: { $contains: tag } })
.find();
const title = details.name ?? `"${tag}"`;
useTitle(title + " Stories", details.description);
</script>
<template>
<main
class="prose dark:prose-invert max-w-3xl flex flex-col grow gap-6 transition"
>
<div>
<h1 class="mb-0">{{ title }} Stories</h1>
<p
v-if="details.description"
v-html="details.description"
class="mt-2"
></p>
</div>
<PostPreviewCard
v-for="(story, index) in docs"
:key="index"
:post="story"
:highlighttags="[tag]"
type="stories"
/>
</main>
</template>

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: [
require(`tailwindcss`)(`./tailwind.config.js`),
require(`autoprefixer`),
],
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-147 -70 294 345">
<g fill="#a4c639">
<use stroke-width="14.4" xlink:href="#b" stroke="#FFF"/>
<use xlink:href="#a" transform="scale(-1,1)"/>
<g id="a" stroke="#FFF" stroke-width="7.2">
<rect rx="6.5" transform="rotate(29)" height="86" width="13" y="-86" x="14"/>
<rect id="c" rx="24" height="133" width="48" y="41" x="-143"/>
<use y="97" x="85" xlink:href="#c"/>
</g>
<g id="b">
<ellipse cy="41" rx="91" ry="84"/>
<rect rx="22" height="182" width="182" y="20" x="-91"/>
</g>
</g>
<g stroke="#FFF" stroke-width="7.2" fill="#FFF">
<path d="m-95 44.5h190"/><circle cx="-42" r="4"/><circle cx="42" r="4"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 745 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32.000001">
<g transform="translate(0 -1020.3622)">
<ellipse cx="-907.35657" cy="479.90009" fill="#384e54" color="#000" overflow="visible" rx="3.5793996" ry="3.8207953" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" transform="scale(-1 1) rotate(-60.548)"/>
<ellipse cx="-891.57654" cy="507.8461" fill="#384e54" color="#000" overflow="visible" rx="3.5793996" ry="3.8207953" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1" transform="rotate(-60.548)"/>
<path fill="#384e54" d="M16.091693 1021.3642c-1.105749.01-2.210341.049-3.31609.09C6.8422558 1021.6738 2 1026.3942 2 1032.3622v20h28v-20c0-5.9683-4.667345-10.4912-10.59023-10.908-1.10575-.078-2.212328-.099-3.318077-.09z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill="#76e1fe" d="M4.6078867 1025.0462c.459564.2595 1.818262 1.2013 1.980983 1.648.183401.5035.159385 1.0657-.114614 1.551-.346627.6138-1.005341.9487-1.696421.9365-.339886-.01-1.720283-.6372-2.042561-.8192-.97754-.5519-1.350795-1.7418-.833686-2.6576.517109-.9158 1.728749-1.2107 2.706299-.6587z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<rect width="3.0866659" height="3.5313663" x="14.406213" y="1035.6842" fill-opacity=".32850246" color="#000" overflow="visible" ry=".62426329" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill="#76e1fe" d="M16 1023.3622c-9 0-12 3.7153-12 9v20h24c-.04889-7.3562 0-18 0-20 0-5.2848-3-9-12-9z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill="#76e1fe" d="M27.074073 1025.0462c-.45957.2595-1.818257 1.2013-1.980979 1.648-.183401.5035-.159384 1.0657.114614 1.551.346627.6138 1.005335.9487 1.696415.9365.33988-.01 1.72029-.6372 2.04256-.8192.97754-.5519 1.35079-1.7418.83369-2.6576-.51711-.9158-1.72876-1.2107-2.7063-.6587z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<circle cx="21.175734" cy="1030.3542" r="4.6537542" fill="#fff" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<circle cx="10.339486" cy="1030.3542" r="4.8316345" fill="#fff" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<rect width="3.6673687" height="4.1063409" x="14.115863" y="1035.9174" fill-opacity=".32941176" color="#000" overflow="visible" ry=".72590536" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<rect width="3.6673687" height="4.1063409" x="14.115863" y="1035.2253" fill="#fffcfb" color="#000" overflow="visible" ry=".72590536" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill-opacity=".32941176" d="M19.999735 1036.5289c0 .838-.871228 1.2682-2.144766 1.1659-.02366 0-.04795-.6004-.254147-.5832-.503669.042-1.095902-.02-1.685964-.02-.612939 0-1.206342.1826-1.68549.017-.110233-.038-.178298.5838-.261532.5816-1.243685-.033-2.078803-.3383-2.078803-1.1618 0-1.2118 1.815635-2.1941 4.055351-2.1941 2.239704 0 4.055351.9823 4.055351 2.1941z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill="#c38c74" d="M19.977414 1035.7004c0 .5685-.433659.8554-1.138091 1.0001-.291933.06-.630371.096-1.003719.1166-.56405.032-1.207782.031-1.89122.031-.672834 0-1.307182 0-1.864904-.029-.306268-.017-.589429-.043-.843164-.084-.813833-.1318-1.324962-.417-1.324962-1.0344 0-1.1601 1.805642-2.1006 4.03303-2.1006 2.227377 0 4.03303.9405 4.03303 2.1006z" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<ellipse cx="15.944382" cy="1033.8501" fill="#23201f" color="#000" overflow="visible" rx="2.0801733" ry="1.343747" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<circle cx="12.414201" cy="1030.3542" r="1.9630634" fill="#171311" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<circle cx="23.110121" cy="1030.3542" r="1.9630634" fill="#171311" color="#000" overflow="visible" style="isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"/>
<path fill="none" stroke="#384e54" stroke-linecap="round" stroke-width=".39730874" d="M5.0055377 1027.2727c-1.170435-1.0835-2.026973-.7721-2.044172-.7463"/>
<path fill="none" stroke="#384e54" stroke-linecap="round" stroke-width=".39730874" d="M4.3852457 1026.9152c-1.158557.036-1.346704.6303-1.33881.6523m23.5840973-.3951c1.17043-1.0835 2.02697-.7721 2.04417-.7463"/>
<path fill="none" stroke="#384e54" stroke-linecap="round" stroke-width=".39730874" d="M27.321773 1026.673c1.15856.036 1.3467.6302 1.3388.6522"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 32 32"><path d="M11.622 24.74s-1.23.748.855.962c2.51.32 3.847.267 6.625-.267a10.02 10.02 0 0 0 1.763.855c-6.25 2.672-14.16-.16-9.244-1.55zm-.8-3.473s-1.336 1.015.748 1.23c2.725.267 4.862.32 8.55-.427a3.26 3.26 0 0 0 1.282.801c-7.534 2.244-15.976.214-10.58-1.603zm14.747 6.09s.908.748-1.015 1.336c-3.58 1.07-15.014 1.39-18.22 0-1.122-.48 1.015-1.175 1.7-1.282.695-.16 1.07-.16 1.07-.16-1.23-.855-8.175 1.763-3.526 2.51 12.77 2.084 23.296-.908 19.983-2.404zM12.2 17.633s-5.824 1.39-2.084 1.87c1.603.214 4.755.16 7.694-.053 2.404-.214 4.81-.64 4.81-.64s-.855.374-1.443.748c-5.93 1.55-17.312.855-14.052-.748 2.778-1.336 5.076-1.175 5.076-1.175zm10.42 5.824c5.984-3.1 3.206-6.09 1.282-5.717-.48.107-.695.214-.695.214s.16-.32.534-.427c3.794-1.336 6.786 4.007-1.23 6.09 0 0 .053-.053.107-.16zm-9.83 8.442c5.77.374 14.587-.214 14.8-2.94 0 0-.427 1.07-4.755 1.87-4.916.908-11.007.8-14.587.214 0 0 .748.64 4.542.855z" fill="#4e7896"/><path d="M18.996.001s3.313 3.366-3.152 8.442c-5.183 4.114-1.175 6.465 0 9.137-3.046-2.725-5.236-5.13-3.74-7.373C14.294 6.893 20.332 5.3 18.996.001zm-1.7 15.335c1.55 1.763-.427 3.366-.427 3.366s3.954-2.03 2.137-4.542c-1.656-2.404-2.94-3.58 4.007-7.587 0 0-10.953 2.725-5.717 8.763z" fill="#f58219"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M0,0 L256,0 L256,256 L0,256 L0,0 Z" fill="#F7DF1E"></path>
<path d="M67.311746,213.932292 L86.902654,202.076241 C90.6821079,208.777346 94.1202286,214.447137 102.367086,214.447137 C110.272203,214.447137 115.256076,211.354819 115.256076,199.326883 L115.256076,117.528787 L139.313575,117.528787 L139.313575,199.666997 C139.313575,224.58433 124.707759,235.925943 103.3984,235.925943 C84.1532952,235.925943 72.9819429,225.958603 67.3113397,213.93026" fill="#000000"></path>
<path d="M152.380952,211.354413 L171.969422,200.0128 C177.125994,208.433981 183.827911,214.619835 195.684368,214.619835 C205.652521,214.619835 212.009041,209.635962 212.009041,202.762159 C212.009041,194.513676 205.479416,191.592025 194.481168,186.78207 L188.468419,184.202565 C171.111213,176.81473 159.597308,167.53534 159.597308,147.944838 C159.597308,129.901308 173.344508,116.153295 194.825752,116.153295 C210.119924,116.153295 221.117765,121.48094 229.021663,135.400432 L210.29059,147.428775 C206.166146,140.040127 201.699556,137.119289 194.826159,137.119289 C187.78047,137.119289 183.312254,141.587098 183.312254,147.428775 C183.312254,154.646349 187.78047,157.568406 198.089956,162.036622 L204.103924,164.614095 C224.553448,173.378641 236.067352,182.313448 236.067352,202.418387 C236.067352,224.071924 219.055137,235.927975 196.200432,235.927975 C173.860978,235.927975 159.425829,225.274311 152.381359,211.354413" fill="#000000"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="208" height="128" viewBox="0 0 208 128"><rect width="198" height="118" x="5" y="5" ry="10" stroke="#000" stroke-width="10" fill="none"/><path d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39zm125 0l-30-33h20V30h20v35h20z"/></svg>

Before

Width:  |  Height:  |  Size: 282 B

View File

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="110px" height="110px" viewBox="0.21 -0.077 110 110" enable-background="new 0.21 -0.077 110 110" xml:space="preserve"><linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="63.8159" y1="56.6829" x2="118.4934" y2="1.8225" gradientTransform="matrix(1 0 0 -1 -53.2974 66.4321)"> <stop offset="0" style="stop-color:#387EB8"/> <stop offset="1" style="stop-color:#366994"/></linearGradient><path fill="url(#SVGID_1_)" d="M55.023-0.077c-25.971,0-26.25,10.081-26.25,12.156c0,3.148,0,12.594,0,12.594h26.75v3.781 c0,0-27.852,0-37.375,0c-7.949,0-17.938,4.833-17.938,26.25c0,19.673,7.792,27.281,15.656,27.281c2.335,0,9.344,0,9.344,0 s0-9.765,0-13.125c0-5.491,2.721-15.656,15.406-15.656c15.91,0,19.971,0,26.531,0c3.902,0,14.906-1.696,14.906-14.406 c0-13.452,0-17.89,0-24.219C82.054,11.426,81.515-0.077,55.023-0.077z M40.273,8.392c2.662,0,4.813,2.15,4.813,4.813 c0,2.661-2.151,4.813-4.813,4.813s-4.813-2.151-4.813-4.813C35.46,10.542,37.611,8.392,40.273,8.392z"/><linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="97.0444" y1="21.6321" x2="155.6665" y2="-34.5308" gradientTransform="matrix(1 0 0 -1 -53.2974 66.4321)"> <stop offset="0" style="stop-color:#FFE052"/> <stop offset="1" style="stop-color:#FFC331"/></linearGradient><path fill="url(#SVGID_2_)" d="M55.397,109.923c25.959,0,26.282-10.271,26.282-12.156c0-3.148,0-12.594,0-12.594H54.897v-3.781 c0,0,28.032,0,37.375,0c8.009,0,17.938-4.954,17.938-26.25c0-23.322-10.538-27.281-15.656-27.281c-2.336,0-9.344,0-9.344,0 s0,10.216,0,13.125c0,5.491-2.631,15.656-15.406,15.656c-15.91,0-19.476,0-26.532,0c-3.892,0-14.906,1.896-14.906,14.406 c0,14.475,0,18.265,0,24.219C28.366,100.497,31.562,109.923,55.397,109.923z M70.148,101.454c-2.662,0-4.813-2.151-4.813-4.813 s2.15-4.813,4.813-4.813c2.661,0,4.813,2.151,4.813,4.813S72.809,101.454,70.148,101.454z"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

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