ORGPILLED BABEY

This commit is contained in:
Alexandra Dunn 2022-01-30 14:41:20 -08:00
parent 3c88354f49
commit 10854fc28e
22 changed files with 379 additions and 3881 deletions

View file

@ -1,17 +0,0 @@
const { DateTime } = require("luxon");
const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginSyntaxHighlight);
eleventyConfig.addPassthroughCopy("stylesheets");
eleventyConfig.addFilter("readableDate", dateObj => {
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat("dd LLL yyyy");
});
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
eleventyConfig.addFilter('htmlDateString', (dateObj) => {
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('yyyy-LL-dd');
});
};

5
.gitignore vendored
View file

@ -1,2 +1,3 @@
_site
node_modules
*.html
*.xml
stylesheets

View file

@ -1,12 +1,24 @@
FROM node:lts-alpine as builder
FROM node:lts-alpine as css
WORKDIR /garbage
COPY package.json ./
RUN npm install
RUN npm install -g sass
COPY sass sass
RUN mkdir stylesheets
RUN sass sass:stylesheets
FROM alpine:3.15 as emacs
WORKDIR /garbage
RUN apk --no-cache add \
emacs
COPY . .
RUN npx @11ty/eleventy
RUN emacs --batch --load setup.el
RUN emacs --batch --load publish.el
FROM nginx:stable-alpine
COPY --from=builder /garbage/_site/ /usr/share/nginx/html
COPY --from=css /garbage/stylesheets /usr/share/nginx/html/stylesheets
COPY --from=emacs /garbage/*.html /usr/share/nginx/html/
COPY --from=emacs /garbage/*.xml /usr/share/nginx/html/

View file

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{{ renderData.description or description or metadata.description }}" />
<title>{{ renderData.title or title or metadata.title }}</title>
<link href="https://unpkg.com/prismjs@1.20.0/themes/prism-okaidia.css" type="text/css" rel="stylesheet" />
<link href="/stylesheets/screen.css" rel="stylesheet" type="text/css" media="screen" />
<link href="/stylesheets/print.css" rel="stylesheet" type="text/css" media="print" />
</head>
<body>
<header>
<h1><a href="/" title="root">🖥😩</a></h1>
<h2>stop touching the computer</h2>
</header>
<main>
{{ content | safe }}
</main>
</body>
</html>

View file

@ -1,8 +0,0 @@
---
layout: layouts/base.njk
---
<article>
<h3><a href="{{ url }}" title="Permanent link">{{ title }}</a>
<time datetime={{ date | htmlDateString }}>{{ date | readableDate }}</time></h3>
{{ content | safe }}
</article>

0
drafts/.keep Normal file
View file

View file

@ -1,12 +0,0 @@
---
layout: layouts/base.njk
---
{% for post in collections.post | reverse %}
<ul>
<li><a href="{{ post.url }}" title="Permanent link">{{ post.data.title }}</a> (<time datetime={{ post.date | htmlDateString }}>{{ post.date | readableDate }}</time>)
<br />
<span>{{ post.data.description }}</span>
</li>
</ul>
{% endfor %}

3106
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,20 +0,0 @@
{
"name": "garbage",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@11ty/eleventy": "^0.12.0",
"@11ty/eleventy-plugin-syntaxhighlight": "^3.0.1",
"luxon": "^2.0.0"
},
"jshintConfig": {
"esversion": 8
}
}

View file

@ -1,299 +0,0 @@
---
title: How to Add Needless Complexity to Your Life
date: 2014-10-30
description: How to make email suck even more.
layout: layouts/post.njk
tags: post
---
I used Apple Mail forever until recently, when my Exchange account starting
causing it to blow itself up. Instead of installing Thunderbird and moving on
with my life, I decided it was a good idea to start being a Serious Email User,
and so I installed the Serious Email Client [mutt](http://www.mutt.org). But
since this is a piece of Serious Software, there wasn't any easy-to-find, good
documentation focused on actually *sending and receiving email* as opposed to
Installing and Configuring mutt. (Even [the hard-to-find
ones](http://curvedthoughts.com/blog/email-using-getmail-msmtp-mutt/ "Manage
email using getmail, msmtp, and mutt") didn't go in-depth enough, and weren't
written for OS X.) So this my attempt to get everything necessary---and nothing
more---written down in one place.
#### mutt is just for reading email
The program mutt was not originally designed to do the actual sending and
receiving of email. It can do that now, but it was built as a way to view local
mail and to compose messages (except not really---you do the actual writing in
your `$EDITOR`). Mail is fetched from a mail server using another program---I'll
be using [getmail](http://pyropus.ca/software/getmail/). Mail is sent using yet
another program---[msmtp](http://msmtp.sourceforge.net).
And there's no point in having mutt if you've got nothing to read, so before we
even bother installing mutt we're going to set up getmail.
#### you get mail with getmail
The easiest way to install getmail is with
[Homebrew](http://brew.sh "The missing package manager for OS X"):
```text
brew install getmail
```
The official [configuration
documentation](http://pyropus.ca/software/getmail/configuration.html) is not
always very clear, but it is comprehensive. So we'll try to simplify it here,
with some help from [the
blogosphere](http://curvedthoughts.com/blog/email-using-getmail-msmtp-mutt/
"Manage email using getmail, msmtp, and mutt").
First set up the config directory, with restricted permissions for Serious
Security:
```text
mkdir -m 700 ~/.getmail
```
In that folder you'll need to set up a config file for each email account you
want to retrieve messages from. If you just have one, name the file `getmailrc`,
which is what getmail looks for by default. The examples below are for setting
up a Gmail account, so I named the below config file `gmailrc`:
```text
[retriever]
type = SimpleIMAPSSLRetriever
server = imap.gmail.com
port = 993
mailboxes = ALL
username = gmail-address
ssl_version = tlsv1_2
[destination]
type = Maildir
path = ~/Mail/gmail/
[options]
message_log = ~/.getmail/gmail.log
read_all = false
```
The most common alternative to `SimpleIMAPSSLRetriever` is probably
`SimplePOP3SSLRetriever`, but there are [lots of types supported by
getmail](http://pyropus.ca/software/getmail/configuration.html#conf-retriever).
If you only want to download your inbox, don't specify `mailboxes`. If
you want to download a subset of your mailboxes, replace
`mailboxes = ALL` with a list of desired mailboxes in the following
format:
```text
mailboxes = ("INBOX", "INBOX.spam")
```
getmail's `ssl_version` [defaults to
SSLv23](http://pyropus.ca/software/getmail/configuration.html#retriever-ssl-extra),
which needs to be overridden since it allows SSLv3, which is now [known
to be vulnerable](http://poodlebleed.com).
Replace `gmail-address` with your full Gmail email address, then create
a Maildir directory structure in `~/Mail/gmail`:
```text
mkdir -m 700 -p ~/Mail/gmail/{cur,new,tmp}
```
(getmail supports
[mbox](http://qmail.org/qmail-manual-html/man5/mbox.html) in addition to
Maildir; I don't really know the relative strengths and weaknesses but I
went with Maildir ¯\\\_(ツ)\_/¯.)
The `[options]` are not required, but `read_all = false` is a very good
idea (especially with `mailboxes = ALL`) because otherwise getmail will
download all your mail every time you run it.
You can specify `password` in your config file, but then it's sitting
there in plain text and that's Bad. So instead, add the password to
Keychain Access:
```text
security add-internet-password -a 'gmail-address' -s 'imap.gmail.com' -r imap -P 993 -w app-specific-password
```
Replace `gmail-address` again with your full Gmail email address, and
`app-specific-password` with a [Google App
Password](https://support.google.com/accounts/answer/185833 "Google Support").
**Important:** if your password has characters like `$` that shells
treat specially, make sure to put single quotes around the whole
password.
Then run getmail, with the `--rcfile` flag if you have config files that
aren't named `getmailrc` (you can use the flag multiple times):
```text
getmail --rcfile=gmailrc --rcfile=otheraccount
```
Add that command to your [cron
jobs](https://help.ubuntu.com/community/CronHowto) or use [Apple's
`launchd`](http://nathangrigg.net/2012/07/schedule-jobs-using-launchd/)
to run it regularly.
#### *then* you install mutt
```text
brew install mutt --with-gpgme --with-confirm-attachment-patch
```
The `--with-gpgme` flag enables [GPGME (GnuPG Made
Easy)](https://www.gnupg.org/related_software/gpgme/), which is
apparently [the right way to do encryption with
mutt](http://henrytodd.org/notes/2014/simpler-gnupg-mutt-config-with-gpgme/).
The `--with-confirm-attachment-patch` flag causes mutt to warn you
before sending a message with "attach" in the body but no attachment.
Both of these flags are optional, and there are other flags you might
want to add; see `brew info mutt`.
The only setting you *have* to add to your mutt configuration file (by
default, `~/.muttrc`) is `set mbox_type=Maildir` (or
`set mbox_type=mbox` as the case may be). You'll probably want to
specify the location of your Gmail folder, though:
```text
set mbox_type=Maildir
set folder = "~/Mail/gmail/"
set spoolfile = "~/Mail/gmail/"
set record = "~/Mail/gmail/sent/"
```
The `sent` folder is technically another Maildir box, so you'll need to
populate it with the same three folders:
```text
mkdir -m 700 -p ~/Mail/gmail/sent/{cur,new,tmp}
```
Fine-tuning your configuration and getting comfortable with the program
isn't what this post is about; take a look at [sample `.muttrc`
files](http://curvedthoughts.com/blog/email-using-getmail-msmtp-mutt/ "Manage email using getmail, msmtp, and mutt"),
Steve Losh's [excellent
guide](http://stevelosh.com/blog/2012/10/the-homely-mutt/ "The Homely Mutt")
and the list of [mutt
commands](http://www.mutt.org/doc/manual/manual-6.html#functions).
I will mention one customization that I had to come up with for reading
HTML emails on OS X. It's easy enough to [pass HTML emails and HTML
attachments to a text-based
browser](http://www.debian-administration.org/article/75/Reading_HTML_email_with_Mutt "Debian Administration: Reading HTML email with Mutt")
like lynx or w3m, but when I get [Today in
Tabs](http://tinyletter.com/todayintabs) I want to be able to *open the
tabs* in Safari or whatever real browser I usually use. You can [pass
links from w3m to
Firefox](http://superuser.com/questions/422692/open-current-page-in-w3m-in-firefox)
if you're using Linux, but on OS X you'd have to be using w3m from
within emacs to be able to do that. [Piping the HTML directly to
Safari](http://hints.macworld.com/article.php?story=20051122200920326)
doesn't work either, because the temporary file that mutt creates has
the `.txt` extension, so Safari doesn't render the HTML. My solution is
to add this to your `.muttrc`:
```text
macro pager \cb <pipe-entry>'cat > /tmp/mutt_mail.html; open /tmp/mutt_mail.html'<enter> 'open email in default browser'
```
When you hit `^b` (control-b) while viewing an HTML message or
attachment, what that does is spit the HTML into a temporary file, then
open it in your default browser.
(I wouldn't have figured this out if not for [Bruno Postle's page on
following
links](http://mutt.blackfish.org.uk/following-links/ "my first mutt").)
#### and send mail with msmtp
By now you know the drill:
```text
brew install msmtp
```
Then set up your [configuration
file](http://msmtp.sourceforge.net/doc/msmtp.html#Configuration-files),
with permissions set to `600`, at `~/.msmtprc`:
```text
defaults
tls on
tls_starttls on
tls_trust_file [see below]
logfile ~/Mail/msmtp.log
account gmail-address
host smtp.gmail.com
port 587
protocol smtp
auth on
from gmail-address
user gmail-address
```
OS X doesn't have the `/etc/ssl/certs/ca-certificates.crt` file that
some Linux systems do. All our certificates are in the Keychain Access
application; so we need to export them:
1. Open Keychain Access
(`open -a /Applications/Utilities/Keychain\ Access.app/`).
2. From the "Keychains" column, select "System Roots."
3. Select All, then go to File → Export Items... (`⇧⌘E`).
4. Save the `.pem` file wherever, then set `tls_trust_file` to the path
to it (for example, `~/Mail/certs/Certificates.pem`).
Then return to your `.muttrc` and add:
`set sendmail = "/usr/local/bin/msmtp"`
Add another Keychain entry:
```text
security add-internet-password -a 'gmail-address' -s 'smtp.gmail.com' -r smtp -P 587 -w app-specific-password
```
Again, replace `gmail-address` with your full Gmail email address, and
`app-specific-password` with a [Google App
Password](https://support.google.com/accounts/answer/185833 "Google Support").
#### yay
At this point you should be able to send and receive email using mutt!
Wooooww. Now you can dick around with further niceties:
- Encrypt your emails. If you already have GPG installed, [following
these
instructions](http://henrytodd.org/notes/2014/simpler-gnupg-mutt-config-with-gpgme/)
will probably work. Otherwise `brew install gnupg gpg-agent` and
[get them set up](https://wiki.archlinux.org/index.php/Gnupg).
(If you start mutt and get the error message *"Using GPGME backend,
although no gpg-agent is running,"* gpg-agent may be [running in a
different shell
session](http://lists.gnupg.org/pipermail/gnupg-users/2007-May/031024.html)---this
might occur if you're using a terminal multiplexer like screen or
tmux, or if you're using the
[GPGTools](https://gpgtools.org)-supplied gpg-agent.)
- `brew install lbdb` and create `~/.lbdbrc` with the following lines
to link Contacts.app to mutt:
METHODS="m_muttalias m_osx_addressbook"
MUTT_DIRECTORY="$HOME/.mutt"
MUTTALIAS_FILES=".muttrc .mail_aliases muttrc aliases"
Then add `set query_command="/usr/local/bin/lbdbq '%s'"` to your
`.muttrc`, and use `^t` (control-t) to auto-complete addresses.
(This is adapted from [bluehz's
instructions](http://hints.macworld.com/article.php?story=20041024163030501).)
- [Set up emacs as your message
editor](http://www.emacswiki.org/emacs/MuttInEmacs)

View file

@ -1,287 +0,0 @@
---
title: The Library Genesis API
date: 2014-10-01
description: An English-language guide to using the LibGen API.
layout: layouts/post.njk
tags: post
---
[Library Genesis](http://libgen.io/) has an API, but the only documentation is
[a forum thread in Russian](http://genofond.org/viewtopic.php?p=39355 "The
Library Genesis Miner's Hut"). So this is an English-language guide to using
the LibGen API.
(I don't know Russian, and had to read the original thread using [Google
Translate](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fgenofond.org%2Fviewtopic.php%3Fp%3D39355),
so corrections and additions are very welcome!)
#### First, some bad news
*This is not a search API.*
The API was apparently written to help LibGen maintainers keep their
local mirrors up-to-date, which would explain why the API does not
support the most common use that Library Genesis is put to by the rest
of us: searching for texts. You can't (as far as I can tell) submit a
string and get a list of results based on that string.
There are two *documented* ways to use the API to query the LibGen
database: by text ID, or by date.
#### Querying by ID
Here's how to retrieve information about the texts with the coveted IDs
of `1` and `2`:
```text
curl 'http://libgen.io/json.php?ids=1,2&fields=Title,Author,MD5'
```
(The API is available at `http://gen.lib.rus.ec/json.php` as well.)
The above `curl` request will return an array of JSON objects:
```json
[
{
"title":"Handbook of Clinical Drug Data",
"author":"Philip Anderson",
"md5":"7B2A4D53FDE834E801C26A2BAB7E0240"
},
{
"title":"Handbook of Herbs and Spices",
"author":"K V Peter",
"md5":"048EA0496DB0444F873139CD705A07AF"
}
]
```
I used these three fields -- `title`, `author`, and `md5` -- because
they're all you need in most situations. You can get the page URL by
appending the MD5 to `http://libgen.io/book/index.php?md5=` or to one of
the mirrors:
- `http://gen.lib.rus.ec/book/index.php?md5=`
- `http://bookzz.org/md5/`
- `http://bookfi.org/md5/`
You can create a download URL by appending the MD5 to
`http://libgen.io/get.php?md5=`.
There are other mirrors whose URLs are based on the text's LibGen ID,
rather than the MD5:
- `http://libgen.net/view.php?id=`
- `http://www.libgen.net/view.php?id=`
- `http://libgen.iofo/view.php?id=`
- `http://lib.freescienceengineering.org/view.php?id=`
You can't get a direct download link for these; you have to go to the
page for the text and download from there.
But `title`, `author`, and `md5` are far from the only available data
fields; the full list is below. I haven't figured out what all the
fields mean, and keep in mind that it's up to the person uploading a
text to add this metadata, so not all texts are well-annotated.
- `id` -- the LibGen ID
- `title` -- the title of the text
- `volumeinfo` -- the volume number, if the text is part of a
multi-volume series
- `series` -- the series that the text is part of
- `periodical`
- `author` -- the author of the text
- `year` -- the publication date of the text
- `edition` -- the edition of the text
- `publisher` -- the publisher of the text
- `city` -- the location of the publisher
- `pages` -- the number of pages in the text
- `language` -- the language of the text
- `topic` -- A number corresponding to the topic of the text; for
example, `130` is "Mathematics/Logic"
- `library`
- `issue`
- `identifier` -- the text's short and long [International Standard
Book Numbers](https://www.isbn-international.org/content/what-isbn)
(not necessarily in that order)
- `issn` -- the text's [International Standard Serial
Number](http://www.issn.org/understanding-the-issn/what-is-an-issn/)
- `asin` -- the text's [Amazon Standard Identification
Number](http://www.amazon.com/gp/seller/asin-upc-isbn-info.html)
- `udc` -- the text's [Universal Decimal
Classification](https://en.wikipedia.org/wiki/Universal_Decimal_Classification "Wikipedia entry")
number
- `lbc`
- `ddc` -- the text's [Dewey Decimal
Classification](https://en.wikipedia.org/wiki/Dewey_Decimal_Classification "Wikipedia entry")
number
- `lcc` -- the text's [Library of Congress
Classification](https://en.wikipedia.org/wiki/Library_of_Congress_Classification "Wikipedia entry")
number
- `doi` -- the file's [Digital Object
Identifier](https://en.wikipedia.org/wiki/Digital_object_identifier "Wikipedia entry")
- `googlebookid` -- the text's [Google Books
ID](https://developers.google.com/books/docs/v1/using#ids)
- `openlibraryid` -- the text's [Open Library
ID](https://openlibrary.org/dev/docs/api/books)
- `commentary`
- `dpi`
- `color`
- `cleaned`
- `orientation`
- `paginated` -- the text is paginated (`1`) or not (`0`)
- `scanned` -- the text is scanned from a physical copy (`1`) or not
(`0`)
- `bookmarked` -- the text has bookmarks (`1`) or not (`0`)
- `searchable` -- the text is searchable (`1`) or not (`0`)
- `filesize` -- the size of the file in bytes
- `extension` -- the extension of the file (`.pdf`, `.epub`, `.mobi`,
etc.)
- `md5` -- the [MD5](http://www.md5.net) hash of the file
- `crc32` -- the file's
[CRC32](http://www.riccibitti.com/crcguide.htm "A painless guide to CRC error detection algorithms")
checksum
- `edonkey` -- the file's [eDonkey
hash](https://en.wikipedia.org/wiki/Ed2k_URI_scheme "Wikipedia entry")
- `aich` -- the text's [eMule file
hash](http://www.emule-project.net/home/perl/help.cgi?l=1&rm=show_topic&topic_id=589)
- `sha1` -- the file's
[SHA-1](https://en.wikipedia.org/wiki/SHA-1 "Wikipedia entry") hash
- `tth` -- the file's [Tiger tree
hash](https://en.wikipedia.org/wiki/Merkle_tree#Tiger_tree_hash "Wikipedia entry")
- `generic`
- `filename` -- the name of the file in the LibGen database, in the
form `directory/md5`. The directory name is the text's LibGen ID
rounded to the nearest thousand, and the MD5 hash is in lowercase.
(The directory that each file is located in is [also included in the
file
name](https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/util.php#L6 "LibGen code on GitHub").)
- `visible`
- `locator` -- [As far as I can
tell](https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/librarian/form.php#L187 "LibGen code on GitHub"),
this is the file path of the original file on the machine of whoever
uploaded it.
- `local`
- `timeadded` -- the date/time when the text was added to the database,
formatted as `YYYY-MM-DD HH:MM:SS`
- `timelastmodified` -- the date/time when the text's entry in the
database was edited, formatted as `YYYY-MM-DD HH:MM:SS`
- `coverurl` -- the path to the cover image for the text: the
`filename` followed by a lowercase letter (there's [a
function](https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/book/util.php#L30 "LibGen code on GitHub")
to determine the letter for each cover, but I don't know enough PHP
to understand it).
If you want to get all fields for a text, use `fields=*`.
#### Searching by date
Querying by ID is pretty useless except for internal tasks, so it's the
ability to search by date that makes the API at all interesting. When
searching by date, you don't send the `id` parameter to the API, but
instead use some of the parameters below (along with any of the data
fields from above):
- `mode` -- set to `last`, `modified`, or `newer`
- `timefirst` -- a date formatted as `YYYY-MM-DD`
- `timelast` -- a date formatted as `YYYY-MM-DD`
- `timenewer` -- a time formatted as `YYYY-MM-DD%20HH:MM:SS`
- `idnewer` -- a LibGen ID
- `limit1` -- an integer
- `limit2` -- an integer
Using these parameters allows you to do two things:
- ~~retrieve information about a random set of texts from within a
specified date range,~~ (see below) or
- retrieve information about texts modified after a certain time.
#### The grab-bag method
~~The obvious use case for this method is to display a random text or
set of texts (perhaps for a Twitter bot).~~ **I obviously didn't test
the API enough,** because this method is *not* random. I'll look into it
more when I have the time.
The following parameters and values are allowed here:
- `mode` -- either `last` or `modified`. If you use `last`, the API
will match the dates you specify against text's `timeadded`; if you
use `modified`, it will look at `timelastmodified`.
- `timefirst` -- the API will not return texts before this date
(checked against either `timeadded` or `timelastmodified` depending
on what the `mode` is set to). The first books have a `TimeAdded`
value of `2009-07-20`, and setting `timefirst` to an earlier date
will return an SQL error from the API.
- `timelast` (optional) -- the API will not return texts after this
date.
- `limit1` and `limit2` (both optional) -- if both of these parameters
are set, the number of results returned will be the value of
`limit2`, and the set of results will be offset by the value of
`limit1` (not very important here, where the results are random). If
only `limit1` is set, its value is the number of results returned.
Here's an example. This query returns 10 ~~random~~ MD5 hashes for texts
added between 1 May 2013 and 1 January 2014:
```text
curl 'http://libgen.io/json.php?fields=MD5&limit1=10&mode=last&timefirst=2013-05-01&timelast=2014-01-01'
```
#### The `newer` method
This method, which is literally *newer* -- it was added at the beginning
of 2014 -- finally allows the API to effectively serve its intended
purpose: incremental updates from one of the main servers to a local
mirror.
- `mode` -- must be set to `newer`
- `timenewer` -- the API will return information on texts *modified*
(not added) after this time, starting with the text closest to the
specified time.
- `idnewer` -- the API will not return information on texts with an ID
lower than the value of `idnewer`, even if it was modified after
`timenewer`. (If you don't care about this parameter you can set it
to `1`, but it is required.)
- `limit1` and `limit2` (optional) -- these parameters behave the same
as they do with the grab-bag method.
You could use this method to display new books, but the grab-bag method
can do that well enough for most purposes. I can't think of many uses
for `newer` beyond its original intended one -- mirroring the main
database.
#### Are you sure there's no search API?
Pretty sure, yeah. (There appears to be [a search API for
Bookfi](http://genofond.org/viewtopic.php?p=22423&sid=a2cc032762a2b853b4354d287e4697e6&usg=ALkJrhjEraSeb6V9MMjk1_OCbXy2Ml_B4Q#p22423 "Russian forum post"),
but you need to request an API key from the author.)
But the lack of a search API hasn't stopped people from writing scripts
to search for and download texts from Library Genesis:
- A [Node.js
module](https://www.npmjs.org/package/libgen "npm project page") by
me
- A [Python
script](https://github.com/anomico/libgen.py "GitHub repository") by
"anomico"
- An [Alfred
workflow](https://github.com/smargh/alfred_libgen "GitHub repository")
by [Stephen Margheim](http://hackademic.postach.io)
- A [Chrome
extension](https://github.com/toddpress/Looky_Booky "GitHub repository")
by "toddpress"
[Let me know](https://twitter.com/dunndunndunn "Twitter") if you write
your own!

236
posts/libgen.org Normal file
View file

@ -0,0 +1,236 @@
#+TITLE: The Library Genesis API
#+DATE: <2014-10-01 Wed>
#+DESCRIPTION: An English-language guide to using the LibGen API.
[[http://libgen.io][Library Genesis]] has an API, but the only documentation is [[http://genofond.org/viewtopic.php?p=39355][a forum thread in
Russian]]. So this is an English-language guide to using the LibGen API.
(I don't know Russian, and had to read the original thread using [[https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fgenofond.org%2Fviewtopic.php%3Fp%3D39355][Google
Translate]], so corrections and additions are very welcome!)
* First, some bad news
_This is not a search API._
The API was apparently written to help LibGen maintainers keep their
local mirrors up-to-date, which would explain why the API does not
support the most common use that Library Genesis is put to by the rest
of us: searching for texts. You can't (as far as I can tell) submit a
string and get a list of results based on that string.
There are two _documented_ ways to use the API to query the LibGen
database: by text ID, or by date.
* Querying by ID
Here's how to retrieve information about the texts with the coveted IDs
of =1= and =2=:
#+BEGIN_SRC
curl 'http://libgen.io/json.php?ids=1,2&fields=Title,Author,MD5'
#+END_SRC
(The API is available at =http://gen.lib.rus.ec/json.php= as well.)
The above `curl` request will return an array of JSON objects:
#+BEGIN_SRC json
[
{
"title":"Handbook of Clinical Drug Data",
"author":"Philip Anderson",
"md5":"7B2A4D53FDE834E801C26A2BAB7E0240"
},
{
"title":"Handbook of Herbs and Spices",
"author":"K V Peter",
"md5":"048EA0496DB0444F873139CD705A07AF"
}
]
#+END_SRC
I used these three fields -- =title=, =author=, and =md5= -- because
they're all you need in most situations. You can get the page URL by
appending the MD5 to =http://libgen.io/book/index.php?md5== or to one of
the mirrors:
- =http://gen.lib.rus.ec/book/index.php?md5==
- =http://bookzz.org/md5/=
- =http://bookfi.org/md5/=
You can create a download URL by appending the MD5 to
=http://libgen.io/get.php?md5==.
There are other mirrors whose URLs are based on the text's LibGen ID,
rather than the MD5:
- =http://libgen.net/view.php?id==
- =http://www.libgen.net/view.php?id==
- =http://libgen.iofo/view.php?id==
- =http://lib.freescienceengineering.org/view.php?id==
You can't get a direct download link for these; you have to go to the
page for the text and download from there.
But =title=, =author=, and =md5= are far from the only available data
fields; the full list is below. I haven't figured out what all the
fields mean, and keep in mind that it's up to the person uploading a
text to add this metadata, so not all texts are well-annotated.
- =id= -- the LibGen ID
- =title= -- the title of the text
- =volumeinfo= -- the volume number, if the text is part of a multi-volume series
- =series= -- the series that the text is part of
- =periodical=
- =author= -- the author of the text
- =year= -- the publication date of the text
- =edition= -- the edition of the text
- =publisher= -- the publisher of the text
- =city= -- the location of the publisher
- =pages= -- the number of pages in the text
- =language= -- the language of the text
- =topic= -- A number corresponding to the topic of the text; for example, =130= is "Mathematics/Logic"
- =library=
- =issue=
- =identifier= -- the text's short and long [[https://www.isbn-international.org/content/what-isbn][International Standard Book Numbers]] (not necessarily in that order)
- =issn= -- the text's [[http://www.issn.org/understanding-the-issn/what-is-an-issn/][International Standard Serial Number]]
- =asin= -- the text's [[http://www.amazon.com/gp/seller/asin-upc-isbn-info.html][Amazon Standard Identification Number]]
- =udc= -- the text's [[https://en.wikipedia.org/wiki/Universal_Decimal_Classification][Universal Decimal Classification]] number
- =lbc=
- =ddc= -- the text's [[https://en.wikipedia.org/wiki/Dewey_Decimal_Classification][Dewey Decimal Classification]] number
- =lcc= -- the text's [[https://en.wikipedia.org/wiki/Library_of_Congress_Classification][Library of Congress Classification]] number
- =doi= -- the file's [[https://en.wikipedia.org/wiki/Digital_object_identifier][Digital Object Identifier]]
- =googlebookid= -- the text's [[https://developers.google.com/books/docs/v1/using#ids][Google Books ID]]
- =openlibraryid= -- the text's [[https://openlibrary.org/dev/docs/api/books][Open Library ID]]
- =commentary=
- =dpi=
- =color=
- =cleaned=
- =orientation=
- =paginated= -- the text is paginated (=1=) or not (=0=)
- =scanned= -- the text is scanned from a physical copy (=1=) or not (=0=)
- =bookmarked= -- the text has bookmarks (=1=) or not (=0=)
- =searchable= -- the text is searchable (=1=) or not (=0=)
- =filesize= -- the size of the file in bytes
- =extension= -- the extension of the file (=.pdf=, =.epub=, =.mobi=, etc.)
- =md5= -- the [MD5](http://www.md5.net) hash of the file
- =crc32= -- the file's [[http://www.riccibitti.com/crcguide.htm][CRC32]] checksum
- =edonkey= -- the file's [[https://en.wikipedia.org/wiki/Ed2k_URI_scheme][eDonkey hash]]
- =aich= -- the text's [[http://www.emule-project.net/home/perl/help.cgi?l=1&rm=show_topic&topic_id=589][eMule file hash]]
- =sha1= -- the file's [[https://en.wikipedia.org/wiki/SHA-1][SHA-1]] hash
- =tth= -- the file's [[https://en.wikipedia.org/wiki/Merkle_tree#Tiger_tree_hash][Tiger tree hash]]
- =generic=
- =filename= -- the name of the file in the LibGen database, in the
form =directory/md5=. The directory name is the text's LibGen ID
rounded to the nearest thousand, and the MD5 hash is in lowercase.
(The directory that each file is located in is [[https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/util.php#L6][also included in the file name]].)
- =visible=
- =locator= -- [[https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/librarian/form.php#L187][As far as I can tell]], this is the file path of the original file on the machine of whoever uploaded it.
- =local=
- =timeadded= -- the date/time when the text was added to the database, formatted as =YYYY-MM-DD HH:MM:SS=
- =timelastmodified= -- the date/time when the text's entry in the database was edited, formatted as =YYYY-MM-DD HH:MM:SS=
- =coverurl= -- the path to the cover image for the text: the =filename= followed by a lowercase letter (there's [[https://github.com/lgsoft-developers/libgen/blob/c45f441c7aaa56ae690a6a6503295995a044a76b/book/util.php#L30][a function]] to determine the letter for each cover, but I don't know enough PHP to understand it).
If you want to get all fields for a text, use =fields=*=.
* Searching by date
Querying by ID is pretty useless except for internal tasks, so it's the
ability to search by date that makes the API at all interesting. When
searching by date, you don't send the =id= parameter to the API, but
instead use some of the parameters below (along with any of the data
fields from above):
- =mode= -- set to =last=, =modified=, or =newer=
- =timefirst= -- a date formatted as =YYYY-MM-DD=
- =timelast= -- a date formatted as =YYYY-MM-DD=
- =timenewer= -- a time formatted as =YYYY-MM-DD%20HH:MM:SS=
- =idnewer= -- a LibGen ID
- =limit1= -- an integer
- =limit2= -- an integer
Using these parameters allows you to do two things:
- +retrieve information about a random set of texts from within a
specified date range,+ (see below) or
- retrieve information about texts modified after a certain time.
** The grab-bag method
+The obvious use case for this method is to display a random text or
set of texts (perhaps for a Twitter bot).+ *I obviously didn't test
the API enough,* because this method is _not_ random. I'll look into it
more when I have the time.
The following parameters and values are allowed here:
- =mode= -- either =last= or =modified=. If you use =last=, the API
will match the dates you specify against text's =timeadded=; if you
use =modified=, it will look at =timelastmodified=.
- =timefirst= -- the API will not return texts before this date
(checked against either =timeadded= or =timelastmodified= depending
on what the =mode= is set to). The first books have a =TimeAdded=
value of =2009-07-20=, and setting =timefirst= to an earlier date
will return an SQL error from the API.
- =timelast= (optional) -- the API will not return texts after this
date.
- =limit1= and =limit2= (both optional) -- if both of these parameters
are set, the number of results returned will be the value of
=limit2=, and the set of results will be offset by the value of
=limit1= (not very important here, where the results are random). If
only =limit1= is set, its value is the number of results returned.
Here's an example. This query returns 10 +random+ MD5 hashes for texts
added between 1 May 2013 and 1 January 2014:
#+BEGIN_SRC
curl 'http://libgen.io/json.php?fields=MD5&limit1=10&mode=last&timefirst=2013-05-01&timelast=2014-01-01'
#+END_SRC
** The =newer= method
This method, which is literally _newer_ -- it was added at the beginning
of 2014 -- finally allows the API to effectively serve its intended
purpose: incremental updates from one of the main servers to a local
mirror.
- =mode= -- must be set to =newer=
- =timenewer= -- the API will return information on texts *modified*
(not added) after this time, starting with the text closest to the
specified time.
- =idnewer= -- the API will not return information on texts with an ID
lower than the value of =idnewer=, even if it was modified after
=timenewer=. (If you don't care about this parameter you can set it
to =1=, but it is required.)
- =limit1= and =limit2= (optional) -- these parameters behave the same
as they do with the grab-bag method.
You could use this method to display new books, but the grab-bag method
can do that well enough for most purposes. I can't think of many uses
for =newer= beyond its original intended one -- mirroring the main
database.
* Are you sure there's no search API?
Pretty sure, yeah. (There appears to be [[http://genofond.org/viewtopic.php?p=22423&sid=a2cc032762a2b853b4354d287e4697e6&usg=ALkJrhjEraSeb6V9MMjk1_OCbXy2Ml_B4Q#p22423][a search API for Bookfi]], but you need to
request an API key from the author.)
But the lack of a search API hasn't stopped people from writing scripts
to search for and download texts from Library Genesis:
- A [[https://www.npmjs.org/package/libgen][Node.js module]] by me
- A [[https://github.com/anomico/libgen.py][Python script]] by "anomico"
- An [[https://github.com/smargh/alfred_libgen][Alfred workflow]] by [Stephen Margheim](http://hackademic.postach.io)
- A [[https://github.com/toddpress/Looky_Booky][Chrome extension]] by "toddpress"
[[https://twitter.com/dunndunndunn][Let me know]] if you write your own!

View file

@ -1,27 +1,22 @@
---
title: The Hardest Problem In Computer Science is Opening a Port
date: 2020-06-09
description: Or, how to get RTMP working in Kubernetes.
layout: layouts/post.njk
tags: post
---
#+TITLE: The Hardest Problem In Computer Science is Opening a Port
#+DATE: <2020-06-09 Tue>
#+DESCRIPTION: Or, how to get RTMP working in Kubernetes.
All I wanted was to open port 1935 so that I could run my
[MovieNight](https://github.com/zorchenhimer/MovieNight) instance in a cluster.
But I couldnt find anywhere describing all the steps to actually open a port on
Kubernetes. But #ShePersisted or whatever.
All I wanted was to open port 1935 so that I could run my [[https://github.com/zorchenhimer/MovieNight][MovieNight]] instance in
a cluster. But I couldnt find anywhere describing all the steps to actually
open a port on Kubernetes. But #ShePersisted or whatever.
**NB:** a non-http port (like 1935 for RTMP, or 21 for FTP, or) can only be made
accessible to one (1) service in your entire cluster. So choose wisely. Yes,
this is batshit.
## Configuration the Application
* Configuration the Application
If youre deploying your application with a Helm chart, make sure that its
service type is NodePort, and specify each port you want accessible in its
`service.yaml`:
=service.yaml=:
```yaml
#+BEGIN_SRC yaml
apiVersion: v1
kind: Service
metadata:
@ -41,12 +36,13 @@ spec:
name: rtmp
selector:
{{- include "movienight.selectorLabels" . | nindent 4 }}
```
#+END_SRC
List the same additional ports in your applications `deployment.yaml` (here
8089 is what we are exposing as port 80, since thats what MovieNight binds to
by default):
```yaml
List the same additional ports in your applications =deployment.yaml=
(here 8089 is what we are exposing as port 80, since thats what MovieNight
binds to by default):
#+BEGIN_SRC yaml
containers:
- name: {{ .Chart.Name }}
securityContext:
@ -60,12 +56,13 @@ by default):
- name: rtmp
containerPort: 1935
protocol: TCP
```
#+END_SRC
## Configure the Ingress Controller
* Configure the Ingress Controller
Find your ingress controller service and deployments in the cluster:
```text
#+BEGIN_SRC
$ kubectl get all
NAME READY STATUS RESTARTS AGE
@ -81,54 +78,53 @@ deployment.apps/ingress-ingress-nginx-controller 1/1 1 1
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-ingress-nginx-controller-7555b9d446 1 1 1 89s
```
#+END_SRC
To open port 1935 like you see above, first edit the deployment definition:
```text
#+BEGIN_SRC
kubectl edit deployment.apps/ingress-ingress-nginx-controller
```
#+END_SRC
And add two things:
1. in `spec.containers.ports`, add the port you want open (I want 1935, which is
RTMP):
```yaml
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 1935
name: rtmp
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
```
1. in =spec.containers.ports=, add the port you want open (I want 1935, which is
RTMP):
#+BEGIN_SRC yaml
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 1935
name: rtmp
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
#+END_SRC
2. in =spec.containers.args=, add a line for [[https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/][=tcp-services-configmap=]]:
#+BEGIN_SRC yaml
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=default/ingress-ingress-nginx-controller
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=default/ingress-ingress-nginx-controller
- --tcp-services-configmap=default/tcp-services
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
#+END_SRC
2. in `spec.containers.args`, add a line for
[`tcp-services-configmap`](https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/):
```yaml
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=default/ingress-ingress-nginx-controller
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=default/ingress-ingress-nginx-controller
- --tcp-services-configmap=default/tcp-services
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
```
`default/tcp-services` refers to the namespace and name of the ConfigMap youre
=default/tcp-services= refers to the namespace and name of the ConfigMap youre
about to create:
```yaml
#+BEGIN_SRC yaml
---
apiVersion: v1
kind: ConfigMap
@ -137,25 +133,27 @@ metadata:
namespace: default
data:
1935: "movienight/trashcloud-movienight:1935"
```
#+END_SRC
Here `movienight/trashcloud-movienight` refers to the namespace and service name
of your application.
Here =movienight/trashcloud-movienight= refers to the namespace and
service name of your application.
Install your ConfigMap:
```text
#+BEGIN_SRC
kubectl apply -f tcp-services.yaml
```
#+END_SRC
Then, edit the service definition of the ingress controller:
```text
kubectl edit service/ingress-ingress-nginx-controller
```
In `spec.ports`, add an entry for the new port, and assign it an unused
[NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport)
between 30000 and 32767:
```yaml
#+BEGIN_SRC
kubectl edit service/ingress-ingress-nginx-controller
#+END_SRC
In =spec.ports=, add an entry for the new port, and assign it an unused
[[https://kubernetes.io/docs/concepts/services-networking/service/#nodeport][NodePort]] between 30000 and 32767:
#+BEGIN_SRC yaml
spec:
clusterIP: 10.128.94.66
externalTrafficPolicy: Cluster
@ -175,7 +173,7 @@ spec:
port: 1935
protocol: TCP
targetPort: 1935
```
#+END_SRC
And that should do it! Im very sleep deprived on account of this nonsense so
if Ive forgotten a step let me know.

28
publish.el Normal file
View file

@ -0,0 +1,28 @@
(require 'package)
(package-initialize)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
(package-refresh-contents)
(require 'org)
(require 'org-static-blog)
(let ((org-static-blog-publish-title "GARBAGE WORLD")
(org-static-blog-publish-url "")
(org-static-blog-publish-directory "")
(org-static-blog-posts-directory "posts/")
(org-static-blog-drafts-directory "drafts/")
(org-static-blog-enable-tags nil)
(org-export-with-toc nil)
(org-export-with-section-numbers nil)
(org-static-blog-page-header
"<meta charset=\"utf-8\">
<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />
<link href=\"stylesheets/screen.css\" rel=\"stylesheet\" type=\"text/css\" media=\"screen\" />
<link href=\"stylesheets/print.css\" rel=\"stylesheet\" type=\"text/css\" media=\"print\" />")
(org-static-blog-page-preamble
"<header>
<h1><a href=\"/\" title=\"root\">🖥😩</a></h1>
</header>"))
(org-static-blog-publish t))

View file

@ -31,6 +31,15 @@ aside {
}
}
.post-date {
font-style: italic;
font-weight: bold;
}
.post-title {
margin-top: 0;
}
img {
border: 5px solid black;
margin: 1em;
@ -46,6 +55,12 @@ footer {
min-width: 20%;
}
pre {
background: #1e1e1e;
color: white;
padding: 5px;
}
dt {
font-weight: bold;
}

8
setup.el Normal file
View file

@ -0,0 +1,8 @@
(require 'package)
(package-initialize)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
(package-refresh-contents)
(package-install 'org)
(package-install 'org-static-blog)

View file

@ -1,2 +0,0 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
/*# sourceMappingURL=normalize-8.0.1.css.map */

View file

@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "AAAA,4EAA4E,AAU5E,IAAK,CACH,WAAW,CAAE,IAAI,CACjB,wBAAwB,CAAE,IAAI,CAUhC,IAAK,CACH,MAAM,CAAE,CAAC,CAOX,IAAK,CACH,OAAO,CAAE,KAAK,CAQhB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAWlB,EAAG,CACD,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CAQnB,GAAI,CACF,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAUhB,CAAE,CACA,gBAAgB,CAAE,WAAW,CAQ/B,WAAY,CACV,aAAa,CAAE,IAAI,CACnB,eAAe,CAAE,SAAS,CAC1B,eAAe,CAAE,gBAAgB,CAOnC,QACO,CACL,WAAW,CAAE,MAAM,CAQrB,aAEK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAOhB,KAAM,CACJ,SAAS,CAAE,GAAG,CAQhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,MAAM,CAAE,OAAO,CAGjB,GAAI,CACF,GAAG,CAAE,MAAM,CAUb,GAAI,CACF,YAAY,CAAE,IAAI,CAWpB,qCAIS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,MAAM,CAAE,CAAC,CAQX,YACM,CACJ,QAAQ,CAAE,OAAO,CAQnB,aACO,CACL,cAAc,CAAE,IAAI,CAOtB,qDAGgB,CACd,kBAAkB,CAAE,MAAM,CAO5B,6HAGkC,CAChC,YAAY,CAAE,IAAI,CAClB,OAAO,CAAE,CAAC,CAOZ,iHAG+B,CAC7B,OAAO,CAAE,qBAAqB,CAOhC,QAAS,CACP,OAAO,CAAE,qBAAqB,CAUhC,MAAO,CACL,UAAU,CAAE,UAAU,CACtB,KAAK,CAAE,OAAO,CACd,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CAOrB,QAAS,CACP,cAAc,CAAE,QAAQ,CAO1B,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,gCACe,CACb,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CAOZ,qFAC2C,CACzC,MAAM,CAAE,IAAI,CAQd,eAAgB,CACd,kBAAkB,CAAE,SAAS,CAC7B,cAAc,CAAE,IAAI,CAOtB,0CAA2C,CACzC,kBAAkB,CAAE,IAAI,CAQ1B,4BAA6B,CAC3B,kBAAkB,CAAE,MAAM,CAC1B,IAAI,CAAE,OAAO,CAUf,OAAQ,CACN,OAAO,CAAE,KAAK,CAOhB,OAAQ,CACN,OAAO,CAAE,SAAS,CAUpB,QAAS,CACP,OAAO,CAAE,IAAI,CAOf,QAAS,CACP,OAAO,CAAE,IAAI",
"sources": ["../sass/normalize-8.0.1.scss"],
"names": [],
"file": "normalize-8.0.1.css"
}

View file

@ -1,2 +0,0 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
/*# sourceMappingURL=print.css.map */

View file

@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "AAAA,4EAA4E,AAU5E,IAAK,CACH,WAAW,CAAE,IAAI,CACjB,wBAAwB,CAAE,IAAI,CAUhC,IAAK,CACH,MAAM,CAAE,CAAC,CAOX,IAAK,CACH,OAAO,CAAE,KAAK,CAQhB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAWlB,EAAG,CACD,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CAQnB,GAAI,CACF,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAUhB,CAAE,CACA,gBAAgB,CAAE,WAAW,CAQ/B,WAAY,CACV,aAAa,CAAE,IAAI,CACnB,eAAe,CAAE,SAAS,CAC1B,eAAe,CAAE,gBAAgB,CAOnC,QACO,CACL,WAAW,CAAE,MAAM,CAQrB,aAEK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAOhB,KAAM,CACJ,SAAS,CAAE,GAAG,CAQhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,MAAM,CAAE,OAAO,CAGjB,GAAI,CACF,GAAG,CAAE,MAAM,CAUb,GAAI,CACF,YAAY,CAAE,IAAI,CAWpB,qCAIS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,MAAM,CAAE,CAAC,CAQX,YACM,CACJ,QAAQ,CAAE,OAAO,CAQnB,aACO,CACL,cAAc,CAAE,IAAI,CAOtB,qDAGgB,CACd,kBAAkB,CAAE,MAAM,CAO5B,6HAGkC,CAChC,YAAY,CAAE,IAAI,CAClB,OAAO,CAAE,CAAC,CAOZ,iHAG+B,CAC7B,OAAO,CAAE,qBAAqB,CAOhC,QAAS,CACP,OAAO,CAAE,qBAAqB,CAUhC,MAAO,CACL,UAAU,CAAE,UAAU,CACtB,KAAK,CAAE,OAAO,CACd,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CAOrB,QAAS,CACP,cAAc,CAAE,QAAQ,CAO1B,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,gCACe,CACb,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CAOZ,qFAC2C,CACzC,MAAM,CAAE,IAAI,CAQd,eAAgB,CACd,kBAAkB,CAAE,SAAS,CAC7B,cAAc,CAAE,IAAI,CAOtB,0CAA2C,CACzC,kBAAkB,CAAE,IAAI,CAQ1B,4BAA6B,CAC3B,kBAAkB,CAAE,MAAM,CAC1B,IAAI,CAAE,OAAO,CAUf,OAAQ,CACN,OAAO,CAAE,KAAK,CAOhB,OAAQ,CACN,OAAO,CAAE,SAAS,CAUpB,QAAS,CACP,OAAO,CAAE,IAAI,CAOf,QAAS,CACP,OAAO,CAAE,IAAI",
"sources": ["../sass/normalize-8.0.1.scss"],
"names": [],
"file": "print.css"
}

View file

@ -1,2 +0,0 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}*,*:before,*:after{box-sizing:border-box}body{font-family:monospace;font-size:14pt;padding:0 1em}header{padding:1em;text-align:right}header h1,header h2{margin:0}header h2,aside h2{font-style:italic}img{border:5px solid black;margin:1em;width:100%}article+article{padding-top:2em}aside,footer{min-width:20%}dt{font-weight:bold}h1{font-size:225%}h2{font-size:150%}h3{font-size:131.25%}h4,h5,h6{font-size:112.5%}h5,h6{font-style:italic}h6{font-weight:normal}
/*# sourceMappingURL=screen.css.map */

View file

@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "AAAA,4EAA4E,AAU5E,IAAK,CACH,WAAW,CAAE,IAAI,CACjB,wBAAwB,CAAE,IAAI,CAUhC,IAAK,CACH,MAAM,CAAE,CAAC,CAOX,IAAK,CACH,OAAO,CAAE,KAAK,CAQhB,EAAG,CACD,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,QAAQ,CAWlB,EAAG,CACD,UAAU,CAAE,WAAW,CACvB,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CAQnB,GAAI,CACF,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAUhB,CAAE,CACA,gBAAgB,CAAE,WAAW,CAQ/B,WAAY,CACV,aAAa,CAAE,IAAI,CACnB,eAAe,CAAE,SAAS,CAC1B,eAAe,CAAE,gBAAgB,CAOnC,QACO,CACL,WAAW,CAAE,MAAM,CAQrB,aAEK,CACH,WAAW,CAAE,oBAAoB,CACjC,SAAS,CAAE,GAAG,CAOhB,KAAM,CACJ,SAAS,CAAE,GAAG,CAQhB,OACI,CACF,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,CAAC,CACd,QAAQ,CAAE,QAAQ,CAClB,cAAc,CAAE,QAAQ,CAG1B,GAAI,CACF,MAAM,CAAE,OAAO,CAGjB,GAAI,CACF,GAAG,CAAE,MAAM,CAUb,GAAI,CACF,YAAY,CAAE,IAAI,CAWpB,qCAIS,CACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,MAAM,CAAE,CAAC,CAQX,YACM,CACJ,QAAQ,CAAE,OAAO,CAQnB,aACO,CACL,cAAc,CAAE,IAAI,CAOtB,qDAGgB,CACd,kBAAkB,CAAE,MAAM,CAO5B,6HAGkC,CAChC,YAAY,CAAE,IAAI,CAClB,OAAO,CAAE,CAAC,CAOZ,iHAG+B,CAC7B,OAAO,CAAE,qBAAqB,CAOhC,QAAS,CACP,OAAO,CAAE,qBAAqB,CAUhC,MAAO,CACL,UAAU,CAAE,UAAU,CACtB,KAAK,CAAE,OAAO,CACd,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CAOrB,QAAS,CACP,cAAc,CAAE,QAAQ,CAO1B,QAAS,CACP,QAAQ,CAAE,IAAI,CAQhB,gCACe,CACb,UAAU,CAAE,UAAU,CACtB,OAAO,CAAE,CAAC,CAOZ,qFAC2C,CACzC,MAAM,CAAE,IAAI,CAQd,eAAgB,CACd,kBAAkB,CAAE,SAAS,CAC7B,cAAc,CAAE,IAAI,CAOtB,0CAA2C,CACzC,kBAAkB,CAAE,IAAI,CAQ1B,4BAA6B,CAC3B,kBAAkB,CAAE,MAAM,CAC1B,IAAI,CAAE,OAAO,CAUf,OAAQ,CACN,OAAO,CAAE,KAAK,CAOhB,OAAQ,CACN,OAAO,CAAE,SAAS,CAUpB,QAAS,CACP,OAAO,CAAE,IAAI,CAOf,QAAS,CACP,OAAO,CAAE,IAAI,CCvVf,kBAEQ,CACN,UAAU,CAAE,UAAU,CAGxB,IAAK,CACH,WAAW,CAAE,SAAS,CACtB,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,KAAK,CAGhB,MAAO,CACL,OAAO,CAAE,GAAG,CACZ,UAAU,CAAE,KAAK,CAEjB,mBACG,CACD,MAAM,CAAE,CAAC,CAMX,kBAAG,CACD,UAAU,CAAE,MAAM,CAItB,GAAI,CACF,MAAM,CAAE,eAAe,CACvB,MAAM,CAAE,GAAG,CACX,KAAK,CAAE,IAAI,CAGb,eAAkB,CAChB,WAAW,CAAE,GAAG,CAGlB,YACO,CACL,SAAS,CAAE,GAAG,CAGhB,EAAG,CACD,WAAW,CAAE,IAAI,CAGnB,EAAG,CACD,SAAS,CAAE,IAAI,CAGjB,EAAG,CACD,SAAS,CAAE,IAAI,CAGjB,EAAG,CACD,SAAS,CAAE,OAAO,CAGpB,QAEG,CACD,SAAS,CAAE,MAAM,CAGnB,KACG,CACD,UAAU,CAAE,MAAM,CAGpB,EAAG,CACD,WAAW,CAAE,MAAM",
"sources": ["../sass/normalize-8.0.1.scss","../sass/screen.scss"],
"names": [],
"file": "screen.css"
}