Béton brut

Zrobić dobrze mokrym palcem

Kiedy kota nie ma, myszy harcują. Piotrek wyjechał w delegację, a ja zostałem na włościach pomiędzy rzędami komputerów które czekają na ostatnie szlify przed otwarciem muzeum. Te ostatnie szlify przypominają czasem ostatnie namaszczenie, wszystko wydaje się działać póki się temu z bliska nie przyjrzeć. Weźmy takie Atari MEGA STE. Całkiem ładny komputer, włączony działa. Chcieliśmy puścić zeń trochę muzyki. Grał, grał, przestał. Reset. W ogóle przestał grać, od razu mówi, że nie ma pamięci, nie widać nawet wirtualnych twardych dysków. Nawet stacja dyskietek zniknęła.

Usiadłem przy nim jak ksiądz i spowiadałem go ze wszystkich grzechów, wynotowując te ciężkie i lekkie.1 Ostatecznie udało mi się ustalić jak go zawiesić za każdym razem: wirtualne twarde dyski serwowane z karty SD przez sprytne urządzonko chodzą pod kontrolą FAT12, a ten ma spore ograniczenia. Na przykład katalog z muzyką zawierający ponad pięć tysięcy elementów zdecydowanie przekracza jego możliwości, sterownik nic sobie jednak z tego nie robi i prawdopodobnie pisze po pamięci jak dziecko kredką po świeżo malowanych ścianach, zawieszając cały podsystem w efekcie.

Napisałem szybko kilka linijek które poukładały pliki w podfolderach zgodnie z pierwszą literą nazwy pliku. Problem rozwiązany.

Jeden dobry uczynek należy natychmiast wyzerować uczynkiem potencjalnie złym. Łażąc z miejsca na miejsce przypomniałem sobie o starym micie powtarzanym na szkolnych korytarzach zawierającym jednocześnie obietnicę i przestrogę: jeśli poślinisz palec i dotkniesz go do pierwszego portu dżojstika uzyskasz nieśmiertelność w niektórych grach, ale jeśli zrobisz to źle uszkodzisz swój komputer.

Była to prawda w obu przypadkach. Port dżojstika jest podłączony bezpośrednio do układu CIA w C642, jeśli się nie uziemimy możemy mu wysłać niespodziewany ładunek i doprowadzić do małej katastrofy. Faktem jest, że niektóre gry, najsłynniejszy przypadek to chyba Creatures II: Torture Trouble, reagowały na taką e-intymność obdarzając gracza nieśmiertelnością lub jakąś inną niespodzianką.

Niejasno pamiętam też, że przepisywałem z jakiegoś magazynu program, który reagował na to mizianie, pamiętam też, że od wstępu krzyczał żeby tego nie robić. Kiedy stałem więc przy C64 zamyśliłem się. Jak to działa, tak dokładnie? Teoretycznie może działa to tak, że zwierając port generujemy sygnał wychyłu dżojstika. Ale to chyba nie to. Zerknąłem na schemat portu. No tak, wiosełka.

Wszyscy wiedzą jak działa dżojstik. Wychylasz go w lewo, postać idzie w lewo. Jest to sygnał cyfrowy, albo zaistniał albo nie. W czasach, gdy światem gier elektronicznych rządził Pong i tysiące klonów i/lub wariacji na jego temat, popularnym kontrolerem były wiosełka. Możecie o nich myśleć jako o jednym lub dwóch rezystorach nastawnych (potencjometrach), które dawały kontrolę i płynność jakiej nie mógł dać drążki. Na potencjometr nadziewano ergonomiczną gałkę i już kręcąc nią z lewa w prawo i nazad mogliście przesuwać swoją pongową paletkę. Ponieważ zmiany w oporności można wyrazić w pewnym kontinuum, maksymalny wychył w jedną czy drugą stronę mógł być skorelowany z wyświetlaną grafiką, dzięki temu gracz może bardziej naturalnie reagować na wydarzenia (potencjometr na środku równa się paletka na środku pola gry).

Narysowany w PETSCII port dżojstika z opisanymi portami odpowiadającymi za wiosełka

C64 ma wsparcie dla wiosełek, piny 5 i 9 w obu portach są pinami analogowymi, a ich wartość zapisywana jest w dwóch jednobajtowych rejestrach, skąd można je odczytać: $D419 (X) i $D41A (Y). Z uwagi na ich naturę są bardziej „wrażliwe” na niewielkie zmiany w oporności (tu: pazur penetrujący port) i łatwiej jest wyłapać takie zdarzenie.

10 REM NIE ROBCIE TEGO W DOMU (ANI W MUZUEM)
20 IF PEEK(54298) < 255 OR PEEK(54297) < 255 THEN GOTO 100
30 GOTO 20
100 PRINT "MAM NADZIEJE, ZE NIE SPALILES CIA"

Dlaczego sprawdzamy 255? To maksymalna rezystancja oraz maksymalna wartość jaką możemy zapisać w bajcie rejestru, pin nie jest do niczego podłączony, nasz palec wystarczy aby obniżyć tę wartość i spełnić przynajmniej jeden z warunków.

A może jeszcze gorszy pomysł? Commodore 64 nie ma na standardowym wyposażeniu przycisku reset, można by dodać obsługę resetowania przez polizany palec. Dodajemy jednocześnie element rosyjskiej ruletki: czy udało nam się go zresetować, czy też zawiesił się zniszczony!

Można użyć do tego przerwań, podwiesimy naszą procedurę badającą rejestry i jeśli ich wartość ulegnie zmianie wywołamy procedurę resetu. Niestety, pisałem to bez dostępu do prawdziwego komputera, emulatory nie mają wbudowanej opcji ślinienia portów (choć na BMC64 jest to prawdopodobnie możliwe, wystarczy wyprowadzić port na GPIO), musiałem więc testować kolor tekstu ($0286, 14 to standardowy szaro-niebieski) żeby sprawdzić hipotezę. Ostatecznie to PoSC. Proof of Stupid Concept.

BasicUpstart2(main) // preambuła dla BASICa

* = $c000

finger_irq:
    pha // ponieważ używamy akumulatora
        // musimy się nim zająć sami
    // IF PEEK(54297) < 255
    lda $d419
    cmp #255
    bne goodbye_cruel_world
    lda $d41a
    cmp #255
    bne goodbye_cruel_world
    //lda $0286 // «debug»
    //cmp #14
    //bne goodbye_cruel_world
    pla // przywracamy wartość akumulatora
        // ze stosu
    jmp $ea31 // oddajemy kontrolę kernelowi
    rti

goodbye_cruel_world:
    jmp $fce2
    rts

main:
    sei // stop przerwaniom
    // instalujemy nasz własny wektor
    lda #<finger_irq
    sta $0314  
    lda #>finger_irq
    sta $0315  
    cli // przywracamy przerwania
    rts

Miło tak odkrywać na nowo rzeczy, które się już wiedziało, a które zostały wyparte przez ważniejszą wiedzę zawodową, na przykład że trzeba usuwać node_modules jak frontend nie działa. Pośliniony palec można wsadzić w oko frontendowcowi, może też się zresetuje?

  1. Choć wiemy, że Atari nie może iść do nieba
  2. co łatwo jest udowodnić, wystarczy podłączyć dżojstik do pierwszego portu i pokręcić nim. Bez wątpienia wyskoczy wam znak 2, i spacja, CIA dzieli linie pierwszego portu z matrycą klawiatury

Gwiazdkę z nieba

Obiecał mi wiele, a każda z tych obietnic niosła w sobie obietnicę kolejnych obietnic. Może taki był jego plan, obiecać mi tak wiele że nie będę mogła go rozliczyć. Nie żebym go rozliczała, starczało mi to, co jest. Nasze wygłupy, soboty, godziny spędzone nad spisywaniem szczegółowej listy całotygodniowych zakupów, którą natychmiast gubiliśmy.

Siedzimy na dachu bloku. Ukradł klucze cieciowi. Mówi, że pożyczył, a wiem, że nasz dozorca nie należy do typów pomocnych, choć nie wynika to z jego charakteru tylko z lat doświadczenia. Mieszka w tym budynku od wieków, nie wiemy nawet, czy jest rzeczywiście pracownikiem administracji, czy też stał się po prostu częścią mechanizmu dzielnicy, zna numery telefonów, wie, gdzie są bezpieczniki, zawory i klucze do nich. Tak na górze, jak i na dole, klucze na dach są także pod jego opieką, a raczej były, do dzisiaj.

Siedzimy na środku dachu na plastikowych krzesełkach wciągniętych po niewygodnej metalowej drabince. Boję się podejść bliżej brzegu. Oglądamy panoramę miasta. Samochody odpływają smugą czerwonych świateł, co jakiś czas rozlega się przytłumiony trzask zamykanych drzwi do klatki, bawimy się w zgadywanie kiedy zgaśnie światło w tym czy tamtym oknie, wyłączyliśmy z niej światła kuchenne, o tej godzinie w kuchniach zapala się światło tylko na chwilę.

— Chodźmy już — powiedziałam — zaczyna się robić zimno.

— Zaczyna się Tobie robić zimno! — podkreśli w odpowiedzi, starając się zawsze być dokładny w sprawach błahych.

— Dobrze, jest mi zimno. Możemy już iść? Boję się, że nas przyłapią, a nie jesteśmy już dziećmi żeby świecić oczami i spuszczać głowy w obliczu umocowanych dorosłych.

Podniósł się z krzesła, złożył je i podał mi rękę. A potem wstrzymał mnie gestem i podszedł do gzymsu budynku, oparł na nim jedną stopę jakby był kapitanem gotowym do odpłynięcia z całym blokiem. Podparł się pod boki i spojrzał w dół, a potem w górę.

— Nie stój tam, spadniesz. Boję się, że spadniesz, czemu mnie straszysz. Nie pobiegnę Ci na pomoc jeśli zawiśniesz rozpaczliwie na brzegu. Chodź.

Odwrócił się do mnie mówiąc: Zrobię to dla Ciebie, zrobię wszystko, dam Ci gwiazdkę z nieba.

— Na co mi gwiazdka z nieba, co bym z nią robiła, to tylko taki punkcik na derce wszechświata, jak już to wolałabym księżyc, zawsze myślałam, że księżyc wygląda jak taka wyskubana, okrągła gąbka. Miałam taką w dzieciństwie, ale była jasnoniebieska, nie szara. Może księżyc to po prostu stara gąbka, którą ktoś tam cisnął? — gadałam bez sensu żeby nie myśleć o tej krawędzi.

— Księżyc? Jasne! — zgodził się. Podbiegł do drabiny i zanim zdążyłam coś powiedzieć zniknął w głębi klatki schodowej. Kilka minut później wrócił, stanął przede mną i uśmiechnął się szeroko. Miał w rękach wędkę, której używał jako rekwizytu by czasem znikać z przyjaciółmi na weekend. Ryby złowionej nigdy nie widziałam, mówił że jedli je na bieżąco bo jak je trzymać tyle czasu bez lodu. Brzmi jak kłamstwo.

— Zaraz załatwimy tę sprawę z księżycem, nie wiem tylko na co się je bierze, raczej nie na robaki?

Śmieję się, gdy odstawia pantomimę zarzucania wędki. Wreszcie wykonał zamaszysty ruch i cisnął dociążoną żyłkę w kierunku nieba, a potem zaczął energicznie kręcić kołowrotkiem. Z jakiegoś powodu żyłka nie opadała za ścianę budynku, była naprężona i lekko drgała.

Cały świat się potknął. A księżyc na niebie stawał się coraz większy i większy. Niebo trzeszczało jak nadwyrężona stalowa belka na chwilę przed pęknięciem.

— Wreszcie dotrzymałeś słowa… — wyszeptałam niedowierzając.

— To chyba ostatni raz. — odpowiedział


64 ÷ 8 = Commodore 64

Ze wszystkich odruchów konsumpcjonizmu najgorszy jest konsumpcjonizm aspiracyjny. Jest jedną rzeczą kupować rzeczy ostentacyjne i zbyteczne, które błyszczą i szczerzą się zza mankietów kruszcem czy szlifem, inną rzeczą jest kupować rzeczy z myślą, że uczynią one z nas lepszych ludzi. Sztalugi i sztangi, notatniki i nici, gitary i garnki. Wszystkie w kącie, pokryte kurzem, nie zrobiły z nas malarzy, siłaczy, pisarzy, Slashy i kucharzy. Wszystkie te niezbyt drogie rzeczy, jedno kup teraz stąd, wyposażone w możliwość magiczną moc wyrwania tego lepszego ja z tego zwykłego. Łatwiej jest marzyć, marzenia są darmowe, z darmową dostawą.

Gdybym wszedł do Waszych domów pod ochroną uzbrojonej w niekonstytucjonalne narzędzia, tajnej policji i przeszukałbym Wasze szuflady, ile znalazłbym w nich Raspberry Pi, które kupiliście „do projektu”, ale brakowało Wam kabelka, czasu i wizji żeby go popchnąć dalej? Nie, nie zdążycie spuścić ich w kiblu, jesteśmy już na schodach.


Wrobiono mnie, czy też wrobiłem się sam, w ponowną próbę odpalenia naszego własnego muzeum komputerów w Łodzi. Minęło osiem lat odkąd wystartowaliśmy z wielkim hukiem, ale zabrakło mi zapału, życie się skomplikowało, wiele rzeczy mi zbrzydło i przestałem się udzielać. Ostatnio sprawa wróciła na wokandę i nadając sobie samozwańczy tytuł kustosza ośmiobitowców ruszyłem do pracy. Przebieram oprogramowanie, buduję listy, rozgryzam najlepsze sposoby serwowania tego wszystkiego gościom, próbuję pisać jakieś programy, z różnym skutkiem.

Podczas całonocnej, weekendowej, sesji przypomniałem sobie, że bawiłem się kiedyś emulatorem C64, portem VICE, który działa bezpośrednio na Raspberry Pi, bez pomocy kernela Linuksa. BMC64 startuje w sekundę, potrafi emulować całą gamę ośmiobitowców (C64, C128, C16, VIC20, PET), czyta obrazy dysków, kartridży, obsługuje pady pod USB, a na pinach GPIO można wyciągnąć sygnały kompatybilne z userportem i robić prototypy urządzeń bez obawy o spalenie leciwego i drogiego retro-komputera. Ogólnie, kawał doskonałego oprogramowania. Wyciągnąłem z szafki RPi 3 i 4, służące mi przez długi czas za domowy serwer i zabrałem je do muzeum.

Emulowane komputer vis-a-vis RPi3

Zestawienie C64 poszło mi szybko, ale gdy przełączyłem emulator w tryb C128 powitał mnie komunikat, że nie przegrałem odpowiednich plików. Kilka prób później udało mi się go uruchomić. Pomyślałem chwilę. Skoro ja się potknąłem to jaką szansę ma ktoś, kto chciałby może zaprząc swoje Maliny do szlachetnej pracy jaką jest emulacja Komody? Zwłaszcza ktoś bez znajomości nomenklatury. Albo ktoś leniwy. Musiałem myśleć o tych wszystkich ludziach, którzy podczas kontroli wcześniej wspomnianych jednostek tajnej policji będą mogli wskazać na RPi będące w użyciu, unikając kary lub znacząco ją opóźniając, do momentu w którym okdryją Arduino i ESP32 w stanie spoczynku.

Usiadłem więc i napisałem skrypt, który generuje gotowe do użycia archiwum (lub obraz, jeśli ktoś jest uzbrojony w dostęp do sudo i kpartx, o którym kiedyś już pisałem) zawierający firmware do wszystki1 emulowanych komputerów, wystarczy rozpakować je na kartę SD sformatowaną w FAT i wsadzić do RPi.

git clone https://git.sr.ht/~bronikowski/c64pi
cd c64pi
./build.sh # wszystkie artefakty znajdą się w bieżącym katalogu

Możecie też pobrać sam skrypt jeśli nie macie ochoty klonować repozytorium.

OK, ale co dalej? Możecie grać w stare, ale jare, gry. Możecie oglądać dema bez YouTube, możecie pouczyć się assemblera albo nawet BASIC-a2 Nie macie ograniczeń, poza niezbyt ciekawą paletą kolorów, ekstremalnie wolną stacją dysków (której emulację zgrzytania polecam włączyć, dopełnia iluzji) i anorektyczną ilością pamięci z perspektywy współczesnego użytkownika. Wystarczy jednak udać się na krótką przechadzkę po dziełach sztuki stworzonych przez współczesnych mistrzów żeby przekonać się, że bariery są tylko w Waszych głowach.

Skrypt w działaniu

Podczas pisania tego tekstu wpadł mi do głowy pomysł, mógłbym dodać kilka gier, dem i kartridżów do wygenerowanego obrazu żebyście mieli co robić prócz lampienia się w migający kursor zwisający spod READY. Jak postanowiłem tak zrobiłem. Skrypt, na wasza życzenie, pobierze przygotowane przeze mnie archiwum. Rzeczy wybrane pół na pół: z kompletnym rozmysłem i od dupy, mieszanka studencka i tanie wino.

Dobrej zabawy! A jeśli macie jakieś pytania o konfigurację, używanie BMC64 czy „w młodości grałem w taką grę, pamiętasz może” — możecie zawsze wysłać e-maila.

  1. Prócz C= PET, może w przyszłości, jak sam go rozgryzę, mam z nim zerowe doświadczenie i raczej za szybko nie pojawi się w muzeum
  2. Nomen omen, kilka miesięcy zacząłem pisać „książkę” o BASIC 2.0 w ramach walczenia z marazmem i depresją. W myśl zasady, że lek musi źle smakować. Jak ktoś mnie zmotywuje to może skończę. Mam na oko 15% i tyleż chęci obecnie.

timeout, czekając na Gotoa

Powiedzcie mi, czy to znacie. Jest wieczór, Wasz zmęczony umysł zaczyna produkować głupie pomysły, cały pochód głupich pomysłów, niektóre trzymają się za ręce i wywijają fikołki próbując zwrócić na siebie uwagę, a gdy im się to udaje, podrywacie się z fotela z „HM!” i pędzicie do biurka.

Dziewięćset dziewięćdziesiąt dziewięć razy na tysiąc okaże się, że ten pomysł nie jest taki głupi i że dawno został rozwiązany przez osoby bystrzejsze, bardziej utalentowane, dobrze wyglądające w strojach wieczorowych, posiadające bogate życie wewnętrzne i miłosne. Jedyna szansa, że popełnili jakieś wykroczenie przeciwko Waszemu zmysłowi estetycznemu i macie w sobie dość pasji żeby wynaleźć na nowo lepsze koło, inaczej trzeba zaakceptować istniejącą sytuację i próbować obrócić sprawę w żart, na przykład pisząc notkę o Waszym „odkryciu”.

W wyniku zawirowań życiowych moim jedynym komputerem jest obecnie Thinkpad X61s. To dziarski siedemnastolatek i prawdopodobnie mój ulubiony laptop. Ma wszystko, czego pragnę. Kwadratowy ekran, wygodną klawiaturę, brak touchpada, łatwe do wykręcenia śrubki gdybym chciał coś zmienić w środku. Do tego działa pod kontrolą współczesnego systemu operacyjnego i nie robi z tego powodu żadnych problemów.

~: uname -r && cat /etc/issue.net
6.1.0-16-amd64
Debian GNU/Linux 12

Pod tymi wszystkimi poduszkami jest jednak małe ziarnko grochu, które uwiera mnie w tyłek: niektóre współczesne programy, zwłaszcza te z ciężkim I/O, ujawniają ograniczenia tak starego komputera. Na przykład Syncthing, bez którego nie mogę żyć, bardzo boleśnie daje o sobie znać podczas zmiany wielu plików. I tu urodził się pomysł: mam skrypt, który odpala się na starcie komputera, sprawdza on, czy jestem w domu1, a jeśli nie, wyłącza różne serwisy i zmienia trasy pakietów, spełnia różne moje paranoiczne fanaberie. Gdybym dopisał tam odpalenie Syncthinga i zabił proces po minucie czy dwóch, miałbym mały podatek wydajnościowy na początku, ale potem odzyskałbym zasoby i miał wszystkie/większość nowe plików.

Wystarczałoby odpalić proces, złapać PID, poczekać zadany czas i wysłać mu morderczy sygnał. Przesiadając się z fotela na fotel pomyślałem: pewnie ktoś już to zrobił. I miałem rację, programiści GNU Coreutils i nazwali to timeout.

timeout

W najczystszej formie timeout przyjmuje dwa parametry. Czas do którego ograniczamy uruchomienie programu, domyślnie w sekundach, co można zmienić przyrostkami: m, h, d — odpowiednio, minuty, godziny i dni. Niestety, nie można ich łączyć. Jeśli chcemy czekać przez godzinę i pięć minut podajemy 65m, 1h5m nie zadziała.

Drugim parametrem jest oczywiście polecenie.

Szast-prast. Dodałem timeout 200s syncthing i uznałem sprawę za zakończoną. Następnego wieczoru zadzwoniła do mnie A. abym jej pomógł rozczesać kołtun jakim są zwykle skrypty używane w praktyce zwanej DevOops. I co widzę w pierwszej linijce? Tak, timeout. Myślę, to znak, znak żeby dopisać kilka „jednakże!”.

Jeśli polecenie wykona się przed zadanym czasem timeout skopiuje kod wyjściowy odpalonego procesu. To pożądana sytuacja, często chcemy sprawdzić, czy wszystko się udało czy też program, któremu zadaliśmy limit został ubity.

$ timeout 5s ./sleep_and_die.sh 2 5
Sleep for 2, die with 5
$ echo $?
5

Skrypt wykonywał się 2 sekundy i zwrócił pięć, co zostało odzwierciedlone w zmiennej powłoki. A co w sytuacji, gdy zostanie ubity? Domyślnie timeout zwróci jeden ze swoich statusów, jeśli mamy obsługę sygnałów w naszym kodzie możemy chcieć zachować oryginalną informację do dalszego przetwarzania.

$ timeout 5s ./sleep_and_die.sh 6 5
Sleep for 6, die with 5
$ echo $?                          
124

Jeśli dodamy obsługę SIGTERM i zwrócimy tam własny kod wyjścia oraz użyjemy opcji --preserve-status otrzymamy oczekiwany rezultat.

$ timeout --preserve-status 5s ./sleep_and_die.sh 6 5
Sleep for 6, die with 5
Zakończony
$ echo $?                                            
5

Kiedy timeout osiąga limit zadanego czasu do procesu wysyłany jest SIGTERM, używając parametru -s możemy zdefiniować inny sygnał. W tym przykładzie obsługuję SIGTERM i SIGQUIT.

Zdarzają się sytuacje w których polecenie nie przestaje działać mimo wysłanego sygnału. Jak uczył nas film dokumentalny Zombieland w czasach snujących się zombie-procesów drugą zasadą przeżycia jest “DOUBLE TAP”. Autorzy dostarczyli nam --kill-after przyjmujący dodatkowy czas po którym do procesu zostanie wysłany SIGKILL. Dla przykładu przechwycimy SIGTERM i nie porzucimy procesu.

I to tyle, teraz możecie czekać na Gotoa, choć uprzedzam, że on nie nadejdzie. Wesołego nowego roku. :*

  1. Dom jest tam, gdzie WiFi podłączyło się do sieci o znanym adresie MAC

Marginalia (II-VII)

Ocean daleko od brzegów zdaje się nie mieć kierunków. Są tylko dwie połówki kuli złączone ze sobą linią horyzontu. Jedna mieni się niebieskoczarno, druga błękitnozielono. Tak postrzegał sytuację kawałek deski podskakującej delikatnie na powierzchni wody. Była niezadowolona ze swojej obecnej pozycji — bezwolnego pasażera tej pustki.

Pod deską tętniło życie, które zdawało się mieć pełną kontrolę nad swoim jestestwem. W głębinach ruch miał cel, tam igraszki i śmierć miały znaczenie, a to znaczyło, że tam istoty doznawały szczęścia, nawet jeśli tego nie rozumiały. Deska dryfowała.

Próbowała płynąć to tu, to tam, na wschód, na zachód, ale nie miała duszy, jej wszystkie modlitwy rozmieniały się na drobne. Niebo na nią mrugało świtem tyle razy, a ona pozostawała w miejscu, patrząc całą sobą ku chmurom, a drugą stroną w mrok głębi.

Pewnego dnia nastał ruch. Wpierw wolny i wydawałoby się — bezcelowy. Deska była przekazywana z rąk do rąk przez taki czy inny prąd, nadal bezwolna, ale odczuwająca cel. „Płynę”, myślała. Im dłużej płynęła, tym bardziej upewniała się, że podjęła słuszną decyzję co do kierunku, a jeśli kierunek nagle uległ zmianie, wierzyła, że poprawiła poprzednią, błędną decyzję.

Wszystko nabierało tempa. Świat, który znała deska, zmienił się, spienił i spiętrzył. Tym razem ocean podrzucał ją na wiwat! Hurra, hurra! A w oddali pojawiła się nowość, żółtosina linia plaży, która rosła i rosła, rozsadzając horyzont. Wreszcie zmiana, gwałtowny pęd, ocalenie.

Deska wylądowała na plaży, wyproszona przybojem. Wyschła w słońcu, spróchniała i przestała przejmować się wszystkim.


Marginalia (II-VI)

Artyści umierają za swoją sztukę. Wiktor, czy też Niesamowity Viktor, umierał dziś kilkukrotnie. Sala klubu była wprawdzie wypełniona, ale nikt, kto przybył w ten czwartkowy wieczór do baru, nie planował oglądać jego występu, wieczorki artystyczne wiążą się z promocją na napoje alkoholowe. Cel jest jasny: napędzić widownię i ją spacyfikować. Niesamowity Viktor widział, że oczy tylko tych ludzi, którzy siedzieli najbliżej sceny, podążały za nim. Reszta, pozostając ukryta w ciemniejszej części baru, nie zwracała na niego uwagi. Drugą strona miłości nie jest nienawiść, tylko obojętność.

Kiedy kończył jedną sztuczkę, czekał chwilę na oklaski, a te nie nadchodziły. Wydawało mu się, że jego ręce są sztywne, niewprawne, niezdolne do ruchów pełnych gracji. Kiedy wyciągał z rękawa „niekończącą się” kolorową szarfę, czuł, jak ta przesuwa się pod jego niedopasowanym smokingiem, zawadzając o guziki, sprawiając, że co powinno być pokazem płynnych ruchów i pewności, staje się czkawką gestów. Za każdym razem, gdy materiał stawiał opór, nachodziły go mdłości.

Gdy ostatnie centymetry szarfy pojawiły się wreszcie, Wiktor uniósł ją w górę, pokazując widowni brak supłów. Następnie podszedł do stoliczka i sięgnął po talię kart. — Do tej sztuczki potrzebuję osoby z widowni — oznajmił, a gdy nikt nie drgnął z miejsca, podszedł do najbliższego stolika i zdobywając się na wyuczoną jowialność, powiedział do siedzącego przy nim człowieka: — Pan! Proszę wybrać kartę. — Wskazany osobnik wziął pierwszą kartę, po czym został poinstruowany, aby nie pokazywać jej wartości nikomu.

Wiktor zgrabnie wrócił na scenę i zaczął tasować talię. Robił to tysiące razy. Rozłożył karty w palcach w mały wachlarz, a następnie przesunął nim między oczami.

— Czwórka kier! Proszę sprawdzić! — zawołał do widza trzymającego kartę. Ten upewnił się i potwierdził, po czym podniósł się i zwrócił Niesamowitemu Viktorowi kartę, jakby bał się, że to jedyna talia, na którą go stać. Artysta odczytał to w duszy jako obelgę, ale w sercu jako prawdę.

Nadchodził koniec programu. Wiktor stanął na środku sceny i ściągnął z głowy cylinder. Włosy miał mokre od potu i przyklejone czoła, jakby obudził się w środku nocy z koszmaru.

Zaprezentował dno cylindra widowni, potem stuknął w niego kilka razy. Wreszcie sięgnął w głąb i wyciągnął za kark pięknego, białego królika. Obrócił się delikatnie od lewej do prawej, aby zobaczyła go cała widownia. Wypuścił go na deski estrady, sięgnął ponownie do cylindra i wyciągnął kolejnego. Widownia lekko się ożywiła, fala zainteresowania rozlała się do najodleglejszych zakątków lokalu. „Widziałeś? Dwa króliki”.

Potem były trzy króliki. Cztery króliki. Wiktor ukłonił się, rozległy się ciche brawa.

Zaciągnięto kurtynę i bar wypełnił się znów rozmowami.


Korytarz był tak wąski, że gdyby rozłożyć w nim ręce, dotykałoby się palcami obu ścian. Jego koniec ginął w mroku. Sufit zdobiły plamy i szczerbate oprawy lamp jarzeniowych. Podłogę wyłożono zielonym linoleum, które czas naznaczył pęknięciami, przetarciami i odbarwieniami, wyznaczając historyczne ścieżki, miejsca postojów i fantomowe lokalizacje wyniesionego sprzętu. Duchy poprzedniego artystycznego życia dawno już wyegzorcyzmowała codzienność.

Po lewej stronie co kilka kroków znajdowały się drzwi skrywające małe i martwe pokoje, składnice złomu, kurzu i występujących artystów. Spod czwartych drzwi sączy się światło, tam bez wątpienia przebywa obecnie Niesamowity Viktor. Postać w płaszczu podeszła do nich i zastukała cicho, niemal konspiracyjnie.

— Zaraz, przebieram się — odpowiedziały drzwi.

Postać zastukała ponownie i dodała: — Pan Viktor, Niesamowity?

— Zaraz, zaraz — za drzwiami było słychać ruch, gdy wreszcie się otworzyły, stanął w nich człowiek w średnim wieku, któremu przerwano naciągnie koszuli przez głowę — …tak, o co chodzi? — zapytał.

— Dzień dobry — powiedział gość — widziałem właśnie pańskie przedstawienie, reprezentuję organizację pozarządową, która ma na celu dobrostan zwierząt w przemyśle rozrywkowym. Nie jest w żaden sposób prawnie umocowane, aby przeprowadzić kontrolę, więc to Pana wybór.

— A jak Pana nie wpuszczę?

— Nic się nie stanie, poza tym, że napiszę o tym w raporcie, który jest dostępny dla zainteresowanych podmiotów w przemyśle rozrywkowym. Wie pan, „jeśli chcecie zatrudnić kogoś, kto nie uczy niedźwiedzi tańczyć, parząc im łapy, sprawdźcie naszą listę”.

Wiktor popatrzył na jego pogodną twarz. Człowiek wydawał się promieniować gorliwością i dobrocią. Ubrany był schludnie, jakby do baru zaszedł wprost ze swojej biurowej pracy bez przebierania się. Miał w ręku małą teczkę.

— Zapraszam — Niesamowity Viktor odsunął się od drzwi.

Wygląd pokoju był w kompletnej harmonii z tym, co można było zobaczyć na korytarzu. Żaden element nie był zniszczony, ale wszystkie były zmęczone. Biurko z lampką, na nim małe lustro oparte o ścianę. Kanapa służąca jako wieszak. Krzesło, kilka taboretów, na wprost drzwi okno wychodzące na fasadę budynku obok. Wiktor przerzucił zalegające na kanapie rzeczy na jedną stronę i wskazał gościowi miejsce do siedzenia. Ten, zanim je zajął, wyciągnął dłoń: — Proszę mi mówić Miron.

— Wiktor — odpowiedział Viktor.

Miron usiadł na kanapie, wyciągnął z teczki jednostronnicowy formularz, popatrzył na niego z uwagą, uzupełnił kilka rubryk, nazwisko kontrolera, nazwisko artysty, nazwę lokalu. Odhaczył kilka punktów i zwrócił się wreszcie do Wiktora.

— Króliki, dobra, klasyczna sztuczka. I jak mistrzowsko wykonana. Cztery króliki na ciasnej estradzie, hyc hyc, pomiędzy nogami. Piękne zwierzęta. Patrzę tak teraz tutaj i nigdzie ich nie widzę, czy trzyma pan je w klatkach? Może po występie pakuje je pan do samochodu? Chciałbym się dowiedzieć, jak są one traktowane, wie pan, wie pan, o co mi chodzi? — Miron tracił pewność z każdym słowem, patrząc na niewyrażające niczego oblicze magika.

— Nie ma żadnych królików. Dokładniej, to nie ma już żadnych królików. Odeszły.

— Odeszły? W sensie pan je najmuje od kogoś i ten ktoś je zabiera po?

— Odeszły. Nie ma ich.

Miron przybrał minę człowieka, który nie jest pewien, czy robią z niego idiotę, czy też on czegoś nie rozumie. Próba odczytania podpowiedzi z twarzy Wiktora nie przynosiła skutku, to było jak czytanie pustej strony. Ten wreszcie podniósł się, podszedł do sterty rzeczy leżących obok kontrolera, wziął cylinder, strzepnął z niego niewidzialny kurz, a następnie wyciągnął z niego królika. Popatrzył na niego krytycznie i postawił go na ziemi.

Królik pozostawiony sam sobie siedział przez chwilę w miejscu, a potem zaczął skakać po pokoju. Przesuwał się i zamierał, tak jak to robią zwierzęta w nowym środowisku. Kontroler chciał coś powiedzieć, ale Wiktor przerwał mu gestem ręki. — Czekaj — powiedział.

Po niecałej minucie królik dotarł do taboretu i hycnął pod niego. Zza drewnianej nogi wystawał jego pyszczek, różowy nos pozostający nieustannie w ruchu, uszy położone po sobie. Po drugiej stronie nogi, gdzie powinna się znajdować reszta tułowia, nie było niczego. Królik zastrzygł wąsami, odwrócił się i zniknął kompletnie.

Miron obszedł taboret, podniósł go na wysokość wzroku, przełożył palce przez wszystkie przestrzenie w bryle taboretu. Nie znalazł niczego. Postawił taboret na ziemi i usiadł na nim.

Wiktor patrzył z wyrozumiałym uśmiechem.

— Mówiłem. One zawsze odchodzą. Kurtyna opada, odchodzą. Wczołgują się pod koc, odchodzą. Wbiegają za szafę, odchodzą. Jeśli znikną na chwilę z wzroku, odchodzą. — Mówiąc, zwijał swoją garderobę, szykując się do wyjścia.


Tego samego wieczoru na rogu cichnącej ulicy Miron usiadł przy barowym stoliku. Rozłożył przed sobą formularz, wyprostował go kciukiem, następnie wyciągnął papierosa, wypalił go i wyciągnął następnego. Stukał długopisem w kartkę i szukał odpowiedniej rubryki. Nie znalazłszy niczego, co odpowiadałoby rzeczywistości, wpisał odręcznie na spodzie kartki:

„Uchybień nie stwierdzono.”


Marginalia (II-V)

Wpadł na mnie, wychodząc zza rogu zaułka. Zatrzymałem się o krok przed jego bosymi stopami, zmierzyliśmy się wzrokiem. On wysoki, w białej, rozchełstanej szacie, mimo zimna i deszczu bosy. Ja zdziwiony, na wpół już wychylony, aby ominąć postać z „przepraszam” na ustach.

Wtedy chwycił mnie za ramiona, patrząc mi w twarz z taką zawziętością, że jego źrenice nieomal odgniotły się na moim czole, i powiedział podniesionym głosem, „I ty będziesz zbawiony!”. Zamarłem w tym jego uścisku, przeklinając zezowate szczęście, które wylosowało mi wariata tak późno wieczorem. „Przepraszam?” zapytałem i odsunąłem jego wyciągnięte ręce.

On klasnął w dłonie jak dziecko oczekujące prezentu i powtórzył, że będę zbawiony. Zbawiony, zbawiony, mówił z uśmiechem.

„Zbawiony od lęku, od tej pustki w Twojej duszy, wydobyty z dna na światło dzienne, uwolniony z pęt, otrzepany z kurzu, postawiony na nogi, abyś rękoma mógł sięgnąć nieba, zbawiony dla siebie, aby zbawiać innych! Rozwiniesz się jak kwiat pokryty szronem wiosennej nocy. Wzejdzie słońce, a ty otrzymasz życie i dasz życie”, powiedział z przekonaniem. Następnie uścisnął jeszcze raz moje ramiona, obrócił się na gołej pięcie i zaczął się oddalać.

Stałem tak z głupią miną, którą przyjmują ludzie, kiedy się ich nagle zakłopocze, pomiędzy lekkim wystrachem, rozbawieniem sytuacją oraz zadowoleniem z jej szybkiego rozwiązania. Wzruszyłem ramionami i wsadziłem ręce do kieszeni płaszcza, żeby osłonić je przed padającym deszczem. Odprowadziłem wzrokiem białą postać, która nagle rzuciła się do biegu i zniknęła za rogiem. „Ty skurwysynu!” rzuciłem jeszcze za nim, ale pewnie już nie usłyszał, a jak usłyszał, to pewnie się nie obruszył. Portfel mi ukradł.

I tego dnia byłem zbawiony. Nie upiłem się, nie poszedłem do baru grać w karty, nie proponowałem nura w degrengoladę ulicznicom. Wróciłem do domu i położyłem się spać, gdyż wszystkie moje występki i grzechy kosztują pieniądze. Nie mam naturalnych talentów ku popełniania zła, mogę je tylko kupić.


Marginalia (II-IV)

(Drogi czytelniku, jeśli jesteś uzbrojony w specjalistyczne urządzenie do czytania e-książek możesz zrobić mi przyjemność i pobrać zbiór opowiadań «Marginalia», dziękuję!)

Do przeszklonych drzwi zastukała sekretarka i nie słysząc zaprosin, wsadziła głowę, żeby sprawdzić, czy szef nie jest przypadkiem zajęty. Nie był, chodził po pokoju i zdawał się nie zważać na podążającą za nim wzrokiem sekretarkę. Miał ręce założone z tyłu, a jego łysa głowa była pochylona do przodu, jakby stawiał czoła jakiemuś silnemu wiatrowi.

— Przepraszam! — powiedziała wreszcie.

— Ah! — żachnął się dyrektor i obrócił na pięcie. — Pani Marto, nie usłyszałem, jak Pani stukała, myślałem. O tej godzinie myślenie idzie mi bardzo powoli, więc muszę chodzić, a wtedy nie zwracam na nic uwagi — dodał przepraszającym tonem.

— Nie przeszkadzałabym już dziś, ale okazało się, że mamy jeszcze jedno spotkanie z kimś z branży, które nie było potwierdzone, ale pan pojawił się przed chwilą i chciałam zapytać, czy mam go umówić na inny czas i odprawić?

Dyrektor spojrzał do góry, jakby na suficie miał ściągę z bieżącym rozkładem zajęć. Wreszcie kiwnął głową, drzwi zamknęły się za sekretarką, a on zajął miejsce za swoim biurkiem.

Biurko stanowiło centrum dowodzenia, zawierało wszystko, co powinno zawierać biurko dyrektora, który uważa się za człowieka pracującego. Nie zielone sukno bankierów i prawników, lecz wielokrotnie malowany i lakierowany drewniany blat, tak wielki, że trzeba się podnieść z krzesła, by sięgnąć ku jego krańcom. Na nim zestaw papierów w różnym stadium przetworzenia, te ku brzegom w różnym stanie rozkładu, głównie rzeczy już nieważne, odepchnięte z niechęcią. Prawa szuflada, butelka czegoś mocniejszego na zimowe wieczory, ostatnio nieco zaniedbana, gdyż dyrektor postanowił, że powoli robi się zbyt stary na to, by wychodząc po pijaku z biura, odegrać przekonująco rolę odpowiedzialnego, szanowanego człowieka biznesu przed nocnym portierem, którego biuro obserwuje bezpośrednio windę. Oczywiście mógłby go zwolnić, gdyby zaczął siać plotki, ale czułby się fatalnie, przyłapany jak uczniak, więc to nie rozwiązałoby niczego.

W lewej szufladzie trzymał rewolwer, prezent od przyjaciół, sześciostrzałowy. Dyrektor wyciąga go z szafki co pół roku i zanosi do rusznikarza na przegląd. Sam nie wierzy, że mógłby go użyć, nie dlatego, że brzydzi się przemocą, raczej dlatego, że w złości nie radzi sobie z rzeczami wymagającymi gracji.

Znów rozległo się stukanie, drzwi otworzyły się i do pokoju wparował, nie czekając na zaproszenie, człowiek w średnim wieku. Żwawym krokiem przemierzył pokój i stanął przy biurku z wyciągniętą ręką. Wszystko stało się tak szybko, że twarz dyrektora nie zdążyła nawet zareagować.

Dyrektor uścisnął profesjonalnie dłoń nowoprzybyłego i wskazał mu krzesło, które ten zajął, nieomal zataczając piruet na pięcie, po czym postawił obok aktówkę, wygładził nieco swoje fiołkowe spodnie i założył nogę na nogę. Z wewnętrznej kieszeni marynarki koloru musztardowego wyjął coś, co zatrzymał w zamkniętej dłoni.

— Proszę — powiedział dyrektor — pan chciał się ze mną spotkać. Proszę wybaczyć to zamieszanie ze spotkaniem, czasami są takie tygodnie, że wszystko idzie nam na boki. Przez to wszystko nie wiem nawet, w jakiej pan sprawie, proszę więc.

— Panie dyrektorze, nazywam się Marcin J. i reprezentuję firmę produkującą elementy elektryczne. Elektryka jest przyszłością, tak naszą, jak i państwa. Słyszeliśmy, że rozpoczynacie prace nad nowymi pociągami na rynek niemiecki, gdzie będą jeździły z użyciem trakcji elektrycznej. Cieszymy się, że nasze lokalne przedsiębiorstwa tak szybko inwestują w pewny sukces.

Marcin poderwał się na równe nogi, podniósł aktówkę z podłogi i płynnym ruchem wydobył z niej katalog produktów. Odwrócił go w rękach i położył przed dyrektorem, który otworzył go niechętnie, bo zwykle nie był odpowiedzialny za kupowanie pojedynczych elementów; od tego jest dział w firmie. Skoro jednak nieopatrznie wpuścił sprzedawcę, odegra przynajmniej zainteresowanie, a sam katalog rzuci na biurko inżynierów, którzy lepiej wiedzą, czego potrzeba.

Na każdej kartce roiło się od rozmaitych przełączników, kontrolek, lamp rogowych, gniazdek, a każde z nich w rozmaitych fasonach i kolorach, każda kategoria komentowana przez Marcina w tylu detalach, na ile pozwalało tempo przerzucania kartek przez dyrektora.

Zakończył wreszcie kartowanie i powiedział, że dziękuje za prezentację i poda to dalej, z nadzieją, że może już iść do domu. Wtedy nad złożonym już katalogiem pojawiła się otwarta dłoń Marcina, która ujawniła małą lampkę koloru pomarańczowego, która gasła i zapalała się rytmicznie.

Sprzedawca wydawał się zadowolony z tak efektownego finiszu. Położył migającą lampkę na biurku i szybko dodał: — A to nasza nowość. Lampka informacyjna o kierunku, albo migacz, jeśli nikt nie wymyśli lepszej nazwy do czasu, aż rozpoczniemy pełną produkcję. Czas jest regulowany! — Marcin nie krył dumy.

— No bardzo ładne — przyznał dyrektor, przyglądając się pulsującemu gadżetowi. — Ale co to dokładnie robi?

— Och, to bardzo proste. Mocujemy dwa takie na każdym wagonie pociągu. Po obu stronach. Nasz elektryk montuje przełącznik, także dostępny w naszym katalogu, którym można zapalać jeden lub drugi…

— …i co się wtedy dzieje? — dyrektor wciąż nie rozumiał idei.

— Wtedy wiadomo, czy pociąg jedzie w lewo, czy w prawo! Już z daleka. Podwyższone bezpieczeństwo, reklama dla firmy, dba nie tylko o swoje, ale także o zwykłego człowieka, a to przecież zwykły człowiek kupuje bilety!

Dyrektor zrobił minę, jakby ktoś opowiedział mu żart, w opinii opowiadającego żart bardzo dobry, z puentą o jego matce.

— Drogi panie — oznajmił sztywno. — Pociągi, per se, nie skręcają. To nie jest karoca, pociągi jadą po szynach, bardzo rzadko zdarza się, żeby pociąg nieplanowanie skręcił. A gdy to się dzieje, potrzebne są karetki i ciężki sprzęt, nie migające lampki!

— W takim razie — niewzruszenie kontynuował Marcin — moglibyśmy dać przekaźniki w miejscach, gdzie postronnym osobom wydaje się, że pociąg skręca, wtedy maszynista nie musi nawet używać przełącznika, wszystko odbywałoby się automatycznie!

Dyrektor wsparł się na na dłoniach i wysapał: — Setki, nie, tysiące kilometrów mamy obstawić przekaźnikami, które nic nie robią? A nie, przepraszam, migają, że pociąg skręca, choć każdy widzi, że skręca? I pewnie oczekujecie państwo kontraktu na wymianę żaróweczek i, niech zgadnę, te żaróweczki się wypalają po tygodniach, zgadłem? — Tu dyrektor już krzyczał. — I pewnie te przekaźniczki też trzeba konserwować konsekwentnie, inaczej wszystko przestanie mrygać!

— Trzeba rozważyć przyszłość — odpowiedział spokojnie sprzedawca. — A gdyby w przyszłości pociągi mogły się wyprzedzać, w ramach konkurencji i walki o klienta jeden drugiemu dawałby znaki, o, zobacz, jaki jesteś wolny, minę cię po prawo!

Dyrektor schylił się w kierunku biurka i próbował drżącymi rękoma otworzyć lewą szufladę. Ta wysuwała się zaledwie na ósmą część swojej długości, trzasnął więc nią w złości. Porwał katalog, próbował zgnieść go w kulkę, ale zbyt wiele stron stawiało opór, ostatecznie cisnął nim, zwiniętym w rulon, w kierunku ratującego się ucieczką Marcina.

— Gałgany! Patafiany, krwiopijcy i najgorsze — dyrektor wziął oddech — kompletni idioci! Won, won, won, drzwi nie zamykaj nawet za sobą.

Dyrektor opadł na fotel, pogładził głowę i otworzył prawą szufladę. Następnego dnia firma dała ogłoszenie, że szuka nowego portiera.


Marginalia (II-III)

— Kiedy tu do ciebie przychodzę, a to zawsze ja muszę, bo ty mnie już nie odwiedzasz, siedzisz na tym krześle taki ponury, ze zwieszoną głową. I zawsze w tym samym ubraniu, wymiętym i bezkształtnym. Nigdy nie proponujesz mi herbaty ani dobrego słowa. Czy ty się w ogóle dobrze odżywiasz? Pewnie nie jesz warzyw, twoja cera jest żółtoszara. Chcesz, żeby matka się martwiła?

Położyła dłonie na stole, czekając na odpowiedź. Wszystko w pokoju było nieruchome i nieme.

— Gdy zadzwonisz, raz na miesiąc, nie mówisz mi nic o tym, co się dzieje w twoim życiu. Kiedyś byłeś w gazetach, może nie na pierwszych stronach, ale ludzie pytali, czy to o moim synu.

— …mamo — odpowiedział więzień.


Marginalia (II-II)

Spotkali się na tyłach lokalnego sklepu spożywczego. Wpierw przyszedł jeden, chwilę później jeszcze jeden. Obaj czekali chwilę, aż wreszcie przyszedł jeden, ostatni, który ich tu zwołał. Stanęli naprzeciwko siebie i wreszcie jeden przemówił. Był on najstarszy rangą, ale rangi nie grały roli w ich życiu, więc przyjmijmy, że ten jeden mówił po prostu pierwszy.

— Rzadko się zdarza, abyśmy się spotykali, zwłaszcza na wezwanie. Ani ja, ani drugi inny nie widzieliśmy powodu, ale skoro jesteśmy w tym samym miejscu, możemy. Może trzeci inny ma powód?

Inny przemówił zaraz po nim:

— I szybko, mamy rytuały do odprawienia, niebo kręci się nad nami bez względu na to, czy ktoś ma z tym faktem jakieś problemy. Rzeczywistość jest wystarczająco krucha, aby nie próbować cierpliwości Sił, tak wspierających nas, jak i tych będących przeciwko nam.

Trzeci inny odpowiedział im szybko:

— Drodzy my, moja dusza jest pełna niepewności. Każdego dnia zastanawiam się, po co my to robimy. I czy robimy to poprawnie? Czy nasz los jest przypieczętowany, los ludzi, którzy chronią ten świat, pozostając bez twarzy i imion?

— Nie rozumiem — wtrącił inny — czy chcesz sprawdzić metodą testu, jak prawdziwe są nasze metody? A co, gdy mamy rację? Jeśli my, najmądrzejsi, przepełnieni wiedzą sięgającą pradziadów spisujących dzieje na kościach zwierząt, przestaniemy robić, co robimy, i następnego dnia niebo stanie w ogniu, oceany zamienią się kamień, a góry wyparują, kiedy nastąpi zagłada, totalna i bezwzględna, co wtedy? Chcesz wtedy powiedzieć światu, z którego ucieka życie, „no wybaczcie, chciałem zobaczyć tylko, czy to ma sens, teraz widzę, że ma, można to odwrócić do jutra, kiedy wznowimy normalne usługi?”.

Inny zgodził się, sięgnął do kieszeni i wydobył z niego kolorowy proszek, który podrzucił do góry. Kolorowy dym opadał powoli ku ziemi, a oni uklękli, czekając. To był rytuał 10:38, jeden z 35 utrzymujących Siły w balansie.

Wszechświat istniał dalej, czego dowodem była pracownica sklepu, która właśnie wyłoniła się zza rogu, trzymając w rękach wielki worek pełen śmieci. Zmierzyła ich wzrokiem i burknęła, że spożywanie wyrobów alkoholowych w obrębie sklepu jest zabronione. Inny powiedział, że oczywiście. W tym czasie inny zasłonił otwartą butelkę połą płaszcza.

— Czy potrzeba nas trzech do tego wszystkiego? Czy nie możecie zwolnić mnie z tej służby? Na co mi znajomość wszystkich tajemnic wszechświata, wszystkich faktów, odpowiedzi, skoro nikt nie wie, kim jestem ani co robię?

„Próżność!” zawołał inny. „Upadek!” zawołał drugi inny.

I dodał:

— Chronisz każde życie i każdy atom, nie oczekuj niczego więcej, to nagroda sama w sobie. To skarb, który nosisz w sercu, niemożliwy do przebicia w złoto, za które możesz kupić inne życie. Porzuć tę ścieżkę, zaprowadzi cię ona tylko do nieszczęścia. Innych można zastąpić, gdy stają się nimi, ale dla nich nie ma powrotu.

— Wystarczy! — powiedział trzeci inny. — Mam dość. Odchodzę, mam gdzieś to życie bez nagrody, tę chwałę spisaną w eterze, ten niewidzialny ciężar. I nazywam się Bartosz. Do widzenia.

Inni pochylili głowy w geście rozpaczy.

Bartosz przyjął się w firmie publicystycznej, która produkowała książki kucharskie. Dzięki swojej wszechwiedzy otrzymał przydomek „Rebus”, gdyż znał odpowiedzi na nawet najbardziej podchwytliwe pytania. Mimo to wszystkie arkana ezoterycznej wiedzy nie pomogły Bartoszowi w zgłębieniu Excela, przez co jego kariera utknęła na szczeblu managera. Dorobił się emerytury, nienawidząc każdego dnia, a potem umarł, bojąc się śmierci.

A inni? Nic o nich nie wiemy, bo byli mądrzy.


Marginalia (II-I)

Wisiałem przewieszony przez płot jak pranie. Jak pranie byłem wyduźdany, mokry, ale czysty. Oparłem brodę na jednej ze sztachet i patrzyłem na piaskową ścieżkę, która przebiegała obok i łączyła porozrzucane domki we wioskę. Dzień powoli chylił się ku końcowi i nawet letnie słońce opieszale zjeżdżało do zajezdni. Kompletną ciszę i bezruch przerwał ujadający pies tańczący na smyczy trzymanej przez sąsiada.

Przyjmuję bardziej godną pozycję, aby po ludzku wymienić kilka uprzejmości. Kiedy sąsiad jest wreszcie w zasięgu słuchu, witam go gromko i entuzjastycznie. Zatrzymuje się z uśmiechem i zaczyna mówić. O psie, o gorącu. O tym, jak zamknięto nasz lokalny sklep, mimo że wszystko było w nim droższe, i jaki to musiał być słabo prowadzony biznes, skoro się nie udał. O sąsiadach. Niewiele, malutkie ploteczki.

Ja potakiwałem. I mówiłby tak dalej, ale przerwał zdumiony, gdy z mojego podwórka rozniosło się donośne pianie koguta, powtórzone kilkukrotnie. Sąsiad skrzywił się i spojrzał na mnie zdziwiony.

— Kogut ci pieje o tej godzinie? — zaśmiał się.

Wzruszyłem ramionami. — Tokio? Tak.

— Nie tylko pieje w nocy, ale jeszcze ma imię? Kto jest tu dziwniejszy, ty, że nazywasz ptactwo, czy ptactwo, że jest pokręcone?

— Och, on się nazywa Tokio dlatego, że jak go kupiłem z drugiej ręki, to miał ustawioną strefę czasową na Japonię. Dlatego teraz pieje. Nie da się chyba z tym nic zrobić — machnąłem ręką w geście obojętnego zrezygnowania.

— Twój kogut ma strefy czasowe, jak to działa?!

— Kto wie, jak działają strefy czasowe, chyba nikt.

Odwróciłem się od płotu i, unosząc rękę na pożegnanie, udałem się do domu.


Podcast metodą chałupniczą

Obudziłem się wczoraj o trzeciej w nocy. Postanowiłem napić się herbaty, a gdy ją piłem zdałem sobie sprawę, że nie zasnę ponownie. Włączyłem truchło mojego laptopa i wskoczyłem do katalogu ~/work, grobowiska pomysłów, ambicji i marzeń. Nie znalazłem tam niczego inspirującego, bo z kości tamże złożonych projektów można najwyżej złożyć makabryczny ksylofon.

Zabrałem się więc za prace ogrodnicze, wypieliłem grządkę z YAMLowych chwastów, przyciąłem krzewy skryptów powłoki, zgrabiłem logi, zamiotłem ścieżki żeby pakiety mniej się chybotały w drodze do stodoły serwerów i wreszcie uderzyło mnie: hej, ten skrypt, który periodycznie pobiera listę odtwarzania z YouTube i zamienia ją w wygodne pliki dźwiękowe, on mógłby zasadniczo produkować kanał RSS lub Atom. A taki można wpiąć w aplikację do słuchania podcastów i tym samym pozbyłbym się problemu dystrybucji (relatywnie mniej uciążliwego dzięki Syncthing) oraz problemu z tym, że odtwarzacze muzyki zwykle nie pamiętają miejsca w którym porzuciłem słuchanie, a aplikacje do podcastów już tak.

Poza tym zmarnowałbym czas do momentu w którym głowa znów mi opadnie na poduszkę.

Po kilku godzinach miałem już działający prototyp, ale zaraz przyszło kolejne olśnienie, razem ze wschodem słońca. Starczy dodać do tego dwa parametry i mógłbym ofiarować taką usługę ludziom, ludziom takim jak ja. Jeśli używasz „staromodnego” klienta podcastów, takiego który czyta kanały RSS i czujesz, że są na YouTube widea, które chciałbyś zmieścić do swojego prywatnego radiowego programu, wystarczy, że wyślesz mi e-mailem adres do publicznej lub ukrytej1 listy odtwarzania, a ja odeślę Ci link kanału pod którym będzie się tworzyła audycja. Każda nowo dodana do tej listy rzecz ostatecznie trafi do ciebie jako nowy odcinek.

Na teraz mamy następujące funkcje:

  1. tworzenie kanałów RSS i Atom (kanał RSS ma więcej funkcji, bo używam własnościowych notacji iTunes)
  2. jeśli wideo ma wbudowane rozdziały, plik audio będzie posiadał także
  3. meta dane takie jak opisy i miniaturki są prezentowane w kontekście „odcinka”
  4. u mnie działa

Trzy zrzuty ekranu przedstawiające wyżej opisane funkcje w działaniu

Panelu administracyjnego zrobić nie przewiduję, gdyż jest to projekt gośćwdombógwdomware, human scale, nie policzę ci za cukier do herbaty, ale jak zaczniesz się panoszyć to ci prywatnie zwrócę uwagę, a ostatecznie wskażę drzwi.

Zapraszam więc.


Dwie rzeczy organizacyjne. W wyniku cyfrowego procesu gnilnego musiałem wyłączyć tymczasowo njusletter. Usiądę do tego niedługo, obiecuję (sobie)2 . Dwa, w grudniu chciałem opublikować kilka małych opowiadanek, które pozbierałem z notatników, nie wiem jeszcze, czy będę kładł po jednym na tydzień, czy też może stworzę gdzieś osobną stronę z odnośnikami do nich żeby wam nie przynosić rozgardiaszu do czytników RSS.

  1. public lub unlisted
  2. Naprawione, częściowo!

Pracuję, mam na to dowody

Telefony nas śledzą, komputery nas śledzą, ulice śledzą nas oczami CCTV, pracodawcy mierzą nam puls i liczą poruszenia myszką, sklepy patrzą nam przez ramię BLE, gdy zatrzymujemy się przy półce, serwisy społecznościowe nas śledzą i w zamian dają nam możliwość śledzenia innych. Śledzą nas „dla naszego dobra”, „dla ich dobra” oraz dla „wyższego dobra”. Jedyna osoba, która nie ma ochoty nas śledzić to nieopłacony prywatny detektyw.

Skoro jest to nieunikniona rzeczywistość może czas zacząć się śledzić samemu, jak bohater książki PKD, „Przez ciemne zwierciadło”. Podczas gdy normalni ludzie używający normalnych systemów operacyjnych otrzymują inwigilację w prezencie, użytkownicy Linuksa, w duchu DIY, muszą zbudować sobie swój własny panoptykon klecąc jakąś serię poleceń w Bashu z nadzieją, że im się to nie rozsypie.

Kilka dni temu sprzątałem swoje archiwum. Okazało się na przykład, że mam pół terabajta obrazów nieistniejącego już serwera, za które wystawiają mi rachunek co miesiąc. Pośród różnych plików znalazłem niewielką paczkę nazwaną x11.tar.gpg i po chwili przypomniałem sobie, co to jest. Kiedyś wymyśliłem że napiszę sobie program, który będzie logował nazwę aktywnego okna do pliku tekstowego i dzięki temu będę mógł wiedzieć, co robiłem. Zrobiłem, wstawiłem go do crontaba i zapomniałem. Potem znalazłem efekt, spakowałem go, zaszyfrowałem i wrzuciłem do zamrażarki.

Kodu samego programu nie zachowałem, a przynajmniej nie mogę znaleźć. Bez wątpienia był bezwartościowy. Byłem za to ciekawy jak szybko uda mi się odtworzyć go przy pomocy typowego skryptu-pająka. Mam zainstalowany xdotool i po tym jak zerknąłem w jego olbrzymi manpage widziałem, że się nada.

xdotool służy do automatyzacji X11. Można nim wysyłać wydarzenie takie jak wciśnięcie klawiszy, ruch myszki, zmieniać geometrię okien, statusy. Można też odczytać informacje o klasie, identyfiaktorze i innych atrybutach dostępnych dla rzeczy działających pod kontrolą X11.

Wpisałem xdotool getactivewindow getwindowname w terminalu i otrzymałem poprawną odpowiedź — zsh. Doskonale, możemy zacząć się śledzić samemu. Postanowiłem, że zamiast zapisywania dowodów do pliku tekstowego przez >> użyjemy prawdziwej bazy danych, wtedy możemy zarządać donosami na siebie w sposób wygodny, a co najważniejsze uzyskane zeznania będą dokładne.

Na początek sprawdzimy, czy nasza baza danych istnieje, a jeśli nie, utworzymy ją wraz z potrzebną tablicą. SQLite przyjmuje polecenia bezpośrednio z stdio, nie ma się więc o co martwić.

#!/bin/bash

if [ ! -f ispy.db ]; then
    echo "Database initialization"
    echo "CREATE TABLE ispy(id INTEGER PRIMARY KEY AUTOINCREMENT, created_at, window_title)" | sqlite3 ispy.db
fi

Teraz nie pozostaje nic innego jak kręcić się w nieskończoność i karmić nowopowstałą bazę informacjami.

while :
do
    echo "INSERT INTO ispy(created_at, window_title) VALUES (datetime('now'), '"$(xdotool getactivewindow getwindowname)"')" | sqlite3 ispy.db
    # tak, też widzę sql-injection przy użyciu spreparowanego
    # <title> ;) 
    sleep 5
done

Jeśli przyszłoby Wam na myśl odpalanie tego w cronie czy w supervisord musicie pamiętać że są one zwykle uruchomione poza kontekstem waszej sesji X11, musicie więc odpalić taki skrypt przekazując zmienną środowiskową DISPLAY (lub ustawiając ją w samym skrypcie).

Czyli na przykład DISPLAY=:0 ./ispy.bash.

Wielkiej magii tu nie odkryliśmy. Skoro już się szpiegujemy to powinniśmy dołożyć wszelkich starań aby z zebranych dowodów prokuratura mogła ugrać jak najcięższy wyrok. Obraz wart jest tysiaca słów. Dodajmy więc obraz.

Użyjemy scrot, aby zrzucić zawartość ekranu, mogrify aby dodać tekst do zrzuconej klatki, będzie on zawierał to samo, co u góry: nazwę okna. Następnie scalimy wszystkie te obrazy w bardzo poszatkowaną animację. Teraz możecie doświadczyć pełnej autoinwigilacji.

Zaczniemy od obsługi przerwania działania skrptu. Nie ma sensu za każdym razem przekodowywać wideo, starczy że będzie to ostatnia operacja.

#!/bin/bash

DISPLAY=:0
STORAGE_PATH="/tmp"

trap encode SIGINT

encode() {
    ffmpeg -r 2 -pattern_type glob -i "$STORAGE_PATH/*.png"  \
                    -an -vcodec libx264 -pix_fmt yuv420p  \
                    -profile:v baseline -level 3 \
                     $STORAGE_PATH/out.mp4
    exit 0
}

Potem ten sam taniec, pętla, obraz, modyfikacja obrazu, sen.

while :
do
    filename=`date +"%Y%m%d%H%M%S"`
    echo "Capturing $filename"
    r="text 0,0 \""$(xdotool getactivewindow getwindowname)"\""
    scrot -D $DISPLAY $STORAGE_PATH/$filename.png
    mogrify -pointsize 40 \
                -fill white \
                -undercolor black \
                -gravity south \
                -draw "$r" $STORAGE_PATH/$filename.png
    sleep 5
done

Cudo. I żeby było zupełnie fair postanowiłem, że nagram sam siebie pisząc pierwszą wersję tego tekstu. Będzie się ona pewnie różniła od tej opublikowanej, musicie mi wybaczyć prace edytorskie. Jeżeli z jakiegoś powodu nie wyskoczy Wam kontrolka wideo, możecie zerknąć bezpośrednio.

Muzykę jumano psych858o^Onslaught

W tym odcinku serialu „rzeczy, które są bezużyteczne ale podstępnie inspirują Was do eksperymentowania z komputerem” to chyba wszystko. Miłej paranoi.

Posłowie dla ludzi używających tmuxa: standardowe formatowanie tytułu okna jest nieco dzikie, zawiera identyfikator sesji i czasem ciężko się zorientować. Możecie dodać te dwie linie do konfiguracji, wtedy pozostaje tylko czysta nazwa procesu:

set-option -g set-titles on
set-option -g set-titles-string '#W'


Dzienniki (pod)różne

Parawany pozwijane, budki z plastikowym badziewiem powoli się zamykają, lokalne ptactwo przechodzi na dietę, lato odchodzi. A ja, wbiegając na peron krzyczę za tym latem: proszę się zatrzymać, ja miałem napisać bardzo zaangażowaną notkę, która zainspirowałaby czytelników do popełniania przygód. I co teraz? Nic. Przygody są dozwolone we wszystkich porach roku, a jeśli będę siedział na tym pomyśle na tekst do kolejnego lata wtedy bez wątpienia utknie on w niebycie jako kilka zdań w notatniku, który jest już zarchiwizowany (wrzucony do szafy z trzydziestoma innymi, nie do odnalezienia w wyniku nieuniknionego ruchu Browna) i prawdopodobnie nigdy nie ujrzy światła dziennego.

Zanim zaczniemy ustalmy fakt o mnie. Lubię dzienniki, pisać i czytać. To niezmiernie frapująca forma literacka, nieustannie tańcząca pomiędzy szczerą autentycznością a kompletnym fałszem. Zawsze nadchodzi moment w którym autor dziennika widzi za swoim ramieniem fantomowego czytelnika i czując do niego, ale też do siebie, olbrzymią sympatię, ubarwia nieco karty. Jak przyjaciel opowiadający tę samą historię i dodający do niej kolejnych powalonych przeciwników i następne skąpo ubrane damy przez lata.

Nie mamy pamięci absolutnej, mamy za to absolutną fantazję.

Jakoś w maju stwierdziłem, że zupełnie przypadkowo cztery książki, które czytam to a) dzienniki b) o podróżach i wymyśliłem, że zrecenzuję je za jednym razem, kogoś może to zainteresuje, zainspiruje i ten ktoś w przyszłości wyśle mi swój własny dziennik i będę dumny z wkładu w kulturę. Chyba, że ten potencjalny dziennik będzie kiepsko napisany, wtedy odczuję tylko żal.

Bones bleaching in the fields, A pillgrimage to Kashima, Knapsack Notes, A Journey to Sarashina, The Narrow Road through the Hinterlands

Bashō wielkim poetą był. W czasach epoki Edo aby być wielkim poetą należy utrzymywać dobre kontakty z możnymi i arystokracją których dobre słowo może zamienić się w mecenat, spotkać się z „kolegami po fachu” oraz przekonać młodych ludzi do podążania tą samą ścieżką rozwijając szkołę krzewiąc styl mistrza, a to wymagało podróży po całym kraju.

Here I am, not dead
after many nights on the road—
at autumn's end.

Nie podróżował on jednak tylko dla sławy, w pierwszą długą podróż udał się szukając śmierci po serii niepowodzeń i nieszczęść z której Matsuo nie mógł się otrząsnąć. Zamiast tego znalazł na drodze radość i nową nadzieję, a podczas kolejnych, inspiracje i przyjaźnie. Jak przystało na poetę-wędrowca spisał on serię dzienników, często obecnie wydawanych pod jednym tytułem, pełnych widokówek, dialogów i oczywiście, wierszy, układanych pod gołym niebem, w knajpach i na salonach. Znajdziemy w dziennikach haiku, renga, ulubiony gatunek Bashō, wiersz układany przez wiele osób, wers za wersem, lirykę, okruchy zuihitsu.

A bee makes its way out,
from deep in the peony flower—
but with regrets.

Ta pozycja jest najtrudniejsza do polecenia, gdyż przygody spisane są iście mnisze, a szkielet dzienników składa się głównie z poezji, do tego niemal każde zdanie ma osobną historię ukrytą w bogatych przypisach (w moim wydaniu). To jedna z tych książek, którą mogę opisać jako „polecam wszystkim mnom”.

Mapa podróży opisanej w «Narrow Roads through the Hinterlands»

Full Tilt

Jedno słowo — „fantastyczne”. Autorka tego dziennika wsiadła na rower i pojechała z Dunkierki do Indii, zaczynając swoją podróż w styczniu, co wydaje się być fatalnym wyborem z praktycznego punktu widzenia, ale dobrym dla dziennika. Jest 1963. Świat wygląda zupełnie inaczej. Żelazna kurtyna. Jugosławia. Na granicy Afgańskiej służby nie mogły zrozumieć konceptu samotnej kobiety na rowerze, podróżującej przez świat, ostatecznie zamiast wydania jej wizy władze znalazły rozwiązanie iście „salomonowe”, wpisali Dervlę jako bagaż dwóch Niemieckich panów jadących samochodem w tym samym kierunku z przykazem żeby kobietę „oclić” po drugiej stronie.

Kombinuję jak tu wyłuszczać, że dziennik jest fantastycznie napisany, ale non-stop kasuję paragraf za paragrafem wracając do pierwszej tezy. Dziennik jest fantastycznie napisany, nie tak jak ten tekst.

Kiedy Dervla ma przygodę, bez względu na to jak niebezpieczną i w jakie tragiczne skutki może się ona obrócić, spisana jest ona dramatycznie ale, nie płaczliwie, a co najważniejsze — krótko. Kiedy złapałem gumę napisałem pięć tysięcy słów opisując lekko uciążliwą sytuację, która mnie spotkała. Dla porównania oto Dervla zaatakowana przez dzikie zwierzęta w lesie.

I stumbled, dropping the torch that I had been carrying, then recovered my balance, and found one animal hanging by its teeth from the left shoulder of my wind-cheater, another worrying at the trousers around my right ankle, and a third standing about two yards away, looking on, only its eyes visible in the starlight. Ironically enough, I had always thought that there was something faintly comical in the idea of being devoured by wolves. It had seemed to me the sort of thing that doesn’t really happen … So now, as I braced my body against the hanging weight, slipped off my glove, pulled my ·25 out of my pocket, flicked up the safety-catch and shot the first animal through the skull, I was possessed by the curious conviction that none of this was true, while at the same time all my actions were governed by sheer panic

Dervla nigdy nie pęka na trasie, jest pokorna wobec sytuacji które się jej wylosowały, posiada stalowy charakter i zaraźliwą beztroskę i dobroć wobec wszystkiego dookoła niej.

Dziennik ten czyta się lepiej niż większość nowelek przygodowych. Więcej akcji, lepsza proza i jeszcze się wydarzyło.

Of walking in ice

Kupiłem tę książkę kilka lat temu i przez te lata przejechała ze mną w plecaku setki kilometrów, ale nigdy nie miałem odwagi jej otworzyć i zacząć czytać. Myśl założycielska podróży Herzoga przez tytularny lód tej jest irracjonalna i znajoma, czułem niepokój myśląc o tym, co mogę tam znaleźć.

Na wieść o tym, że jego przyjaciółka, jest chora i umiera Werner postanawia, że aby powstrzymać los musi się udać pieszo z Monachium do Paryża. Jeśli jego misja się powiedzie życie przyjaciółki zostanie ocalone. Założył kurtkę, nowe buty i plecak i wyszedł w październikowy lód dotrzymać swojej części targu.

Być może nie wszyscy, ale część z was rozpozna pewnie tę niewymówioną chęć używania własnego cierpienia jako zastawu do niepodpisanego kontraktu z prawdopodobnie nieistniejącymi siłami posiadającymi nadludzkie możliwości odmieniania losu.

Moje obawy były częściowo słuszne. Dziennik zaczyna się jak podróżny dziennik powinien, od utyskiwania na małe niewygody, żywego opisywania okolicy, ludzi w wyszynku, małych przygód jak włamywanie się do domków wypoczynkowych na nocleg.

Im dłużej Herzog idzie tym bardziej z jego prozy zerka na czytelnika mania. Pomiędzy zdaniami o rzece pojawiają się krótkie historie o afrykańskich watażkach, pomiędzy paragrafami poutykane są bomby atomowe i anioły. Czasem zatrzymywałem się na tych dodanych kolorach i palcem wodziłem wstecz po stronie żeby znaleźć genezę, która być może mi umknęła, często bezskutecznie.

I kiedy Herzog stał wreszcie na przedmieściach Paryża nie odczułem żadnego katharsis tylko zmęczenie, jak on. Zdecydowanie polecam jako lekturę dla ludzi ceniących sobie udrękę, samotność i chłód.

Busy doing nothing

Gdy podróżuję stawiam na metody, które pozwalają mi zmienić zdanie. To odbywa się kosztem odległości, ale uważam, że jeśli ktoś nie potrafi odkryć fantastycznych światów 80 kilometrów od domu nie będzie mógł ich znaleźć 8000 kilometrów dalej. Jestem też skąpy i boję się samolotów, nie wiem więc, czy wymyśliłem tę ideologię na własne potrzeby, czy też na serio w nią wierzę.

Kiedy idę lub jadę rowerem w każdej sekundzie mogę zmienić zdanie, w lewo, w prawo, tu zostaję. Maksymalna rozdzielczość, najmniejszy dystans. Pociągiem mogę się rozmyślić tylko co stację, rozdzielczość się zmniejsza, zwiększa dystans. Nadal w granicach mojego komfortu. Samoloty i statki mają zbyt niską rozdzielczość. Trudno jest zmienić zdanie w samolocie i wysiąść. Ze statku można wysiąść choć jest to całkiem bezcelowe.

Kiedy dowiedziałem się, że mały kolektyw artystyczny 100r, który znałem wcześniej ze środowisk związanych z tworzeniem alternatywnej ścieżki technologicznej dla przyszłego, może niezbyt wygodnego, świata, wydał książkę o podróży żaglówką z Japonii do Kanady, zakupiłem ją natychmiast.

Czytanie dzienników upewniło mnie w moim uprzedzeniu do metod transportu o „niskiej rozdzielczości”, które wspominałem wcześniej. Długie dni niczego przeplatane są momentami ekscytacji, zwykle tego nieproszonego typu. Zaawansowana buchalteria: zarządzanie jedzeniem, wodą pitną, benzyną, energią elektryczną. Sztormy, omijanie kontenerowców, zimno, wilgoć. A pomiędzy tym wszystkich dwójka ludzi, którzy bez wątpienia muszą się bardzo kochać, bo żeby wysiedzieć w takiej podróży tysiąc godzin razem trzeba osiągnąć komfort współżycia znany tylko świętym.

Takie podróżowanie to maraton, fizyczny i psychologiczny, do którego nie jestem raczej zbudowany.

Busy doing nothing” może służyć także za bardzo specjalną książkę kucharską, na ostatnich stronach znajdziemy przepisy na potrawy opisane na stronach. Z uwagi na środowisko w którym były przygotowywane są bardzo proste, więc jeśli ktoś jest drętwy w kuchni lub właśnie rusza w wielotygodniową podróż, porady mogą okazać się bardzo przydatne.

Ilustracja: Rekka, za zgodą autorki

I to już wszystko. Cztery książki, cztery metody podróżowania, cztery różne czasy, pięć osób, tysiące kilometrów i zdań. Teraz wasza kolej, do zimy jeszcze daleko.


Syncthing

Niewiele jest programów, które nigdy nie sprawiły mi problemu, które odpalam z pełną pewnością, że mnie nie zawiodą i zawsze wykonają robotę dla której zostały stworzone. Mutt, Vim, ssh… i to chyba tyle. Kilka lat temu dodałem do tej listy chwały jeszcze jeden program: Syncthing.

Mam problem z pisaniem o aplikacjach, jestem pewien, że wszyscy, którzy to czytają nie tylko wiedzą to, co i ja, pewnie więcej, nie mają problemów z przeczytaniem dokumentacji, a bez problemu uwierzyłbym, że 90% z was mogłaby taką czy inną aplikację skompilować ze źródeł. Ciężko czasem zebrać się i napisać coś więcej niż jedno zdanie typu „zbadaj Syncthing, mi się podoba”.

Ponieważ jestem w lesie, napisałem już listy, odpisałem na e-maile, a poza laptopem jedyną technologią w której jestem obecnie posiadaniu, jest świeczka, zmarnuję wam i sobie trochę czasu przed świtem.

Syncthing jak pewnie można zgadnąć z nazwy służy do synchronizacji plików. Temat oklepany i w większości rozwiązany, często po łebkach, przez różne płatne serwisy. Ja nie mogę żyć z nimi w zgodzie z własnym sumieniem, tak jak rodzina jest podstawową jednostką społeczną, tak LAN jest dla mnie podstawową jednostką infrastruktury sieciowej. Poligamia Internetu jest moralnie szara, może nawet godna potępienia. Spędziłem dużo czasu żeby wszystko, co robię działało bez problemów bez względu na to, czy jestem podłączony do Internetu. Jak śpiewał poeta, „mój jest ten kawałek podłogi”.

Używając Syncthinga możemy sparować między sobą komputery, zarówno w LAN, jak i te dostępne poza granicami naszej infrastruktury, przy użyciu jednego UUID wygenerowanego podczas pierwszego startu aplikacji na komputerze. Dzielimy się identyfiaktorem z kimś i kiedy obie strony wyrażą zgodę, relacja zostanie ustanowiona i można wybrać zdefiniowane foldery, które zostaną rozdmuchane na wszystkie komputery. Poza tak oczywistą funkcją, jest kilka rzeczy wartych uwagi, których nie znajdziecie nigdzie indziej.

Zawartość udostępnionych folderów może być „wersjonowana” w kilku różnych trybach, instancja może traktować folder jako „tylko do niego piszę” (nie akceptuję zmian z innych instancji), „tylko z niego czytam” (synchronizuję folder, ignoruję lokalne zmiany), możemy ustawić limity oraz współdzielone hasło używane podczas transmisji. Rzeczą dla mnie najważniejszą jest to, że folder może być dzielony asymetrycznie. Jeśli masz w domu kilka komputerów na których chodzi Syncthing, możesz wybrać dowolną architekturę: kto od kogo synchronizuje i na jakich zasadach.

Zamiast opisywać prozą elementów UI, co zawsze wychodzi słabo, albo kręcić wideo (“don’t forget to like & subscribe”) opiszę wam jak praktycznie używam Syncthing każdego dnia.

Nie lubię telefonów

Powiem więcej, gardzę telefonami. Jest powód dla którego mój telefon leży teraz 90km stąd, wyłączony. Nie da się jednak zaprzeczyć, że są użyteczne. Mój gra podcasty i czasem robi zdjęcia. W wyniku działania klienta podcastu czy aplikacji aparatu na telefonie pojawiasię plik, a ten czasem chcę mieć od razu pod ręką, bez sięgania do telefonu lub polegania na zewnętrznej synchronizacji, która wymaga Internetu.

Syncthing na telefonie. Folder Photos i folder Podcasts udostępnione są w trybie „tylko do niego piszę”, to znaczy, że to jest jedyne źródło prawdy. Domowy serwer (czyli w mojej nomenklaturze, komputer, który prawie zawsze jest włączony i pradopodobnie ma dostęp do Internetu) synchronizuje oba te foldery na swój dysk w trybie „tylko z niego czytam”. Do tej pory jasne. Robię fotkę, Syncthing wysyła ją na serwer. Pojawia się nowy odcinek podcastu, Syncthing wysyła go na serwer. Teraz laptop. Źródłem danych do synchronizacji jest zarówno telefon jak i serwer. Co to znaczy?

Wyobraźmy sobie, że przez noc ściągnął się nowy odcinek. Telefon dogadał się z serwerem domowym. Ja wstaję, wyłączam telefon (to nie jest pogadanka moralna ani hipotetyczna historia, to wtorek w moim domu) bo na co mi telefon rano. Robię kawę, włączam laptopa. Laptop widzi zmiany na serwerze domowym i je do mnie synchronizuje. Mimo braku głównego źródła wszystko nadal działa jak trzeba. A takie choinki zależności możecie budować tak wysoko jak starczy wam kreatywności.

Raz wystarczy

W pracy często przydzielają mi (choć raczej ja przydzielam sobie, a nikt nie protestuje) prace archelogiczno-detektywistyczne. „Zobacz, co można uratować z SebixCMS, dostaliśmy od klienta jako jedyne źródło dokumentów”. Wtedy okazuje się, że struktura folderów jest oparta na znakach zodiaku i kalendarzu księżycowym, obrazki są w TIFF i BMP, wideo w MOV, a dane tabularyczne w formacie wymyślonym przez programistę, który odszedł z pracy przez to, że nie mógł zdzierżyć pracowania z tak okropnym formatem.

Siadam więc i piszę dziesiątki stron notatek, produkuję mniejsze lub większe skrypty, które grabią po tej stajni Augiasza. Problem z tym, że reszta ludzi pracujących w projekcie będzie miała problem z powtórzeniem moich sztuczek. Skąd ja wziąłem ten cruncher do PNG, pewnie ze źródeł jakiegoś zapomnianego projektu na SourceForge, czy da się zbudować żeby działał pod Windowsem? Nie wiem, nie chcę wiedzieć. Który z setek parametrów potrzebny jest do FFmpeg? Kto wie.

Mój komputer w pracy oraz laptop udostępniają więc innym ludziom (i serwerowi testowemu, ekstremalnie użyteczne. Syncthing nie potrzebuje UI, można więc namówić admina (albo ukraść jego id_rsa) żeby zainstalował) folder z samymi artefaktami po przetwarzaniu. Oni synchronizują się do serwera (po co mają wiedzieć UUID mojego prywatnego laptopa?), serwer synchronizuje się do komputera biurowego lub laptopa, a one między sobą.

Schemat opisany w poprzednim paragrafie

Git dla ubogich

Kocham moich przyjaciół, więc kiedy trzeba staram się im ułatwić życie. Piszemy obecnie grę z thungiem. On rysuje, ja koduję. Nikt z nas nie robi muzyki, dzięki bogom. Mógłbym go nauczyć podstaw Gita albo znaleźć jakiegoś biurkowego klienta dla niego, ale i tak praca szła by karkołomnie. Mój podstawowy serwer Gita to sr.ht, gdzie kooperacja w projekcie odbywa się przy pomocy list dyskusyjnych i dystrybucji patchsetów. Jak mówiłem, kocham swoich przyjaciół i nigdy bym im takiej krzywdy nie zrobił.

Mam też obiekcje przed dodawaniem plików binarnych do Gita. Być może jest to traumatyczna reakcja z czasu gdy przyjaciel frontendowiec dodał do projektu katalog „do pobrania” serwisu nad którym pracowaliśmy. W tym na przykład plik instalacyjny Quake3.exe. A ponieważ była to epoka Subversion spędziłem bardzo przyjemne popołudnie ręcznie wycinając jego bohaterstwo z pliku wyprodukowanego przez svnadmin dump.

Odpowiedzią oczywiście jest znów Syncthing! On pracuje jak człowiek, kompletnie nieświadomy mechaniki pod spodem, a ja robię commity. Wilk syty, owca cała. Boję się tylko dnia, gdy pomyśli, że fajnie jest posprzątać w projekcie i wywali jakiś bezużyteczny folder, na przykład .git, w nim same śmieci.

jutup premium

Ustaliliśmy już, że lubię jak wszystko w moim domu działa bez względu na to, czy mogę się dobić do Internetu, czy też nie. Listę “Watch Later” na YouTube traktuję bardzo poważnie, zgodnie z przeznaczeniem. Umieszczam tam filmy, które chcę zobaczyć, a potem je oglądam — jak szaleniec. Normalnie lista “Watch Later” traktowana jest ambicjonalnie, jak modlitwa, trafiają na nie filmy typu „80 kroków by być lepszym człowiekiem”, „Praca z drewnem, od amatora do własnego domu” i „Analiza analizy okropnego filmu niewartego uwagi (7h)” tylko po to by być usunięte po kilku latach.

Skoro traktuję ją poważnie, to znaczy, że chcę ją mieć na moim laptopie. Telefony i tablety mogą pobierać listy odtwarzania, ale a) trzeba za to płacić b) laptopa mam zawsze, telefon jest opcjonalny. Zgadliście, Syncthing.

Na domowym serwerze, w crontabie, siedzi sobie taki oto skrypt.

#!/bin/bash

p=${1:-download}
cd /media/muczoshito/shitube

if [ $p == "clean" ]; then
    rm *vtt *jpg *json *webp *mp4 *concat archive.txt .syncthing*
    exit
fi

/home/hive/.local/bin/yt-dlp --cookies /media/ssd/Syncthing/Sync/cookies.txt \
    --write-info-json \
    --write-thumbnail \
    --write-subs \
    --embed-subs \
    --sub-langs all \
    --embed-chapters \
    --download-archive archive.txt \
    --sponsorblock-remove default \
    -f "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \
    https://www.youtube.com/playlist\?list\=WL
find ! -name '.stfolder' ! -name 'archive.txt' -ctime 15 -delete

On sobie siedzi tam, ja teraz w lesie, ale nadal mogę zobaczyć, co chciałem zobaczyć. Możecie też zauważyć, że plik cookies.txt także pochodzi z folderu Syncthing. Pobranie listy “Watch Later” wymaga autoryzacji, jako że ta jest zawsze prywatna, mam więc cookiejar z odpowiednimi ciastkami sesyjnymi, które mogę pobrać z laptopa.

~ ls /media/dump/Shitube/*.mp4
1983 in Film [Ab5LeWADtEU].mp4
How programmers flex on each other [r6tH55syq0o].mp4
That's No Ordinary iMac G3... [rvkaAqCaduE].mp4

Proszę, oto i wschód słońca. Znowu udało się doczekać końca.

Biurko w lesie, świeczki, papier


Do nieba

Bez względu na to jak ciekawego życia intelektualnego bym nie prowadził i jak bogate jest moje życie wewnętrzne, ludzie najbardziej lubią słuchać historii o tym, jak się wywaliłem. Czasem metaforycznie, czasem faktycznie. Siedząc nad kilkoma tekstami, z którymi nie mogę sobie dać rady, a do tego pisząc w pracy karkołomną dokumentację-wampira, co wysysa mnie ze wszystkiego, postanowiłem, że zrobię sobie przerwę i napiszę coś łatwego i przyjemnego.

Pod koniec marca pojawiło się kilka niespodziewanie ciepłych dni. Spakowałem się więc i postanowiłem, że zrobię przyjemną trasę: pociągiem do Torunia, a potem już rowerem przez Grudziądz, Malbork i ostatecznie Jantar, pomachać morzu, zjechać do Gdańska i do pociągu. Bez pośpiechu, turystycznie. Pierwszy dzień przeszedł bez wydarzeń, zaparkowałem w przyjemnym hostelu na jednym z podjazdów do Grudziądza i spędziłem spokojną noc. Obudziłem się jeszcze przed świtem, pełen niesamowitej werwy. Padał deszcz, ale o ósmej miał przestać, czekałem więc paląc na werandzie i zastanawiając się jak i dokąd pojechać. Może przeskoczyć na drugą stronę Wisły? Nie mogąc się zdecydować postanowiłem, że dojadę do miejsca w którym mogę wybrać nowy kierunek, jakieś 40 km stąd, zobaczę jak się będę czuł i jak będzie się układał dzień.

Ostatecznie nie pozostało nic innego jak jechać, osiodłałem więc rower i zacząłem pedałować. Wyszło słońce, wszystko pachniało pięknie po deszczu, nic tylko się rozkoszować. To był pierwszy wypad tego roku, wyczuwałem więc euforię budującą się w moim sercu.

Miasto, miasteczka, wsie, kilka samochodów, matki z dziećmi, panowie na ławce przy sklepie spożywczym, skryci pod parasolką reklamującą nieprodukowane już piwo, ich pies, nieuwiązany, goni mnie dla ich uciechy, a ja dla uciechy psa przyśpieszam. Wszyscy się bawimy.

Co jakiś czas ciężarówka wojskowa, bez wątpienia należąca do jednostki logistycznej z Grudziądza. Wiem o niej, bo kiedyś chodząc po kątach wlazłem im na teren i choć nie byli z tego zadowoleni, nie zastrzelili mnie, ale dobrze mi zapadli w pamięć.

Mijam jakieś małe jeziorko i słyszę odgłosy radości. Oglądam się przez ramię i widzę jak dzieci paradują z jakimiś patykami przy plaży, po chwili ściskam hamulce i zawracam. Marzanna! Koresponduję listownie z Tereską z Uncanny Japan i kilka miesięcy temu opisywałem jej topienie Marzanny, pomyślałem, że mógłbym zrobić kilka zdjęć i wysłać jej reportaż z pierwszej ręki. Ku mojemu zdziwieniu pilnujące dziatwy panie przedszkolanki, kiedy już wytłumaczyłem im mój szczytny cel, pozwoliły mi robić zdjęcia, a ja, nie chcąc nadwyrężać cudzego zaufania zrobiłem ich kilka w kulminacyjnych momentach, podziękowałem i podjąłem podróż. Słońce było już całkiem wysoko, co mnie zastanowiło: gdzie ja w ogóle jestem?

Punkt w którym miałem się zatrzymać minąłem dawno temu, ale uznałem, że to widocznie dobry omen. Oceniłem swoją kondycję: doskonała. Samopoczucie: wyborne. Gdyby nie wcześnie zapadający zmierzch, bez wątpienia celowałbym bezpośrednio w morze, niestety, znam tą trasę i wiem że w nocy byłaby bardzo nieprzyjemna, muszę więc nieco powściągnąć wodze fantazji. Więc Malbork. Z Malborka niedaleko, relatywnie OK baza noclegowa, wydaje się, że to całkiem rozsądne miejsce docelowe.

Pojechałem trasą przy Wiśle, nie był to najlepszy wybór, bo tak wczesną wiosną rozlewiska wysysają ciepło z okolicy. Wszystko było delikatnie rozmazane, zamglone i wilgotne. Z drugiej strony moja zasada mówi, że dłuższa, nawet mniej przyjemna trasa, która ma minimalny ruch samochodowy jest lepsza od każdej wygodnej z TIR-ami wyprzedzającymi się na trzeciego na ulicy tak szerokiej, że można by nad nią splunąć.

Delta Wisły

Jechałem przez kompletne odludzie, w półtorej godziny minęło mnie tylko kilka samochodów i ani jeden człowiek. Kiedy zacząłem powoli odbijać na północny-wschód natknąłem się na samochód policyjny, który wyglądał jakby czatował na kierowców przekraczających prędkość. Oby moja dusza zawsze była natchniona równie silnym optymizmem.

Wioska, wioseczka, lasek, mosteczek, kulawa ławka, encore, jeszcze raz!

Wreszcie ludzie. I zielona tablica z napisem, «PIEKŁO 3». Trzy kilometry do piekła, hi hi. Jadę więc wprost w czarcią paszczę. Droga jest okropna. Podłoże składa się z dziur i wspomnień po betonowych płytach, nawet nie tych pełnych, a ażurowych. Po prawej ręce ukazuje się budynek z napisem «WELCOME TO PIEKŁO».

Witamy w Piekle

Zatrzymałem się na wprost niego i zrobiłem zdjęcie, które natychmiast rozesłałem do bliskich i dalekich. Zapaliłem, napiłem się wody. Już miałem ruszać gdy zatrzymała mnie wiadomość od G. — „kto jak kto, ale Ty nie zasługujesz na piekło”.

Kilkaset metrów dalej, jeszcze poprawiając się na siodełku po postoju czuję coraz bardziej wertepy. Wiem już co się stało, strzeliła mi tylna opona. Zeskoczyłem z roweru aby ocenić sytuację. Sytuacja była jasna, dziura. Nie miałem przy sobie ani zapasu, ani łaty. Pomyślicie, że jestem leniwym głupcem i może macie nawet rację, ale gdybym miał dętkę w sakwach to jak skończyła by się ta historia? „Naprawiłem dziurę i pojechałem dalej, osiągnąłem cel, białe Fin na czarnym podkładzie”?

Stanąłem znów i wyciągnąłem jabłko, od wielu lat przestałem reagować na niedogodności losu ze złością, jestem raczej zrelaksowany i ciekawy, co się z tego urodzi. Mina nieco mi zrzedła po konsultacji z mapą. Nagle 40 minutowa trasa do Malborka zmieniła się w ponad 3 godziny. Dwadzieścia kilometrów pchania roweru, głównie anonimową drogą. W takim razie na końcu tej trasy będę bardzo zmęczony, a to znaczy, że może dobrze będzie wrócić do domu, naprawić rower i wrócić na weekend? Sprawdziłem rozkład pociągów. Mam doskonałe połączenie za 3 godziny i dużo gorsze za pięć.

Nic, idziemy.

Idąc śpiewałem sobie piosenki, bo wraz z pierwszymi oznakami zmęczenia przesiąkały mi do mózgu blaski gniewu, ale te nie mogą przejąć kontroli kiedy z gęby wydobywa się „no żubrze, zróbże minę uprzejmą”. Po jakiś pięciu kilometrach wydobyłem się z lasu i trafiłem na asfalt, który prowadził do jakiejś miejscowości na zapleczu Malborka.

Co jakiś czas mijały mnie auta, a gdy słyszałem za sobą silnik myślałem „o, oto jedzie dobry Samarytanin, który rozpozna strudzenie po mojej lekko pochylonej pozie, zatrzyma się i jeśli nawet nie zabierze mnie ze sobą, to oferuje dobre słowo! A może nawet ja mu odmówię, ostatecznie nie idzie mi tak źle”. A potem auto mnie mijało nie zwalniając nawet, a ja przerywałem piosenkę żeby wymruczeć za nim „ty sukinsynu”.

Miasteczko nie zawierało nic wartego uwagi, zacząłem więc przecinać wielkie pola piaskową drogą. Zadzwoniłem do przyjaciela Bartosza, bo to taki zwyczaj, że dzwonimy do siebie kiedy jeden z nas się rozkraczy. Pośmialiśmy się, powyzywał mnie od najgorszych, co jest jego prawem i prawdą. Zgodził się zebrać mnie z miasteczka odległego o 40 km od Łodzi o pierwszej w nocy, jeśli zdecyduję się jechać tym drugim pociągiem. Tym samym straciłem ostatnią niewiadomą dzisiejszego dnia i mogłem się rozluźnić.

Kilka kilometrów później przyszła od niego wiadomość. „Ej, Malbork jest niedaleko. Zdążysz”. Jak mogę zdążyć, co za bzdury, nawet nie idę specjalnie szybko. Sprawdzam. Wygląda na to, że idąc tym tempem będę na dworcu 5 minut przed pociągiem! Musiałem sporo nadrobić. Przyśpieszmy więc!

Zapiąłem wszystkie rzeczy aby zrobić się jeszcze bardziej aerodynamiczny i ruszyłem z pełnym rozmachem. Kilometr, drugi. Bartosz coś pisze, bo telefon pika, ale nie zatrzymuję się, lecę. Pięć kilometrów, zegarek na ręku wibruje ostrzeżenia, że od długiego czasu mam tętno 150 i powinienem odpocząć. W piekle odpocznę, a że już tam byłem, nie ma lęku.

Teraz pcham pod górę, pod prąd, drogą wyjazdową z Malborka. Leje się ze mnie i nie mam w głowie żadnych myśli, prócz cichej determinacji. Kierowcy wymijają mnie łukiem, czekam aż ktoś mnie opierdoli. Pojawia się samochód policyjny. Wysyłam im mentalnie przekaz, że rozumiem, że obrałem nieortodoksyjną trasę ale niech mnie lepiej nie zatrzymują. Włączyli migacz i ominęli mnie jak inni, legitymizując moją krucjatę.

Za pięćset metrów skręt w prawo i jestem w Malborku. Nie wierzę. Zatrzymałem się na chwilę. Zyskałem ponad 20 minut. Absurd! Teraz tylko na dworzec. Byłem w Malborku raz i nawet nieźle poznałem jego układ, bo spędziłem dużo czasu spacerując, do tego obok mostu na którym stałem, miałem nocleg. Wiem orientacyjnie, gdzie znajduje się PKP ale czy warto ryzykować. Wpisuję PKP i klikam na wynik drżącymi palcami. Nie jest daleko.

Czym dłużej szedłem, tym bardziej napawały mnie wątpliwości. Ten róg pamiętałem, ten sklep, tę restaurację, ale gdy telefon powiedział „w lewo” rzeczy stały się mi obce. Na końcu ulicy widziałem jednak trakcję pociągów, być może to wejście od drugiej strony.

Staję wreszcie przed bramą i dostaję krótkiego ataku paniki. PKP… towarowy. Z rozpędu kliknąłem bez czytania podpowiedź na mapach. Z budki wychodzi pan strażnik, ma na nogach rozdeptane bambosze i idzie w moim kierunku. Bardzo powoli. Krok. Krok. Krok. Pytam go „panie, odjebałem, czy jest szansa, że puściłbyś mnie żebym przeleciał poboczem w kierunku osobowego?”. Zrobił kilka kroków, bardzo powoli, następnie odwrócił się w kierunku bramy i powiedział — „nie”.

No to koniec. Doznałem kilkusekundowego zaćmienia umysłu, wskoczyłem na rower i zacząłem jechać. Kompletnie nie wiem, co mi do łba strzeliło, ale zanim neurony odpaliły ciało już dawno ruszyło. Pięćdziesiąt metrów dalej kompletnie zaklinowało się tylne koło, co było do przewidzenia.

Usiadłem na śmietniku, oparłem rower o nogi i patrzyłem przed siebie. Jaki absurd. Tak się wypieprzyć przed metą. Nic, poddaję się. Siedziałem tak kilka minut patrząc na przechodniów. Nagle zerwałem się na nogi, zarzuciłem sobie rower na ramię, wraz z sakwami i wszystkim, pewnie z 35 kg i zacząłem iść w kierunku dworca. Moja brawura szybko ze mnie uleciała, gdy organizm przypomniał, że dopiero co zrobiliśmy 20 km marszobiegiem. Przechodziłem obok szkoły, z której wychodziła właśnie młodzież i postanowiłem dać sobie 30 sekund. Stacja III, Emil upada pod rowerem. Zbieram się w sobie, rower na ramię i idę. Na następnym skrzyżowaniu poznaję grupkę chłopaków, opuszczali budynek kiedy odpoczywałem. Stoją, palą, relaksują się. Kiedy ich mijam zaczynają wołać „dajesz pan, dajesz” i „dasz radę, kurwa!”. Wreszcie zapowiadani Samarytanie, nie mogę zawieść ich wiary we mnie.

Jak tylko znalazłem się poza zasięgiem ich wzroku, zrzuciłem rower z pełnym zamiarem zawiedzenia ich. Ciekawe, czy mogę rower pchać z tak zablokowanym kołem? Okazało się, że mogę.

Jakaś ładna uliczka, wczesne popołudnie, Malbork. Ludzie na spacerze, zakupach, siedzą w kawiarniach. Dwie strony ulicy blisko siebie, tworzą intymny klimat. I pośród tego ja, pchający rower, którego koło się nie kręci. Materia się opiera i wydaje okropne dźwięki, metal szczęka, opona szoruje, wszystko klekocze. Wreszcie dwupasmowa ulica, którą pamiętam. Po drugiej stronie widzę kobietę z bagażem podróżnym, stoimy na czerwonym. Krzyczę nad ruchem „CZY TĘDY NA DWORZEC?!” pokazując jednocześnie na jedną z dwóch ulic. Potakuje mi. Zrywam się z zielonym światłem, roztrwoniłem wszystkie wygrane minuty. Jakieś 400 metrów i 3 minuty do odjazdu.

Peron. O bogowie, schody. Nie mam siły podnieść już roweru z ziemi na ramię, ciągnę go trochę, trochę wnoszę. Platforma. Stawiam rower na nóżce i siadam w kucki, balansując na piętach. Patrzę bezpośrednio w brudny asfalt peronu, a na nim pojawiają się krople mojego potu, które kapią mi wprost z twarzy na ziemię.

Głośniki ogłaszają, że mój pociąg opóźni się kwadrans. Widocznie tego dnia los chciał mi dać wszystkie szanse.

Duże liczby

Osiemdziesiąt kilometrów na rowerze, dwadzieścia na pieszo, dwieście pięćdziesiąt pociągami i już mogłem usiąść w domu, nieco zmęczony, ale zadowolony.

Kurekta: Anna Matczak


Podszepty

Działo się to w niedalekiej przyszłości. Pewnie w kwietniu, to miesiąc już ciepły, ale jeszcze niezatłoczony. Jestem w obcym mieście, a to miasto wydaje się być w obcym kraju. Zmierzam w kierunku części spacerowo-konsumpcyjnej, wyłożonej wymytym brukiem, obstawioną pastelowymi kamienicami, pod którymi zasadzono kwiaty i ławki.

W tym obcym miejscu jestem umówiony na kawę z kobietą. W celach niecnych lub skandalicznie niecnych, zależnie od szczęścia.

Kawiarnia znajduje się w bocznej uliczce, ma wielkie, czyste okna przez które widać wszystkie stoliki. Siedząc przy jednym z nich człowiek jest jak manekin wystawowy dla przechodniów, przechodnie tworzą teatralną scenę dla ludzi przy stolikach. Każdy wypełnia swoją rolę lokalnego kolorytu.

W kawiarni wszystko prócz kwiatów zwisających nad ladą jest białe. Białe krzesła, białe stoły, białe filiżanki na białych talerzach. Daje to ogólne wrażenie jakby właściciele nie mogli się zdecydować co do wystroju. Jakby lada chwila mieli pojawić się malarze i uzupełnić te meble o wybrane kolory, a ostrożnie, aby nie wychodzić za linie.

Kobieta siedzi już przy stoliku mimo, że jest jeszcze 30 minut do naszego spotkania. Jest po tej samej stronie punktualności, co ja. Nigdy za późno, zawsze dużo wcześniej by zirytować tych, którzy są punktualni. Jestem pewien, że gdyby zapytać ją o to, czy czekała długo, zaprzeczyłaby — tak jak i ja zawsze zaprzeczam. Zapytałbym, gdybym mógł, oboje nie mówimy w swoich językach. Jestem ostatecznie w obcym mieście, w obcym kraju.

Siadam naprzeciw niej i wyciągam telefon, wkładam słuchawkę i łączę się z serwisem, który potrafi tłumaczyć naszą mowę w czasie niemal rzeczywistym. Tylko uważna obserwacja ust pozwoli uchwycić lekkie opóźnienie między ich ruchem, a głosem w słuchawce. Na pierwszej kawie nie wypada intensywnie wpatrywać się w czyjeś usta.

Rozmawiamy o literaturze. Dzielę się wrażeniami o książce, którą niedawno skończyłem, znanej jej. Odpowiada mi:

— Nie mogę pojąć tego teatru rozpaczy, wydaje się, nieuniknionego w tego typu nowelach. Postać ma skończoną objętość, nie można w nią wlać żalu do całego świata i całego świata żalu do niej bo się przeleje brzegiem i wyjdzie niezamierzona komedia, czyli groteska. Książkę można kupić na Amazonie, dla posiadaczy kont typu Prime dostawa w jeden dzień roboczy!

Powiedziałem, że rozumiem i że nie potrzebuję własnej kopii bo wypożyczyłem ją z biblioteki, a lektury niszowe nie znikają z półek, co łatwo udowodnić obserwując stemple. Co rok, co dwa. Zawsze będzie na mnie czekała.

— Zamówmy coś, bo jeszcze nas wyrzucą — mówię pół żartem — ja wezmę zwykłą czarną kawę.

— Dla mnie za późno na kawę, napiję się wody — odpowiedziała — po chwili głos w mojej słuchawce dodał — Najlepiej spędza się czas pijąc Coca-Colę®. Coca-Cola: Taste The Feeling™

Jej usta były nieruchome.


Jak uratować Internet bez wychodzenia z domu

Jest skończona ilość rzeczy, którymi można się przejmować, jeśli ograniczyć ją do rzeczy, którymi powinniśmy się przejmować, staje się ona tak mała, że można ją zapamiętać bez wytężania mózgownicy. Niestety, lista ta — szeroka, czy skrócona — nie jest uniwersalna, co powoduje tarcia na rozmaitych płaszczyznach społecznych. Tarcia te, zwłaszcza spowodowane przez rzeczy z kategorii nieważnych, zapychają Internet, który jest jak wiadomo serią rur, a nie trzeba być hydraulikiem żeby wiedzieć, że to zła sytuacja.

Sugerowanie wam abyście nie darli kota o to, czyj telefon lepiej otwiera aplikacje, a z tych aplikacji, które są gorsze i co to mówią o umiejscowieniu ich użytkowników na drabinie socjoekonomicznej i dlaczego są tak nisko, nie ma sensu. Anarchiści mają rację — ludzie potrafią się organizować bez udziału super-struktury państwa, problem z tym, że to jest częściej organizacja przeciwko czemuś niż po coś. Próba dogadania się z aniołem na waszym ramieniu też się nie uda, bo choć on i wysłucha, zamyśli się nad problemem to ostatecznie odpowie jakoś tak — „Zaiste, masz rację, że godność ludzka jest wartością nienaruszalną, a każdy zasługuje aby go wysłuchano, jednak jebać Legię”. Nie, trzeba otworzyć dialog z szatanem, ale w trybie szatańskim, podstępnie.

Wyobraź sobie, że następnym razem ktoś wygłasza opinie tak głupie jak i trywialne. Może chwali książkę, która jest oczywiście zła, albo gani dobrą, której nie zrozumiał. Może lubi paskudny kolor, a ty możesz naukowo udowodnić, że jest to bardzo nierozsądne i źle o nim świadczy. Nie daj boże słodzi lub nie słodzi czarnej kawy lub z mlekiem. Wszystko są to oczywiste przewiny, które powinny być ukarane z całkowitą surowością, publicznie i bez możliwości apelacji. Chcesz podjąć rękawicę, ale wiesz, że wojna będzie długa, morale może podupaść, może nawet dojść do nieprawości: zwycięstwa twojego oponenta. Czas zdradzić ci tajemnicę dzięki której uratujemy Internet: przedstawiam ci „cichą pogardę”.

Zamiast wdawać się w szarpaninę, przekrzykiwać się z wszelkiej maści głupcami dodając do kakofonii Internetu, spleć ramiona, popatrz na ekran niewidzącym wzrokiem, przekręć głowę delikatnie na bok jakby starając się spojrzeć na sprawę z czyjejś głupiej perspektywy (dla dodatkowego efektu możesz nią pokręcić, ale bardzo delikatnie, z niedowierzaniem), następnie wypuść powietrze przez nos i wypełnij serce cichą pogardą.

Na początku możesz nie czuć satysfakcji z takiego rozwiązania: inni nie widzą twojej cichej pogardy i nie mogą przez to włożyć ci laurów na skronie i obwołać, że zaiste się nie mylisz, ale co powinieneś czuć do ludzi, którzy w ogóle biorą pod uwagę opinie tak jaskrawo błędne, naturalnie obrzydliwe i wymawiane sztywnym językiem? Tak, cichą pogardę.

Odkryjesz, że dzięki takiej optymalizacji zyskałeś dużo czasu, a ten można zainwestować ze zwrotem: możesz czytać dobrą literaturę lub zmywać naczynia. Możesz wyjść na ulicę, stanąć na skrzyżowaniu i oferować każdej starszej pani swoje ramię, iść do parku, usiąść na ławce i machać wszystkim spacerującym psom na powitanie, zadzwonić do dalekich-bliskich i wysłuchać ich problemów. Możesz pojechać do nieodległego lasu i odkryć, że od tak dawna nie słyszałeś ciszy, w uszach i duszy.

A kiedy skończysz te wszystkie prace i wrócisz do domu, okaże się, że nie minął nawet ułamek czasu spalanego wcześniej na ołtarzu ekranu. Miną dni i jeśli wszystko dobrze pójdzie zapomnisz nawet mojej porady o „cichej pogardzie”, zrzucisz szaty komentariatu i staniesz się ponownie człowiekiem.

Emil idzie przez las


molly-guard i kontrolowane wyburzania

Jest druga w nocy i nadal coś dłubiecie. Może wypiliście trzy kolejki dla kurażu. Prawdopodobnie jesteście zalogowani na cztery serwery. Pomiędzy próbą rozszyfrowania niejasnych notatek, przełączaniem się między panelami tmuxa i ogólną gonitwą myśli postanawiacie, że starczy już tej walki i wpisujecie sudo halt.

Connection to production-00 closed by remote host

Żółć podchodzi wam do gardła i to nie przez czwartą kolejkę wypitą przed końcem pierwszego paragrafu. To nie wasz laptop się wyłączył, byliście zalogowani na coś produkcyjnego, ważnego, najpewniej trudnego lub czasochłonnego do podniesienia i to coś właśnie parkuje i odpina się od sieci, żadne rzucone za wysłanymi pakietami bluźnierstwo nie zatrzyma tego procesu.

Jestem niekwestionowanym królem moich serwerów i jak każdy król domagam się kompletnej władzy i zerowej odpowiedzialności za podjęte decyzje, po kolejnej takiej pomyłce postanowiłem jednak poszukać jakiegoś rozwiązania, lękając się komentarzy rozmaitych stańczyków. Okazało się, że wystarczy zainstalować molly-guard i problem sam się rozwiązuje. Molly-guard nadpisuje standardowe destrukcyjne polecenia typu halt czy reboot i wymaga od operatora wpisania nazwy hosta na którym wydaje mu się, że je wykonuje. Ta chwila kontaktu z rzeczywistością wystarczy żeby powstrzymać moją ciężką, morderczą, dłoń.

Nieudana autoryzacja z molly-guard

Życie toczyłoby się dalej normalnie, gdyby nie moja patologiczna chęć do „ulepszania” mojej domowej rupieciarni. Zadecydowałem, że przywrócę do łask, przesuniętą wcześniej do demobilu, RPi3. Był tylko jeden problem: deficyt kabli zasilających. Jako zaprawiony partyzant wymyśliłem, że mogę zasilać RPi3 z portu USB RPi4!1 Jak wszystkie dobre technologiczne rozwiązania, przyszło to z przeciwwagą nowo powstałego problemu. Mianowicie zatrzymanie RPi4 odcina zasilanie do RPi3, która mogła robić coś bardzo ważnego.

Potrzebowałem „można teraz bezpiecznie wyłączyć komputer” dla nowego tysiąclecia.

I tak zawróciłem do molly-guard, szybka lektura manpage wyjaśniła mi, że warunkiem do wykonania polecenia chronionego przez ten program jest poprawne odpalenie wszystkich skryptów znajdujących się w /etc/molly-guard/run.d. Dodałem więc 35-calmyotits zawierający tylko jedną linię z exit o niezerowej wartości (równoważnik „ten skrypt się nie wykonał”), napisałem sudo halt i zgodnie z instrukcją procedura została przerwana.

Użyłem więc tej metody do „kontrolowanego wyburzenia” obu komputerów. Kiedy RPi4 dostaje halt, molly-guard wysyła halt do RPi3, a następnie wchodzi w fazę oczekiwania na zniknięcie ofiary z sieci. Następnie zamyka się sama.

Uwielbiam technologię, dzięki dekadom doświadczenia mogę rozwiązać prawie wszystkie spowodowane przeze mnie problemy! Powinienem odsunąć lodówkę, wymienić zasilacz na taki z dwoma portami, otworzyć szufladę z kablami, zakląć nad panującym tam burdelem, obiecać sobie, że kiedyś to sprzątnę, odnaleźć potrzebny kabel, dowiedzieć się że jest za krótki, odnaleźć odpowiednio długi potrzebny kabel, przesunąć lodówkę na miejsce, jak normalny człowiek.

#!/bin/bash

timeout=10 # liczba powtórzeń
result=0 # zainicjalzujemy rezultat PING-nięcia
echo "Sending halt to 3pi"

ssh emil@3pi sudo halt > /dev/null

while [ $result = 0 ]; do
        ping -c 1 3pi > /dev/null
        result=$?
        echo "Going $timeout"
        sleep 2
        ((timeout=timeout-1))
        if [ $timeout = 0 ]; then
                echo "Can't confirm that 3pi halted"
                exit 69
        fi
done

echo "3pi calmed down"
exit 0

I już!

RPi4 wyłącza RPi3

Z okazji 2023 życzę Wam dużo mniej bezsensu w życiu.

  1. Tak, wiem, że to za małe natężenie dla optymalnego działania, ale nadal działa™

Tak było, jest i będzie

Nabyłem się dziwnej ułomności. Wielu literatów znam z ich esejów, listów, polemik i dzienników bardziej niż z nowel czy zbiorów poezji.

Do Tołstoja, Fauklnera, Bashō, Berry’ego, czy też Orwella dorzuciłem ostatnio Umberto Eco, którego trzy tomy (tomiki właściwie, sto parę stron) esejów opublikowanych w tygodniku L’Espresso na przełomie lat 1986-1996 znalazłem na półce biblioteki.

Nie będę podejmował próby recenzowania tego zbioru, bo mam do tego zero talentu, wystarczy powiedzieć, że kilka mi się podobało, większość była neutralna, a te dotyczące włoskiej polityki przeleciałyby mi kompletnie przez palce gdyby nie nazwisko Berlusconiego, dla Eco premiera rządu, dla mnie właściciela skandalicznie dobrej drużyny AC Milan. Czemu zajmuję więc Wam czas? Ostatni tom, z lat 1994-1996, zawiera kilka esejów dotyczących Internetu i komputerów ogólnie. O komputerach w tamtych czasach czytałem dużo, ale moimi źródłami były jedyne osoby, które w tamtych latach darzyłem zaufaniem: inni pojebani komputerowcy. Co też mógł myśleć, mający wówczas 62 lata, mediewista?

Już w pierwszym tomie Umberto ujawnił się jako ktoś, kto lubi technologię i ją rozumie, ale nie uważa, że samo jej istnienie jest wartością dodaną. Spędza jeden esej wertując katalog sklepu elektronicznego sprzedającego wysyłkowo rozmaite gadżety, w tym protoplastę smartłoczy1 — skomplikowany zestaw czujników pod postacią uprzęży i zegarka jako terminala, dla biegaczy. Eco zastanawia się jak dobrze mają Amerykanie, którzy mogą otrzymać audio-wizualne ostrzeżenie o zmęczeniu, gdy biegaczy w Afryce musi po prostu złapać kolka. Teraz byłaby to trywialna obserwacja, sam ją pewnie popełniłem, ale w 1982 jest ciekawą prognozą.

Dostało się też ikonom. Ikony, jak zauważa Umberto, są przydatne w momentach, kiedy musimy coś zakomunikować bez użycia języka. Toaleta na międzynarodowym lotnisku, znak STOP na granicy. Według autora każdy użytkownik komputera musi umieć czytać żeby móc coś ze swojej maszyny wydusić. Ikony same w sobie, zwłaszcza w czasach przed unifikacją interfaceów, były za każdym razem zgadywanką. Przykładowo panel wyszukiwania schowany pod ikoną przedstawiającą czapkę-uszatkę noszoną przez Holmesa. Sam pamiętam, że to gdzieś widziałem.

Tu naszła mnie myśl poboczna: przeszliśmy pewien cykl. Na początku ikony trzeba było odkryć, bo akcje, które reprezentowały nie były jasne, więc i one nie były. Potem osiągnęliśmy equilibrium, by ostatecznie ikony znów straciły kompletnie znaczenie. Czemu ikona z niebieskim i białym prostokątem zapisuje mój dokument „do chmury”?

Dwa teksty poświęcone były wyszukiwaniu. Pierwszy tekst dotyczy dziobaków i przypomina mi o czasach nieco bardziej sielskiego, zdecentralizowanego naturalnie dzięki braku obecności molochów i ich grawitacji, Internetu. Wynikami dyskutowanymi są strony Uniwersytetu w Illinois, prywatne zapiski fascynatów, lingwistyczna monografia na temat „jaka jest prawidłowa forma mnoga słowa «dziobak»”, katalog monet z wizerunkiem stworzenia oraz stronę poświęconą hipotezie jakoby dziobak, zwierze „anty-kantowskie, kolażem złożonym z cytatów z innych zwierząt”2, jest dowodem na akt stworzenia, bo ewolucja takiej rzeczy nie mogła „poskładać”.

Całkiem przyjemna podróż w przeszłość.

W drugim tekście o wyszukiwaniu jest o gołych paniach i niemożności odkrycia, gdzie się chowają w publicznym Internecie. Eco co chwila zachodzi, zaproszony linkami pełnymi obietnic na prywatne strony, które golizny nie zawierają. Poświęca więc chwilę na pracę detektywistyczną i odkrywa pracownika banku, który dorabia sobie utykając różne internetowe katalogi3 linkami do stron prywatnych opisanych jako golizna. SEO, pod różnymi nazwami, było zawsze przekleństwem, choć wykonane manualnie przez kogoś dorabiającego na piwo wydaje się szlachetniejsze niż to, które mamy obecnie.

Ostatnim odwiedzonym linkiem okazuje się być strona zawierająca purytańskie kazanie do poszukiwaczy pornografii, pełną ostrzeżeń co do szkód natury duchowej i cielesnej jakich można się nabyć przez konsumpcję. Tam kończy się esej, bez osiągnięcia ekstazy.

Zabawne, że składacz, wydawca lub tłumacz (a może wszyscy naraz) wykłada się za każdym razem, gdy w tekście znajduje się URL. Książka wydana w 1997, wydawałoby się, że sztuka stawiania dwukropków i slashy została opanowana w wystarczającym stopniu.

Zdjęcie książki ukazujące błędnie wydrukowany adres

Nie dało się uniknąć najważniejszego tematu lat dziewięćdziesiątych: świętych wojen między platformami. Uberto postuluje aby wojnę pomiędzy Macintoshem a PC-tem rozpatrywać w kategoriach sporu pomiędzy katolicyzmem a protestanckim kalwinizmem. Macintosh jest katolicki, spolegliwy, katechetyczny, prowadzi cię za rękę do zbawienia. PC jest protestancki, bo nie oferuje zbawienia każdemu, a tylko tym, którzy podejmują dobre dzieła, takie jak edytowanie autoexec.bat. Windows jawi się autorowi jako dzieło kontrreformacji.

My, amigowcy, byliśmy bez wątpienia jakimś odłamem buddyzmu. Uwięzieni w samsarze, skazani na wieczną śmierć i odrodzenie.

Ostatni tekst dotyka Internetu w najmniejszym możliwym stopniu, jako puenta. Jest jednak najbardziej, jeśli mogę to tak ująć, współczesny.

We włoskim mieście zebrała się grupa intelektualistów by spróbować stworzyć „esperanto tolerancji”, jedną pozycję, którą można pokazać dzieciom szkolnym i przez to dać im narzędzia do lepszego życia w społeczeństwie. Idea godna pochwały, choć wydaje się nieco naiwna. Nie jest to tylko moja opinia, sami zainteresowani polegli, bo wyprodukowanie kompletnego zbioru etycznych zachowań w oderwaniu od kultury jest trudne. Nie ma prostego sposobu na posortowanie tragedii według jakiegoś klucza, nie da się też ich wyabstrahować z przyczyn i skutków aby powstała Jedna Ludzka Tragedia jako miara niegodziwości.

Spisali więc kilka przykładów, potknięć i obaw w notce służbowej, a potem postanowili zmienić nieco kierunek. Notka wyciekła. Ludzie o dobrych i czystych sumieniach, wolni od grzechów głównych i pomniejszych przeczytali ją uważnie i bez kontekstu po czym rzucili się do swoich faksów by wyrazić niezadowolenie na skandaliczne przykłady w niej użyte. Eco zauważa, że tylko jedna płomienna skarga została złożona przez pracownika włoskiego uniwersytetu, a reszta przypłynęła ze świata, gdzie znajomość języka w której była spisana jest niska. Wysuwa więc hipotezę, że ktoś, gdzieś — może na usenecie, może gdzie indziej, umieścił jej treść. Przetłumaczoną lepiej lub gorzej, ale zatrzymującą uwagę. Jak inaczej wytłumaczyć taką błyskawiczną reakcję?

Czego więc dowiedziałem się o komputerach i Internecie z tekstów osoby postronnej? W sumie niczego, Internet nie zmienił się prawie w ogóle, ani ludzie, co nie jest dziwne, bo nawet amatorska lektura antycznych tekstów czy nawet naściennych bohomazów ujawni nam to szybko. Nadal można znaleźć teksty o dziobakach, prowadzić święte wojny o wyższości rzeczy, którą kupiłeś nad rzeczą, którą kupił ktoś inny, ikony też coraz gorsze, a może ich nawet nie ma, to tylko reszka tej samej monety. Jedyne, co się zmieniło to dostęp do golizny, ale nie będę z tego powodu klaskał.

  1. czy też „zegarków szpiegowskich”, ale nie że ty jesteś Jamesem na usługach jej Królewskiej Mości, tylko, że on Cię szpieguje
  2. Cytuję tu esej, nie zawartość strony
  3. Zanim wyszukiwarki potrafiły przeskanować i zinterpretować większość Internetu katalogi pełniły dobrą odskocznie dla niedzielnego internauty

Droga donikąd

Roads go ever ever on,

Over rock and under tree,

By caves where never sun has shone,

By streams that never find the sea

— Bilbo Baggins

Rower przed Dworcem Fabryczna

Pierwszy akt tej historii był przyjemny i napawał nadzieją. Wstałem o świcie mając w planach kilkudniowy rajd przez Mazury. Plan nadrzędny: radość. Plan podrzędny: odnalezienie przyjaciół, którzy zaplanowali urodzinową imprezę gdzieś wśród niezliczonych jezior. Po mojej stronie, jak zwykle, wszystko było zapięte na ostatni guzik. Trasy wyznaczone, noclegowiska zamówione, umysł rześki, oczy bystre, skarpety czyste. Zabawę biorę śmiertelnie poważnie.

Wysiadłem w Olsztynie, odwróciłem się w kierunku wschodnio-północnym i zacząłem pedałować. Pierwszym przystankiem miało być Mrągowo, gdzie blisko dwadzieścia lat temu spędziłem bardzo dobre wakacje. Wymyśliłem sobie, że odwiedzę to czy tamto miejsce, a na drugi dzień spróbuję złapać się z przyjaciółmi. Dzień był piękny, droga prosta, nieuczęszczana przez TIR-y i głównie asfaltowa.

Krajobrazy przekradały się bokami, a ja pedałowałem w stanie zupełnej błogości. Dziesięć kilometrów, dwadzieścia kilometrów, pewnie nawet trzydzieści kilometrów i herbata z termosu na przystanku PKS, tymczasowym domu wszystkich wędrowców i włóczykijów. Tu popełniłem pierwszy błąd, sprzeniewierzając się bogom podróży — wyciągnąłem z sakwy telefon żeby zobaczyć jak mi idzie. Na ekranie była niebieska linia trasy, dobrze już zużyta. Zauważyłem też Biskupiec. Biskupiec brzmi jak „zawiera znaczne ilości średniowiecznej architektury” i choć sam architekturę oceniam tylko w kategoriach „czy wieje w nery na jesień i czy pada na głowę na wiosnę”, D. lubi zameczki i klasztory, a ja zawszę chcę się przypodobać D. — zapytałem więc jej, czy powinienem może odbić te kilka kilometrów z trasy i zbadać okolicę, może zrobić jakieś zdjęcia i jej wysłać. Powiedziała, że z pewnością byłoby jej przyjemnie gdybym znalazł jakieś zameczki. Dla mnie to wystarczająca motywacja. Odbiłem w lewo, podążając za znakami.

Biskupiec okazał się być dużo mniej zajmujący niż sobie to wyobraziłem. Było około dziesiątej rano, postanowiłem więc, że to dobry czas znaleźć miejsce na śniadanio-obiad i odpocząć chwilę. Zostało mi ile, dwadzieścia, może trzydzieści kilometrów. Nawet na pieszo nie robiłbym paniki. Knajpy były jeszcze zamknięte, ale bez wątpienia niedługo jakaś się otworzy.

Usiadłem w ogródku jednej z nich, pełnej poskładanych krzeseł przeciągniętych łańcuchem i złożonych parasoli, wyciągnąłem notatniczek i pióra i zacząłem sobie mazać bzdury. Po jakimś czasie pojawiła się Pani ze szmatą i oznajmiła, że jeszcze nieczynne. Na pytanie, czy przeszkadzam zaprzeczyła. Siedziałem więc dalej, aż do otwarcia.

Kiedy wyszedłem po śniadanio-obiedzie niebo było koloru stali i coś z niego ciekło. Nie wyglądało na wielki deszcz, postanowiłem więc poczekać chwilę pod już rozpiętymi parasolami. Towarzyszyła mi Pani, która zwierzyła mi się, że ma podobne nadzieje, co do deszczu. „Niedługo przejdzie” — skłamała. Przytaknąłem. Po pół godziny pojawili się jej znajomi z parasolem i zostawiła mnie samego.

Wydobyłem z plecaka płaszcz przeciwdeszczowy i postanowiłem toczyć się dalej, ale natychmiast popełniłem drugi błąd. Nienawidzę jeździć dwa razy tą samą trasą. Skoro zjechałem tu tędy, oczywiste jest, że jak pojadę tędy to ostatecznie wyjadę w tych samych okolicach. Miałem rację sensu stricto, gdyby świat był idealną płaszczyzną niepoprzecinaną produktami industrialnej rewolucji, takimi jak drogi szybkiego ruchu, płoty i inne naturalnie niewystępujące barykady.

Deszcz padał coraz mocniej. Ubranie kleiło się do mnie, tracę ciepłotę ciała i cierpliwość. Co gorsza, nie byłem pewien, czy uda mi się skręcić, S16 odcinała mnie od mojej pierwotnej trasy. Wreszcie widzę jakiś skręt. Telefon mówi: „skręć w lewo”. Ale jak to „w lewo”, przecież to podjazd na S16. A może się mylę? Podjeżdżam szybko żeby sprawdzić i oczywiście, niestety, się nie mylę. To Google Maps1 zwariowało. Dobrze, zrobię to po swojemu, pojadę boczną uliczką, będzie dobrze. Zawsze ostatecznie jest dobrze. Po kilku kilometrach widzę kolejną odnogę ulicy i znak zguby — T — ta droga prowadzi donikąd.

Szybko przekonuję siebie, że to jest tylko dla samochodów. Nawet jeśli droga się urywa, to pewnie jest to lasek, rzeczka, zarzucę rower na plecy i przejdę. Jestem tak przemoczony, że nic mi nie grozi. Dojeżdżam do skraju drogi.

Zaiste, droga jest nieprzejezdna dla samochodów. Niestety, także rowerów. W ogóle dla wszystkich, którzy nie posiadają na podorędziu lotni lub spadochronu. Droga kończy się skarpą. Zdyszana gonitwą świadomość mnie dogania: ładnie się wjebałeś. Wyciągam wreszcie telefon i chroniąc ekran od deszczu próbuję się zorientować w sytuacji. Jedyną drogą, którą mogę obrać jest skręt, który ominąłem. Jest to okrężna trasa, dodaje jakieś czterdzieści pięć kilometrów. To plus ile już przejechałem da finalnie jakieś sto dziesięć. Deszcz pada dalej. Zimna świadomość, że z geografią nie da się negocjować dosięga mojego umysłu, poddaję się i zaczynam jechać.

Niewiele z tej części zapamiętałem. Były tylko TIRy, chłód, absurdalne, niekończące się podjazdy i zjazdy, które nie wynagradzały mi wspinaczki. Zaczynało się powoli ściemniać, a do tego nad wszystkim zawisła mgła. Postanowiłem zrobić zdjęcie stając na szczycie jednego z podjazdów, ale przez deszcz zalewający telefon zrobiłem sobie selfie — najlepsze selfie.

Emil jest zmęczony

Zaprawdę obraz wart jest 1000 słów. Dobrze, że napisałem więcej, inaczej to wszystko nie miałoby sensu.

Powoli zbliżałem się do E600, a stąd już może siedem kilometrów do hotelu. Będzie dobrze. Zaczęło padać jeszcze mocniej. Już czuję smak zwycięstwa: nad przyrodą, topografią, samym sobą. Nie ujechałem trzech kilometrów, a drogę zagrodził mi funkcjonariusz. Stanąłem w korku. Minęło dziesięć minut, stojący obok mnie samochód uchylił szybę po stronie pasażera i kierowca krzyknął do mnie „Panie, nie wiesz Pan, co się dzieje. Ile tak można stać?” — popatrzyłem na niego zalewany strugami deszczu i powiedziałem, że nie wiem i że ogólnie też mi obecna sytuacja niezmiernie mało pasuje.

Wreszcie się wyjaśniło. Ruch wahadłowy. Lewy pas jest wylany nowym asfaltem. Nienawidzę ruchu wahadłowego. Znaczy on dla mnie tyle, że przez nieokreślony czas muszę pędzić jak szalony w towarzystwie samochodów, których kierowcy są równie zirytowani jak ja, tylko mogą utrzymać prędkość pozwalając przemknąć się przez zmianę świateł bez problemu kiedy ja nie bardzo.

Zielona tablica: Mrągowo. Znajduję hotel. Przypinam rower, melduję się. Pytam w recepcji: macie coś do jedzenia? Nie, protokół pandemiczny. A herbaty dacie? Nie, protokół pandemiczny. Potakuję ze zrozumieniem. Wchodzę do pokoju, rozbieram się z brudnego i cuchnącego od potu ubrania, otwieram okno, okno wychodzi na skrzyżowanie. Na czerwonych zatrzymuje się samochód z którego dobywa się jebjebjeb basu. Potakuję ze zrozumieniem.

Wychodzę poszukać czegoś do jedzenia, ale miasto jest puste i śpiące. Jedyny otwarty sklep w okolicy to sklep z alkoholem. Kupuję więc kilka butelek kolacji i wracam do pokoju. Próbuję się zrelaksować. W telewizji pokazują mecz reprezentacji z Holandią, przegrywamy go w fatalnym stylu. Omdlewam w sen bez snów.

Rano przyszło niespodziewanie i zupełnie nieproszone. Wymknąłem się z hotelu i wbiłem lokalizację, którą otrzymałem e-mailem. Miejsce spotkania z przyjaciółmi. Kiedy zobaczę ich pogodne, roześmiane twarze i opowiem im o wczorajszym dniu wszystko zamieni się w żart i zostanie zapomniane.

Jechałem bardzo wolno, zjadłem rogalika, dwa razy źle skręciłem. Powoli, ale nieuniknienie, zmierzałem do celu.

Wjechałem do miasteczka-celu. Nagle rower zrobił brzdęk, a moje siodełko zaczęło się kręcić tak bardzo, że natychmiast z niego zeskoczyłem. Śruba się poluzowała? W normalnej rzeczywistości to byłaby odpowiedź. W mojej rzeczywistości śruba po prostu pękła. Podniosłem siodełko z ziemi, wsadziłem je pod pachę i udałem się do knajpy. Byłem sześćset metrów od miejsca spotkania. Reszta się sama wyjaśni.

Zadzwoniłem do Oli żeby obwieścić moje przybycie. Powiedziała, że oni jeszcze nie wyjechali, norma. Ostrzegłem ją, że będę miał niesamowicie zabawną historię na wieczór. Powiedziała mi, że nie może się doczekać.

„A, jeszcze jedno. Musieliśmy zmienić lokalizację, bo w pierwotnym miejscu nie było miejsc dla nas wszystkich. Wyślę ci «pinezkę»” — dodała.

Aha. Aha. Ha ha. Patrzę, osiem kilometrów stąd. Próbuję zlutować pękniętą śrubę nienawistnym spojrzeniem, niestety nie osiągam temperatur topnienia. Pomysł prowadzenia roweru poboczem ruchliwej ulicy porzucam niemal natychmiast. Jadę bez siodełka. Kiedy mięśnie nóg przekonują mnie, że nie mogę tyle jechać na stojaka bolec, bodący mnie niespodziewanie w tyłek przypomina mi, że siodełko przypięte jest do bagażnika.

Trafiam na miejsce. Znów zaczyna padać. Dzwonię do przyjaciół z informacją, że jestem i czekam. „Jeszcze nie ruszyliśmy” — odpowiadają. Moi przyjaciele to dobrzy ludzie, ale nie można powiedzieć, że da się podłóg nich regulować zegarków. Najwyżej kalendarz i tylko pod warunkiem, że jest to kalendarz, który pokazuje tydzień na jednej stronie.

Siadam więc i czekam. Pada deszcz, gniazdka nie działają, herbata jest paskudna.

Jakieś miejsce w deszczu

Minęło ledwie siedem godzin i już byli!

Impreza urodzinowa była przednia, a moją tragiczną historię przebiła wielopoziomowa anegdota, poskładana niespodziewanie z naszych odrębnych obserwacji, praktycznie niewytłumaczalna tekstem, a przynajmniej nie przeze mnie. Była jednak tak zabawna, że kiedy tylko sobie o niej przypomnę wybucham autentycznym śmiechem, na głos, czasem ściągając na siebie wzrok postronnych obywateli.

Rano nie czułem się fantastycznie, wypiłem jeszcze więcej paskudnej herbaty i zjadłem równie paskudne parówki z budy-restauracji na obiekcie wypoczynkowym. Ponieważ moja przygoda musiała się tu zakończyć padła propozycja podrzucenia mnie na najbliższy dworzec, na co przystałem z radością. Truchło mojego roweru i truchło mnie zostało wpakowane do vana.

Wszystkie górki i krzywizny, zakręty i przyśpieszenia odkładały się w mojej głowie i żołądku. Zlał mnie zimny pot. Nienawidzę jeździć samochodem nawet w najlepszych czasach, a to nie był najlepszy czas.

Wreszcie zostałem porzucony na dworcu. Dumna nazwa dla betonowej platformy przyklejonej do pojedynczego toru z widokiem na nieużytki i skarlały las. Po dwóch dniach smagania mnie deszczem natura wymyśliła, że nagrodzi mnie równie intensywnym słońcem. Powietrze drgało od gorąca, ostatnią butelkę wody wypiłem dawno temu, herbata w termosie skończyła się wczoraj. Szumiało mi w głowie, aż do gardła podchodziła mi żółć, próbowałem się szybko otrzeźwić żwawym spacerem dookoła platformy, ale w wyniku niekompatybilności oprogramowania ze sprzętem moje nogi odmówiły posłuszeństwa i runąłem na tory.

Leżałem tak z głową na torach jak samobójca w romansach, zwinięty skurczem i marzyłem o pociągu, który skróciłby te męczarnie, choć wiedziałem, że przyszłoby czekać tak przynajmniej dwie godziny, a przez tyle czasu idzie się przeziębić. Spróbowałem podnieść się na rękach, bez skutku, wsparłem więc głowę o podkład kolejowy i zacząłem rzygać.

Wreszcie pozbierałem się, wsiadłem do pociągu, powiesiłem rower, w ustach czułem smak miedzi, a w głowie miałem tylko jedną myśl — „ile jeszcze”. Pani konduktorka wyjaśniła mi, że gdyby dziś nie było święta (a może weekendu?) to byłoby z jedną przesiadką. A że jest inaczej to najszybciej do Łodzi będzie mi tu i tak: cztery przesiadki.

Wysiadając przy domu pomyślałem, że nigdy więcej i myślałem tak aż do następnego piątku.

Widok na przedział

Jaką tu dać puentę? Nie śpijcie w soboty do południa, bo potem będziecie mieć całą noc do zmarnowania i zaczniecie pisać co Wam się podoba bez pytania o pozwolenie.

  1. Unikajcie Google Maps do jazdy w trasy na rowerze. Wyznaczcie sobie trasy w gpx, odmieniło moje życie

In Terminal Veritas

TL;DR: wszystkie teksty na stronie można czytać na terminalu przy użyciu curla:

curl -s https://fuse.pl/beton/cegla.html | less
curl -s https://fuse.pl/beton/focu.sh.html | less

Jestem dinozaurem (technologii): potężny, kochany przez dzieci i dorosłych, źródło strachu i fascynacji, a także inspiracji. Prawdopodobnie nigdy nie porzucę idei, że klawiatura i terminal są najbardziej efektywną metodą komunikowania myśli i celów komputerowi.

Czasem zadaję sobie pytanie, czy lubię tak żyć dlatego, że potrafię tak żyć, czy też w drugą stronę — nauczyłem się tak żyć dlatego, że lubiłem tak żyć. Wydaje mi się, że fascynacja poprzedza komfort, a jeśli uda się tę fascynację utrzymać, to wszystko równoważy się w jakiś sposób, który trudno wytłumaczyć bez odwoływania się do ontologii.

Ponieważ wszystko nadal mnie bawi, uwielbiam budować różne pierdoły, karykatury prawdziwych technologii na marginesach notatników, bezużyteczne dla większości ludzi.

Dla przykładu: pomiędzy dwiema połowami piłkarskiego meczu odbywa się spektakl obrzydliwości zwany «studiem», w którym różni ludzie mówią o meczu, jak gdybym go przed chwilą nie doświadczył na własne oczy. To wszystko jest wsadzone między dwie kromki reklam. Piętnaście minut żenady. Wystrugałem sobie więc stfufor, który przyjmuje minuty jako parametr. Połączenie catt i at ścisza transmisję, a następnie podbija głośność nazad po zadanym czasie. Kiedy słyszę gwizdek kończący połowę, piszę po prostu stfufor 15.

Mój bojler wyłącza się, kiedy wychodzę z domu. Nie muszę o tym informować jakiegoś chińskiego operatora chmury, żeby łaskawie wydał callback do mojego gniazdka, RPi ma listę urządzeń i na podstawie arpinga stwierdza, że albo mnie nie ma, albo śpię — w każdym razie zmywanie raczej nie jest wysoko na liście priorytetów. Za każdym razem, gdy wracam do domu, słyszę po kilku minutach «klik» przekaźnika i uśmiecham się do siebie jak poskramiacz cherlawych lwów: dumny, choć świadomy braku po temu powodu.

Kilka lat temu przez social media przeleciał projekt tego rodzaju, serwis wyświetlający prognozę pogody na terminalu. Pobawiłem się, było to bardzo ładne, cudo technologicznego kiczu. Nie analizowałem jednak detali — być może jestem nadal pod wpływem traumy, gdy pokazałem jakiś „sprawdzacz pogody” mojemu ówczesnemu administratorowi, na którego serwerze gościłem. Powiedział: „opi, a nie możesz kurwa wyjrzeć za okno?”. Do dziś nie znalazłem odpowiedzi na takie dictum.


Sam jednak pomysł wydał mi się całkiem ciekawy, szczególnie ze względu na pewien dualizm: serwis działał tak samo w przeglądarce i terminalu. Postanowiłem odtworzyć ten efekt, przystosowując stronę, którą czytasz, do podobnego działania.

Pierwsze, co należało ustalić, to czy curl, który domyślnie wyświetla pobrane informacje na stdio, zachowuje wszystkie style, kiedy pobiera plik tekstowy z serwera HTTP. Stworzyłem przykładowy plik z testowymi formatowaniami: pogrubienie, czerwony kolor etc., po czym odpaliłem webfsd, mikro-serwer statycznych treści. Wszystko poszło bez problemu, połowa drogi przebyta.

Teraz trudniejsze pytanie: w jaki sposób odbywa się negocjacja treści? Wczytanie URI w przeglądarce i przez curl pokazuje HTML i tekst. Przeglądarka może negocjować za pomocą nagłówków, w przypadku curl musimy polegać na tym, co jest domyślnie wysyłane do serwera. Poszedłem tropem podglądania user-agent. Dodałem -A "Przeglądarka" do wywołania… i wrócił HTML. Aha, czyli pierwszy strzał od razu celny.

Dopisałem do konfiguracji nginx testową linijkę, która przekierowywałaby do dokumentu stworzonego wcześniej. Jeśli wszystko zadziała, to gdy robię curl https://fuse.pl/beton/cegla.html, powinienem zostać zawrócony, a na ekranie wyświetli się sformatowany plik.

Część logistyczno-infrastrukturalna rozwiązana. Co z treścią? Teksty źródłowe mam w „utylitarnym markdownie”: wszystko, co jest wygodne i praktyczne, jest w Markdownie, a reszta bezczelnie w HTML-u. Blog generuje Pelican wyposażony w system wtyczek. Moim pierwszym pomysłem było dopisanie wtyczki, która wygeneruje odpowiednie pliki .txt podczas normalnego działania. Niestety, dokumentacja dotycząca wtyczek to głównie proces czytania kodu źródłowego zarówno projektu, jak i jakichś losowych gotowców operujących w hipotetycznym sąsiedztwie tego, co chcę osiągnąć.

Po kilku godzinach prób na ślepo postanowiłem, że wrócę do tego później i napiszę minimalistyczny generator „na teraz”. Jedna z tych prowizorek, co ma potencjał przetrwać nas wszystkich.

Jest trzy tygodnie później, wyszło słońce, porzuciłem komputery na rzecz wygodnych butów i plecaka. Już wróciłem, ale zaraz wychodzę znów, spróbuję więc skończyć ten tekst teraz.

Jak postanowiłem, tak zrobiłem. Zgodnie z tradycją pierwsze 90% projektu zrealizowałem w godzinę — czytanie plików tekstowych z dysku i zapisywanie ich nie jest specjalnie trudne. Następne 10% pracy zajęło jakieś 400% czasu. Problemy były wielorakie.

Treści fatalnej jakości

Nie mówimy tu o wartości literackiej, lecz o starych tekstach przeniesionych z Wordpressa. To prawdziwy gar zupy z tagów, bulgoczący i pachnący niezbyt zachęcająco. Jakimś pomysłem było zadeklarowanie listy legalnych tagów, które będę mógł zinterpretować. Ostatecznie uznałem, że te teksty są tak słabe, że ich nieczytelność jest praktycznie przysługą. Problem, mhm, rozwiązany.

Przypisy

Przypisy w blogu generowane są przez wtyczkę, która używa własnego tagu REL w nawiasach kwadratowych jako znacznika przypisu. Bez specjalnej miłości w sercu udałem się do testera wyrażeń regularnych i próbowałem napisać coś, co wychwyci potrzebny fragment. Musicie wiedzieć, że jedyne wyrażenie używane przeze mnie regularnie, to „kurwa”, proces ten zajął mi zatem więcej czasu niż powinien. Po testach postanowiłem, że wstawię przypisy pod paragrafami je zawierającymi, a nie na końcu tekstu. Wyglądało bardzo profesjonalnie, jakbym był blogerem z sponsorowanymi wpisami.

Linki

Ten sam problem co z przypisami, pomnożony przez to, że w moim lenistwie często używam zarówno markera z Markdownu, jak i <a>. Musiałem użyć nie tylko wyrażenia regularnego — bezwstydnie skopiowanego z internetu po godzinie walki — ale także BeautifulSoup celem wyłowienia tagów HTML-a. Zadziałało.

Obrazki

Chciałem zamienić obrazki na kolorowe „piksele” terminala. Używając notacji RGB, mogę bez problemu wykorzystać Pillow do przekonwertowania obrazu na tryb indeksowanej palety i przeskalować go do szerokości 76 znaków — docelowej szerokości tekstu, który chcę generować.

Poszło szybko, ale… efekt pozostawia dużo do życzenia. Poza „heh, fajne”, użyteczność obrazów przeskalowanych do 72px szerokości wydaje się być znikoma. Prawdopodobnie zmienię generator tak, żeby zamiast obrazków wstawiał odnośniki do nich, aby czytelnik mógł kliknąć samodzielnie.

Aktualizacja: obrazki działały okropnie, wszystko zależało od definicji terminala czytającego, więc po namyśle wywaliłem całość.

Markdown, «ANSI»

Nie miałem już zapału w sercu, by siadać do pisania parsera, który wypluwałby odpowiednio „wyeskejpowane” kody dla terminala w miejsce pogrubień, nagłówków i całego tego bajzlu. Znalazłem bibliotekę wyposażoną w komplet narzędzi i kiedy już oswoiłem się z jej konceptami, zagnałem ją do pracy.


Po prawie dwóch miesiącach mogę wreszcie zadeklarować, niczym lider wolnego świata — “MISSION ACCOMPLISHED” — prawie wszystko się udało™. A rzeczy, które się nie udały, najwyraźniej były kiepskimi pomysłami i zostały porzucone nie z powodu braku cierpliwości, tylko w wyniku głębokiej, filozoficznej retrospekcji.

Poprawiała Kaja ❤️

PS. curl -s https://fuse.pl/beton/curl-blog.html | less, duh. ;-)


Od cegły do ziarnka

Na gruzowiskach budynków bywam częściej niż na grobach bliskich. W grobach nie ma bliskich, są oni w mojej głowie. Gruzy budynków są rzeczą samą w sobie, gram do grama — budynkiem, tylko w stanie nieładu. W dzieciństwie łatwiej było znaleźć opuszczony budynek, teraz profesjonalizm, BHP, rzeczy nie rozpadają się samodzielnie, własnym tempem, jak to było w moim dzieciństwie. Są zsuwane w niebyt zębami koparek i spychaczy.

Na obrzeżach miasta nawet puste budynki miały swój cykl w ekosystemie biednej dzielnicy. Wpierw plac zabaw dla dzieci, wbrew protestom matek zdobywany kawałek po kawałku. Potem ktoś stłukł szybę, ktoś wszedł na dach po rynnie, wreszcie ktoś śrubokrętami ojczyma rozkręcił zamek i teren został przejęty. Meble, jeśli jeszcze jakieś zostały, były przeglądane dokładniej niż skrzynie pełne skarbów, każdy metr podłogi zbadany na obecność śladów potencjalnej przygody. Starsze dzieci dopowiadały legendę domu, wyssaną z palca o brudnym paznokciu. Poprzedni właściciele zwykle byli przestępcami, mordercami, ukrywali się przed organami państwa, a los dogonił ich tutaj: powiesili się na tym haku do lampy, skoczyli z tego okna na ten betonowy chodnik, zastrzelono ich na schodach. W tych opowieściach żaden były właściciel nie dożył godnego końca, wszyscy odchodzili w sile wieku i nigdy po cichu.

Później przychodziła zima i dom z powybijanymi oknami nie nęcił już tak jak latem. Na wiosnę rozpoczynał się proces niszczenia. Kto nie chciał zobaczyć, jak wielkie lustro pęka na tysiące części? Szuflady wyrwane z szafek uderzały o ściany tak mocno, że traciły swój kształt i stawały się kupą desek. Ostatnie okna kruszyły się na podłogi.

Latem miejsce przejmowali dorośli: zdejmowali metalowe elementy, darli kable, wystawiali lepiej zachowane framugi. Następnie ktoś przynosił młot i siekierkę. Czerwone cegły, jedna po drugiej, były oddzielane, czyszczone z resztek zaprawy i układane w małe stosiki, które można później sprzedać rolnikowi. Nadawały się nadal do budowy nieforemnych komórek na narzędzia lub niskich chlewików. I tak tydzień po tygodniu, miesiąc po miesiącu budynek bladł i kurczył się, by wreszcie któregoś dnia zostawić po sobie odcisk w ziemi, w którym zbiera się deszczowa woda.

Niedawno odkryłem, że jeden z budynków na trasie moich poobiednich spacerów jest przygotowany do obalenia. Stało się to tak szybko, że kiedy trafiłem po raz kolejny przed jego oblicze, był już tylko szkieletem rozciągniętym na podwórzu. Na moje szczęście miejsce nie było dobrze zabezpieczone i tylko znaki zakazu wstępu łypały na mnie niechętnie.

Dom obrócony w perzynę jest negacją wszystkich wartości zawartych w jego istocie. Okna we wciąż stojących ścianach kiedyś wpuszczały do mieszkań światło słoneczne, teraz przechodzień na ulicy może popatrzeć przez nie na puste niebo. Rzeczy oddzielone od siebie są razem. Pokoje ubrane w ściany chroniły prywatność, teraz są rozpoznawalne przez topologiczne badanie resztek podłogi. Drewniane klepki to pewnie mieszkanie, błękitne płytki pokryte grubą warstwą betonowego kurzu to bez wątpienia łazienka. Niewyraźne granice można odtworzyć, studiując inne geograficzne elementy: resztki niewyniesionej komody, ścięte węzły wodociągowe, liczba okien.

Wytrawny antropolog rozpadu znajdzie też komin. Na nosa. Umorusane sadzą cegły śmierdzą zimną spalenizną. Dekady gryzącego dymu nie ulecą w niepamięć w kilka miesięcy.

Po wschodniej stronie budynku kręci się chłopak. Zerka na mnie podejrzliwie. Ma w ręku siekierę, a na stosie przed nim leży wyzwolone drewno, przycięte na długość wygodną do transportu. Jest bardzo zimny, styczniowy dzień. Nie mogę po prostu podejść i powiedzieć: „nie martw się, jestem tu z tego samego powodu, co Ty. Chcę zabrać z tego budynku ostatnie wartościowe rzeczy”. Odsuwam się więc na bok i udaję, że go nie widzę. Niestety, spłoszony, pakuje się i odchodzi w kierunku niedalekiej kamienicy. Zostaję sam, odwiedzam wszystkie cztery strony budynku i wreszcie zadowolony wracam do domu.

Zburzony budynek
Za kilka miesięcy stanie tu nowoczesny budynek, bez kominów i drewnianych podłóg. Wbity pomiędzy pozostałe kamienice, będzie im przypominał o ich nieuniknionym losie.

Nad tekstem pochylała się Kaja/Nerdy Nocą


focu.sh

Mody przychodzą i odchodzą. To dowód na to, że moda jest rzeczą fatalną. Nic dobrego nie psuje się kompletnie w miesiące, aż do momentu w którym trzeba całość wyrzucić. W świecie edytorów tekstowych dla pisarzy najnowsze mody sugerują, że jeśli nie możesz użyć maszyny do pisania, powinieneś przynajmniej naśladować jej zachowania: pozbyć się klawisza delete co uniemożliwi poprawianie tekstu na bieżąco, to samo z podróżowaniem pomiędzy paragrafami przy użyciu klawiszy kursora. Najlepiej też nie pokazywać tekstu poza obecnie pisanym kawałkiem, zaciemniając go lub nie wyświetlając go w ogóle.

Wszystko to ma jeden cel: nie kraść uwagi pisarza poprzednimi bohomazami i skierować go na jedną, słuszną drogę: drogę wiodącą do przodu.1

Będąc autorem amatorskim, o suchym pysku, pustej stronicy i drżących rękach, pomyślałem, że dam sobie szansę dołączyć do ludzi aktywnych pisarsko. Pobrałem taki i siaki edytor (słowa kluczowe “minimalism”, “markdown”, “focus”), większość nie ma wersji na Linuksa, a te, wydane dzięki technologii przeglądarka-vm2 zwykle nie przeżywają zetknięcia ze skąpymi w cykle procesora komputerami na których pracuję.

Przetestowałem też aplikacje mobilne. Tu jakościowo było znacznie lepiej, powstał jednak problem poboczny: część z tych edytorów domaga się comiesięcznej opłaty subskrypcyjnej. Jestem moralnie przeciwny takiej formie finansowania oprogramowania, co raczej nie powinno nikogo dziwić.

Zrobiłem więc następną dobrą rzecz: napisałem najbardziej hipsterski edytor dla prawdziwych artisanów, focu.sh3 — kilka linii w Bashu. Minimalistyczny edytor minimalistycznym nakładem sił.

focu.sh

Edytor składa się zasadniczo z jednego elementu: czytaniu stdin przy użyciu read i przekierowaniu (przez dopisanie) pobranej wartości do jakiegoś pliku wybranego przez użytkownika.

Wersja tylko fakty wyglądałaby tak:

while :
do
    read line
    echo $line >> "$1"
done

Już minimalistyczne, ale jeszcze nie hipsterskie. Musimy usunąć z ekranu wpisaną wcześniej treść i pokonać wewnętrznego Narcyza, zakochanego w już popełnionej prozie. Moglibyśmy wywołać clear, ale to zbyt agresywne i nieestetyczne. Musi być symetria jak u Kubrika i Wesa.

clear_and_align() {
    lines=`tput lines`
    half=`echo $lines/2-1 | bc`
    tput clear
    for i in $(seq 1 $half);
    do
        echo
    done
}

Dodałem funkcję clear_and_align() powodującą, że kursor jest zaparkowany na środku ekranu. Białe litery pośród morza ciemności, pięknie. Aby uzyskać ten efekt odczytuję ilość linii obecnego terminala używając tput, tnę je na pół używając kalkulatora bc, czyszczę ekran, a następnie „spuszczam” kursor odpowiednią głębokość kręcąc się po sekwencji 1…ekran/2. Całość wystarczy dodać do naszej głównej pętli while…do…done.

W pisaniu najważniejsza jest motywacja. Dobrze byłoby wyświetlić wiadomość pożegnalną wraz z ilością linii dodanych podczas sesji.

trap goodbye SIGINT
goodbye() {
    clear_and_align
    echo "W R I T I N G   S E S S I O N   T E R M I N A T E D."
    echo
    echo "$lines_added   L I N E S   A D D E D"
    exit
}

Dzięki użyciu trap możemy załapać sygnał SIGINT (wciśnięcie ^c) i wskazać funkcję do wywołania bezpośrednio po jego nadejściu. W funkcji wyświetlimy zmienną globalną lines_added, wartość której podbijamy oczywiście w głównej pętli. I proszę, po strachu.

I chciałbym móc Wam skłamać, że to właśnie ten cudowny edytor jest powodem mojej obecnej aktywności. Niestety, użyłem go raz i nie sprawiło mi to wielkiej przyjemności. Odkąd nauczyłem się wychodzić z Vima4 robię w nim wszystko. Nie napisałem może nowego edytora, ale za to mamy praktyczny przykład użycia „nieskończonego” while, seq, tput i trap.

Edytor w działaniu.

Wersja „finalna” w repozytorium.

Runda dodatkowa

Wymyśliłem, że mógłbym przypudrować nieco nosa funkcji goodbye. Moją wizję nazwałem „poprzeczny Matriks”: weźmiemy ciąg znaków i będziemy go wypisywali literka po literce używając pary kolorów (czy też własności: jak jasność i pogrubienie) wybieranych losowo zasymulujemy wyłanianie się napisu z mroku do maksymalnej jasności i wspak.

Byłem pewny i spokojny, a w mojej głowie odgrywało się jak to wszystko będzie wyglądać. Po godzinie z kawałkiem popatrzyłem na efekt i otrzepując ręce powiedziałem pod nosem „Jebać. I tak nie chciałem tego robić.”

END OF TRASMISSION

  1. próbując edytować to w kawiarni naszła mnie nagle przerażająca myśl. To wszystko jest log typu append-only. Czy jestem pierwszym człowiekiem, który wymyślił blokczejn-teknolodżi z zastosowaniem? TołstojPiniondż niedługo na rynku!
  2. Electron i jego bękarty
  3. Gdyby domena nie kosztowała $80 to bym zrobił sobie landingpage w bootstrapie
  4. alt-a tworzyło nową sesję na terminalu tekstowym, logowałem się i wydawałem polecenie kill

Się, nam

Czy jest bardziej polskie stwierdzenie niż „się załatwi”? Jest ono reprezentacją ducha narodu, jego najcenniejszych wartości: pomysłowości, zdolności organizacyjnych, słusznego sprzeciwu ikonoklasty i niedopowiedzeń godnych listów między kochankami.

Taki taniec godowy, nierozpoznawalny dla innych gatunków, wyewoluowany przez wieki, gdy tylko biedy było pod dostatkiem.

Kiedy Polak mówi Polakowi, że „się załatwi” dochodzi do niewerbalnego porozumienia, które wypowiedziane słowami, a nie daj bóg, zapisane na papierze, mogą być użyte jako źródło paszkwili. Strona, która mówi, że „się załatwi”, rozgrzesza stronę proszącą. Nikt nie jest pewien jak ta rzecz się stanie. Czy ktoś na tym ucierpi, czy zostaną nagięte przepisy, złamane prawa. Osoba w potrzebie, niemal jak w modlitwie, wypowiada swoje prośby do istniejącej gdzieś, niepoznanej, siły sprawczej. Odbiorca tej modlitwy też odżegluje się od bycia instrumentem stworzenia. Nigdy „ja załatwię”, zawsze „się załatwi”. Pasywnie, anonimowo, przed oblicze niewidzialnych sił natury.

Niesłychana jest również egalitarystyczna potęga tego porozumienia. Lekarz może powiedzieć do pacjenta, że „się załatwi”, ale też szatniarz do dyrektora. Choć moce sprawcze i rezultaty będą różnego kalibru, do paktu wszyscy podchodzą patrząc sobie w oczy, jak równy z równym, nasz własny wkład w urzeczywistnianie utopijnych wizji mutualizmu Kropotkina i Proudhona.

Dziś obrońcy statusu quo starają się wyrugować ten piękny zwyczaj, zaszczepić nam moralną pewność, że „się-zalatwizm” jest przywilejem przyznawanym wraz z wpisem w KRS. Apeluję abyśmy odrzucili te postulaty i nie dali się ograbić kulturowo, a jeśli już damy się ograbić kulturowo, to przynajmniej nie dajmy się ograbić materialnie.


10 PRINT

Dyskusja na temat „czym jest sztuka, czym jest piękno” jest z nami tak długo jak długo istnieje klasa intelektualno-próżniacza, która mogła zadawać sobie takie pytania i szukać na nie odpowiedzi. Będąc bękartem tej klasy, odziedziczyłem tylko pół genotypu, jestem próżniakiem, dlatego na potrzeby dzisiejszego dnia zdefiniuję sztukę i piękno jako „to, co da się wyrazić jedną linijką w najgorszym1 BASIC-u”.

Najsłynniejszym przykładem „generowanej sztuki” jest 10 PRINT, jedna linijka w BASIC-u na C64, która generuje pseudolosowy labirynty. Jest możliwa tylko dzięki szczęśliwym zbiegom okoliczności. Prześledźmy ją krok po kroku.

10 PRINT CHR$(205.5 + RND(0)); : GOTO 10

PRINT nie trzeba nikomu tłumaczyć. Natomiast warto rozważyć dwa znaki interpunkcyjne. : pozwala na separacje poleceń, ; jest modyfikatorem dla PRINT i powoduje, że następne znaki nie będą wypisywane w nowej linii. CHR$() przyjmuje indeks i wypisuje znak znajdujący się pod nim w tabeli ASCII C642. Wartość 205 odpowiada /. RND() zwraca pseudolosową wartość w zakresie 0…1. GOTO zamyka pętle.

CHR$() jako parametr przyjmuje liczbę całkowitą. Jeśli podać mu liczbę zmiennoprzecinkową bezceremonialnie odrzuca wszystko po kropce bez zaokrąglania. To dla nas dobry zbieg okoliczności. Teraz rozważmy operację dodawania: 205.5 + [0…1] daje nam liczby z zbioru 205.5…206.5. Jak już ustaliliśmy CHR$() jest kompletnie nieczułe i widzi tylko dwie wartości. 205, które w tablicy ASCII odpowiada / i 206, kolejny szczęśliwy zbieg okoliczności, odpowiada \.

Ostatni pozytywny zbieg okoliczności? Piksele na 8-bitowych maszynach to materiał premium, twórcy komputera nie mieli luksusu martwienia się jak typografia „oddycha” na ekranie. Odstępy pomiędzy liniami nie są tego warte.

10 PRINT: wideo zrzucone z emulatora C64 demonstrujące efekt

I tyle: stawiamy znak \ lub / i pozwalamy naszemu mózgowi poukładać ten szum w kształty. Magiczne sztuczki wydają się głupie, gdy je wyjaśnić.

Dla zabawy „przeportowałem” ten kod na odpowiednik w Pythonie, niestety, Linuksowy terminal jest już bogaty w piksele i nie da się tak łatwo uzyskać jednolitych linii. Po ustawieniu fontu z C64 efekt był już całkiem zadowalający.

from random import choice
while True: print(choice(['/', '\\']), end='')

Szybka opowiastka o: random.choice zwraca losowy element z listy (tu dwuelementowa lista z \ i /, oczywiście), end='' do print() powoduje to samo, co średnik w BASIC-u, operacja nie kończy się nową linią.

10 PRINT: na Linuksie

Miałem w tym tygodniu opublikować inny tekst, ale chyba jestem kolejną ofiarą zarazy™ i nie mogę myśleć zbyt jasno. Widziałem wczoraj wideo w którym Robin optymalizuje 10 PRINT w asemblerze i pomyślałem, że to temat łatwy i przyjemny, a może ktoś z subskrybentów nie wie o fenomenie.

Kilka lat temu MIT wypuściło książkę o 10 PRINT, ma ona 324 strony, co jest pewną formą meta-sztuki nieosiągalnej dla zwykłych śmiertelników. Skłamałbym gdybym powiedział, że ją przeczytałem. Dość uważnie przekartkowałem ją spacją.

  1. TI/99 walczy zaciekle o koronę
  2. PETSCII, nie będę jednak dzielił włosa na czworo

asdf-vm

Wszyscy lubią dobry sequel, choć szansa na niego jest znikoma. W zeszłym tygodniu pisałem o wygodnej metodzie instalacji programów napisanych w Pythonie, a dziś przedstawię Wam podobne rozwiązanie: z tą różnicą, że nie „programów w Pythonie” tylko „wszystkiego w sumie z naciskiem na języki programowania i narzędzia pomocnicze”. asdf-vm

W „Boskiej Komedii” Alighieri opisuje 9 kręgów piekła do którego może trafić grzeszna dusza. Wbrew religijnej ikonografii ostatni krąg nie ma gotującej się siarki i diabołów uzbrojonych w ostre narzędzia rolnicze tylko jezioro skute na wieki lodem, najbardziej oddalone od ciepła bożej miłości. Gdybym miał talent (no, więcej talentu) napisałbym pastisz w którym na końcu byłby asdf instalujący Pythona, instalujący pipx, instalujący docker-compose, w kontenerze. Dziewięć kręgów abstrakcji, prawdziwe piekło.

Żarty na bok, ale w zasięgu ręki.

W przeciwieństwie do pipx, który używa standardowych mechanizmów Pythona, asdf to bardzo lekka specyfikacja do skryptów instalacyjno-kompilacyjnych zarządzana przez super-polecenie.

Podczas pisania tego tekstu dostępne są 4201 specyfikacje, które w nomenklaturze asdf nazywamy pluginami. Większość z nich dostarczona jest przez osoby zewnętrzne, więc standardowe ostrzeżenie o „odpalasz czyjeś skrypty z Internetu” obowiązuje każdego dnia i każdej nocy.

Co do jakości samych wtyczek: jest różnie. Niektóre budują oprogramowanie wprost ze źródeł, inne znów pobierają skompilowane binarki. Podobnie jak w świecie kontenerów istnieje założenie, że końcowy odbiorca posiada komputer z x64. W chwili obecnej takowego nie posiadam, niektóre instalatory popełniają więc naiwne błędy: ściągają binarkę na x64, kładą ją do wirtualnego katalogu, zacierają ręce i mówią — „gotowe”, czy trochę lepiej, wywracają się od razu na kolana mówiąc „nie ma takiej architektury — armhf”. Innymi słowy, jeśli upstream nie rozwiązał problemów wieloplatformowości są niewielkie szanse, że autor wtyczki do asdf poświęcił czas na testowanie instalacji na nie-Intelach.

Jedna funkcja samego asdf jest mi szczególnie miła. Poza możliwością instalowania obok siebie kilku wersji tego samego programu istnieje też możliwość zadeklarowania jaka wersja jest globalna (widziana przez powłokę normalnie) a jaka jest lokalna (na przykład w katalogu projektu).

Uratowało to moją duszę przed wizytą w drugim kręgu, gdy odziedziczyłem po frontendowcach projekt, który potrafił się tylko zbudować jedną konkretną wersją nodejs. Dlaczego? Nikt nie wiedział, a ostatnia osoba, która mogła coś na to poradzić postanowiła sprzedawać łódki dłubane w korze na rogach jasno-oświetlonych domów handlowych.

Wystarczy przenieść się do katalogu projektu i wydać polecenie asdf local nodejs 12.18.3 (oczywiście po wcześniejszym zainstalowaniu) i za każdym razem gdy odwiedzimy nasz projekt wersja zmienia się magicznie pod naszymi stopami. Wersję ustawia zawartość pliku .tool-version, możemy go wciągnąć do repozytorium, co pomaga ludziom tak zapominalskim jak ja.

Instalacja

Polecaną metodą jest sklonowanie repozytorium do katalogu domowego. Kilka pakietów, które próbowałem na Arch instalowały do /opt czy też /usr/local, nie pamiętam, w każdym razie kłóciło się nieco z moją ideą żeby wszystko żyło w katalogu domowym, dlatego usunąłem je i użyłem ręcznej metody.

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.8.1

Do skryptu uruchomieniowego powłoki należy dodać wywołanie ./$HOME/.asdf/asdf.sh rozpędzające machinerię. Jeśli używacie oh-my-zsh można dodać do jego konfiguracji plugins=(asdf git […]).

Używanie

Wpierw dobrze się rozejrzeć, co też dają w tej knajpie. Listę wszystkich dostępnych pluginów otrzymamy po wywołaniu:

asdf plugin list all

Jeśli nasza powłoka nie wspiera dopełnienia należy sprawdzić jakie wersje konkretnego pluginu możemy zainstalować:

asdf list all nodejs2

Obecnie doszedł uniwersalny tag latest aby ułatwić start. Niektóre pluginy zawierają też inne nazwy własne takie jak lts czy stable. Zainteresowani muszą zbadać sprawę na własną rękę.

Musimy dodać plugin do listy aktywnych:

asdf plugin add nodejs

By ostatecznie zainstalować rzecz samą w sobie. Dwie rzeczy na potrzeby demonstracji:

asdf install nodejs 12.18.3

asdf install nodejs latest

Kiedy (lub jeśli, build-essential + *-dev* będą nieodzowne) wybrany program się już zainstaluje możemy wybrać wersję do użycia. Domyślnie, bezpośrednio po instalacji, programy nie są aktywne.

asdf global nodejs 12.18.3 — wybierze nam domyślną wersję zainstalowanej aplikacji

asdf local nodejs latest — zadeklaruje wersję aplikacji do użycia w sytuacji, gdy znajdujemy się w danym katalogu.

W praniu

Poniższe wideo zawiera bardzo hipotetyczną sytuację.

Mam w Vimie wsparcie do fzf i chcę zainstalować program by móc z niej korzystać. Z jakiegoś powodu, być może na potrzeby demonstracji, ubzdurałem sobie, że chcę je zainstalować w wersji 0.22.0. Ta wersja ma gotową binarną dystrybucję, więc wszystko kończy się na pobieraniu do odpowiedniego katalogu.

Zadeklarowałem wersję 0.22.0 jako globalną i odpaliłem Vima. O nie, szelma, zostałem zdradzony, wtyczka do Vima potrzebuje nowszej wersji fzf. A ta nie ma binarnej dystrybucji. Na szczęście 0.29.0 buduje się używając go, nomen omen, zainstalowanego via asdf, i mogę zadeklarować tę wersję jako lokalną.

Animacja demonstrująca poprzedni paragraf tekstu

Przyznam, że znalezienie czegoś do demonstracji zajęło mi więcej czasu niż pisanie samego tekstu. Szrotowany powindowsowy „tablet” z mizernym Atomem nie jest idealną platformą do kompilowania LibreOffice i nagrywania z tego wideo.

  1. nice
  2. 622 wersje. Dżizas kurwa mać ja pierdolę,,,

pipx — bezbolesna instalacja programów w Pythonie

Moje komputerowe życie umila zaskakująca liczba programów napisanych w Pythonie. Na przykład wspominany wcześniej catt, bardzo wygodne i praktyczne klienty do baz danych jak pgcli czy mycli. Niezastąpiony youtube-dl (a właściwie jego fork yt-dlp) pozwalający archwizować media, goobook integrującym książkę kontaktową Googla z muttem. Mógłbym tak wymieniać długo.

Programy w Pythonie pisze się niezwykle przyjemnie, prawdziwe schody zaczynają się w momencie dystrybucji efektu naszej pracy. Część chce się instalować przez curl | sh, inne znów posiadają własne instalery i metody aktualizacji, są też oderwane od rzeczywistości pakiety .deb i .rpm niesiące ze sobą obietnice katastrofalnego zakłopotania systemu.

Jeśli deweloperzy dystrybucji (lub ludzie tworzący „hobbistyczne” repozyoria przylgnięte do oficjalnych (AUR czy PPA)) nie przygotowali gotowego pakietu końcowy użytkownik jest pozostawiony samemu sobie.

Niewprawiony użytkownik może sobie szybko skomplikować życie instalując rzeczy bezpośrednio w trzewia systemu. Zaawansowany użytkownik może się szybko znudzić żonglowaniem pół-rozwiązaniami wymyślonymi na szybko, które trochę działają, trochę nie.1

Któregoś dnia „wdepnąłem” w pipx, program tworzący wirtualne środowiska per program jednocześnie zajmując się podlinkowaniem wykonywalnego skryptu. Dzięki temu możemy zainstalować wiele pożytecznych aplikacji bezpośrednio z PyPI bez większego bólu głowy, uzyskać dostęp do aktualizacji i możliwości usunięcia programu z systemu bez pozostawiania tradycyjnego kurzu i gruzu.

Instalacja

Użytkownicy bardziej konserwatywnych dystrybucji, więc i ja, nie mogą oczekiwać, że pipx będzie znajdował się w repozytorium. Znaczy to, że program przyjdzie nam zainstalować bezpośrednio z PyPI. Trzeba przyznać, że stajemy wtedy przed ciekawym problemem typu „jajko czy kura”. Dylemat ten pozostawię do rozważenia w Waszych sercach, osobiście proponuję pip3 install --user pipx i sprawdzenie, czy ~/.local/bin znajduje się w ścieżce (zmienna środowiskowa PATH).

Po instalacji możemy przetestować, czy wszystko poszło gładko wpisując pipx --version. Jeśli otrzymaliśmy numer wersji w odpowiedzi jesteśmy gotowi.

Używanie

pipx w akcji

Odpalenie pipx bez parametrów wyświetli nam listę dostępnych opcji. Część z nich tłumaczy się sama przez się, inne wymagają słowa objaśnienie.

Instalacja pakietu z PyPI:

pipx install yt-dlp

Instalacja pakietu bezpośrednio z repozytorium:

pipx install git+https://git.sr.ht/~bronikowski/pyswatch2

Usunięcie zainstalowanego pakietu:

pipx uninstall yt-dlp

Aktualizacja pakiet(ów):

pipx upgrade-all lub pipx upgrade yt-dlp dla ludzi o sercach miękkich wobec procesorów.

Uzyskanie listy już zainstalowanych pakietów:

pipx list

Przytrafiają się sytuacje, gdy zainstalowany pakiet nie chce się uruchomić. Jeśli problem spowodowany jest brakiem zależności lub jej niewłaściwą wersją, możemy naprawić taki problem „wstrzykując” zależność do wirtualnego środowiska zarządzanego przez pipx.

pipx inject yt-dlp <jakaś_biblioteka> lub użyć bezpośrednio pip w tymże środowisku pipx runpip yt-dpl <polecenie pip>.

Do Waszej dyspozycji pozostają też trzy zmienne środowiskowego:

PIPX_HOME — katalog w którym tworzone są wirtualne środowiska (domyślnie: ~/local/pipx/

PIPX_BIN_DIR – katalog w którym zostaną umieszczone symlinki do wykonywalnych poleceń. Oczywiście najlepiej taki, który znajduje się w ścieżce uruchomieniowej. Domyślnie ~/.local/bin.

PIPX_DEFAULT_PYTHON — jeśli chcecie używać innej wersji Pythona

Na zakończenie przypomnę tylko, że pipx nie rozwiązuje magicznie problemu pakietów, które wymagają dostępu do kompilatora i nagłówków — tu nadal musimy zapewnić wszystko przy użyciu pakietów -dev*.

  1. Staram się porzucić żywot człowieka używajcego Debian/oldstable żyjącego z 25GiB-towego katalog ~/src
  2. zob. „Umówiłem się z nią na dziewiątą

W 80 minut dookoła Łodzi

Cóż to za kropka na horyzoncie? Nad Starym Widzewem wisi sobie balon. Nie pamiętam kiedy widziałem taką bańkę zawieszoną na moim niebie, zmieniam więc trasę mając nadzieję, że przetnę jego ścieżkę.

Wpakowałem się niestety w jeden z trzydziestu czterech, odbywających się równocześnie, remontów. Postanowiłem trzymać go na wschodzie i jechać przed siebie.

Niebo jest nieoczekiwanie wielkie. Kilka kilometrów później zaczyna mi się kończyć miasto, ale nie wygląda jakbym zbliżał się do trasy balonu.

Widzę więcej balonów. To musi być jakaś zorganizowana akcja.

Przejazd kolejowy i czekamy aż przejedzie samotna ciuchcia PKP Cargo.

Balon, który śledziłem, znika za blokami. Znaczy, że usiadł, bo to zaledwie czteropiętrowe budynki. Skręcam pomiędzy nimi i zostaję nagrodzony. Na boisku do koszykówki przycupnął sobie balon z nieco zirytowanym operatorem.

Prosi o pomoc. Łapię za gondolę z dwoma innymi chłopami i niesiemy go w kierunku, który nam wskazuje. Balon jest zadziwiająco ciężki nawet z non-stop pracującym palnikiem, który pluje ogniem w jego brzuch.

Od środka jest całkiem pusto. Nawet tanich mebli z Ikei nie ma.


Patrzysz mi się na ręce. Ręce mi się trzęsą.

Wczoraj widziałem nowelkę wspomnień.1 Co zaczęło się jako wieczór ze sprawdzaniem stanu prywatnych archiwów, skończyło się na przeglądaniu starych zdjęć, a następnie znalezieniu konkretnego wycinka mojego życia i odbijania się po nim z lewa na prawo.

Szukanie wspomnień, przywoływanie kontekstu, ludzi, tematów rozmów prowadzonych do świtu, odtwarzanie dźwięków i smaków.

Refleksje wczepiły się tak bardzo w moją świadomość, że nawet po przebudzeniu się na drugi dzień nie mogłem się otrząsnąć z kilku emocji. Jak odgrzane resztki dawnej fiesty, nie wyglądały atrakcyjnie, ale smakowały wspaniale. Wyciągnąłem notatnik, pióro i postanowiłem, że poukładam sobie rzeczy na papierze. Nie ma lepszego piorunochronu na burzę myśli niż notatnik.

Napisałem może stronę, gdy telefon zrobił ping. Jestem podejrzliwy, bo mój telefon nie robi ping w normalnych warunkach, większość aplikacji jest poproszona o zamknięcie mordy. Patrzę w źródło powiadomienia. Google Photos ma dla mnie zajmujący kolaż! Tylko dla mnie, samo zrobiło!

Mając najgorsze przeczucie klikam.

Jak niekompletny szpieg, przekonany o swoich super-mocach i rentgenowskim wzroku, Google zauważyło, że oglądałem konkretny wycinek czasu i przygotowało mi prezentacje z tego właśnie.

A ponieważ nie posiada kontekstu, moich wspomnień, nie wie, że część tej wycieczki w przeszłość uzupełniałem zdjęciami z dysku to, co wybrało było kompletną bzdurą: kolekcja kilkunastu zdjęć kościołów.

Intelektualnie wiem i rozumiem, że jestem śledzony przez dziesiątki takich niekompetentnych szpiegów, którzy robią to dla „mojego dobra”. Udaje mi się jednak o tym zapomnieć. Co jakiś czas Sztuczna Indolencja, napędzana miliardami dolarów, wysyła swojego agenta by mi przypomnieć, że mogę kupić książkę, którą już kupiłem lub zobaczyć zdjęcia, które już widziałem.

Jest coś frustrującego w tym, że ktoś może przerwać mi osobistą kontemplację, zdemaskować się naruszając mój mir domowy i pełnym głosem, z wypiętą piersią oświadczyć: a wiesz, że ja umiem SELECT […] BETWEEN?.

No i co z tego, kurwa?


  1. Ze wzrou „obraz wart tysiąca słów” 


Marginalia (V)

Piotr szedł nasypem przy brzegu rzeki. Na jednym z zakrętów zauważył na kamienistej plaży staruszka, który trzymał się pod boki i krytycznie przyglądał się rzece. Piotr nie odszedł jeszcze wystarczająco daleko, by stracić go z wzroku, gdy ten wykonał kilka energicznych skłonów po czym z impetem wskoczył obunóż do wody. Ta nie ustała się jeszcze po pierwszym ataku, a dziadek już był na brzegu, już obrócił się na pięcie i znów wbił się w impetem w wodę. Tym razem stał tak prze chwilę, gładząc łysą głowę by wreszcie potrząsnąć nią z zagniewaniem.

Zaintrygowany, Piotr postanowił poczekać i zobaczyć czy teatr, który właśnie ogląda ma jakiś epilog. Podszedł bliżej stromej skarpy i przystanął przy rosnącym tam krzaku. Gdy spojrzał na plażę, dziadka już na niej nie było. Jego łysa głowa pojawiła się na skraju skarpy, a za nią podążyła reszta ciała. Piotr podskoczył, przestraszony i zmieszany, przyłapany na gorącym uczynku.

— Ależ mnie pan przestraszył! — zawołał

Tu znów podskoczył dziadek, najwidoczniej pogrążony w myślach nie zauważył swojej ukrytej widowni.

— A pan mnie. Dzień dobry i przepraszam.

— Dzień dobry — odpowiedział Piotr, ale już do dziadkowych pleców, bo ten już przeprowadzał inspekcję krzaka.

Brał do ręki gałąź po gałęzi i oceniał je. Wreszcie podjął decyzję i ułamał jedną. Mierząc ją jeszcze w dłoni począł schodzić w kierunku plaży.

Piotr, już zdemaskowany, przyglądał się otwarcie drugiemu aktowi.

Patyk zatoczył koło w powietrzu i poleciał w kierunku wody. Po przepłynięciu kawałka został wyłowiony przez starca, który wydawał się być zadowolony z eksperymentu. Patrząc znów na płynącą wodę wzrokiem pełnym determinacji, dziadek wskoczył do wody trzymając patyk w prawej ręce i niemal natychmiast wypuścił go z ręki, pozwalając mu popłynąć ze strumieniem.

Sam wyskoczył z wody na piasek i podjął pościg za odpływającą gałęzią, przymierzając się całą drogę do skoku.

Skoczył wreszcie rozbryzgując wodę dookoła. Stał tak chwilę odprowadzając odpływający patyk wzrokiem. Potarł kark i z wyraźnym znużeniem wrócił na miejsce startowe. Położył się na brudnym piasku, zamknął oczy i złożył ręce na brzuchu.

— Przepraszam — zawołał Piotr — ale muszę pana zapytać, co pan do cholery robi? To jakieś ćwiczenia sportowe? Sztuka?

Starzec przewrócił się na bok aby mógł widzieć swojego rozmówcę i powiedział

— Znacie panie Heraklita?

Piotr potrząsnął głową przecząco.

— To taki filozof, myślał dużo o świecie, o zmianach. Jego najpopularniejsza sentencja to „Niepodobna wstąpić dwukrotnie do tej samej rzeki.” — próbuję obalić tę frazę.

— Dlaczego? — zapytał Piotr

— Bo, drogi panie, mam już dosyć zmian. Ułamże mi pan inny patyk, skoro już jesteś tam na górze.


Marginalia (IV)

Słońce wpadające przez okno zostawiało na biurku pasy światła, jak linie demarkacyjne nieistniejących granic. Republika lampy, gubernia książek będąca w nieustającej wojnie z wielkim królestwem przyborów do pisania. Rzeczy migrowały wraz z pracą, a granice migrowały wraz z posuwającym się dniem, gdy słońce zaczynało chować się za gzymsem budynku na przeciwko.

W wyzwolonym terytorium stał kubek. Był to zwykły, aluminiowy kubek, bez historii, bez znaczenia, gdyż nie spełniał swojej jedynej funkcji jaką jest okiełznanie ciepłego napoju.

Miał tylko fusy.

Iwanowicz starał się go nie zauważać. Był jak wyrzut sumienia. W głębi duszy wiedział, że musi go umyć ale rzeczy proste wydawały się tak skomplikowane. Dużo łatwiej jest robić rzeczy trudne.

Rzeczy trudne pełne są zakamarków w których można ukryć znużenie. Rzeczy trudne są ruchome, mienią się kalejdoskopem problemów od których kręci się w głowie. Jeśli ktoś baruje się z rzeczą trudną, to wszyscy ze zrozumieniem akceptują że rozwiązanie może nie być doskonałe. Jeśli wyciosasz bale, postawisz z nich dom, a krzywo osadzisz drzwi to ludzie powiedzą: „To piękny dom, choć czasem przeciąg”.

Jeśli nie domyjesz kubka, nikt ci nic nie powie. Bo wszyscy, słusznie, będą tobą gardzić.

Więc Iwanowicz pisał, bo pisanie jest trudniejsze, więc prostsze. Poza tym wątpił, czy naprawdę chciał się napić herbaty. Może to tylko jedna z tych żądzy, która przyplątuje się około południa i zadamawia się w głowie. Być może odrzucenie kubka jako drogi do herbaty jest czynem godnym i on, przez to niemycie staje się człowiekiem moralnym, człowiekiem wyboru!

Czy nie zostaliśmy, myśli Iwanowicz, stworzeni do rzeczy większych. Czyż nie trzeba demonom mówić stop, walczyć z pokusą, nie dać kierować swoje życia zachciankami.

Herbata była zielona i smakowała dobrze.


Marginalia (III)

Z mównicy płynął głos.

„Obywatele!” — zadudnił.

„Obywatele.” — powtórzył spokojniej, gdy zebrany tłum ucichł.

„Rozumiemy jak ważny jest dla Was chleb. Dlatego, jednomyślnie podjęliśmy decyzję o powołaniu komitetu do spraw organizacji parady chlebów. Planujemy szeroką reprezentację chlebów z całego świata: meksykański Conchas, japoński Pan, francuską Bagietkę i tak dalej. Uniwersytety otrzymają specjalne dotacje na badania naukowe dotyczące znaczenia chleba w kulturze. Do tego dofinansujemy sztuki teatralne ze szczególnym naciskiem na teatr muzyczny w oczekiwaniu na chwytliwą produkcję, która pokaże aspiracyjne znaczenie chleba. Lokalne samorządy otrzymają pozwolenie na zmianę jednej ulicy, która nazwana jest imieniem króla na Piekarzy.”

Wtrącił się głos z widowni — „A czy będzie chleb dla nas, do jedzenia?”

— „W tej chwili” — odpowiedział człowiek stojący za pulpitem — „planujemy tylko igrzyska.”


Marginalia (II)

Ty leżysz tu, ja leżę tam. Spotykamy się wzrokiem. Twoje oczy są mokre od łez, a moje skupione. Leżymy tak obok siebie, ja wyciągam w Twoją stronę rękę. Twoja pozostaje przy boku. Próbuję wymówić słowa, ale więzną mi w gardle. Na Twojej twarzy maluje się ból. Tu, wyciągnięci na trawie, przeżywamy naszą wspólną tragedię, prywatnie.

Nad nami wisi księżyc w nowiu, blady i uwikłany w chmury, nie świeci nam na twarze. Stłuczona lampa, jakby w komitywie, też zieje mrokiem. Koło roweru powoli przestaje się kręcić. Aleśmy się wyjebali.

(Dla zdziwionych nagłą aktywnością: w ramach zamykania roku przepisuję sobie tekściki i opowiadanka ze stron notatników. Cisza powróci niedługo.)


Marginalia (I)

Zawsze przylatują, gdy próbuję się skupić. Siedzę przy biurku, przywołuję duchy produktywności w nadziei, że posiądą moje ciało i zaczną coś tworzyć. Moje modlitwy przerywa ruch za oknem. Widzę przemykające cienie na zasłonce, słyszę jak atakują mój parapet.

Gdy pada, przysiadają na dłużej, a wypłoszone robią tylko koło nad podwórkiem i lądują ponownie, sprawdzając jak daleko się posunę. Kiedyś wypadłem na nie z parasolem, po czym zacząłem go gwałtownie otwierać i zamykać wołając „Sio! Sio!”. To było moje pierwsze druzgoczące zwycięstwo w tej nierównej walce. Parasolkę zostawiłem chyba w tramwaju, więc dziś nie mam się czym bronić.

Gdyby tylko przykościelne staruszki ich nie dokarmiały, może rozwinęłyby jakiś instynkt łowczy i poszukały szczęścia dalej od parapetów miast, zwłaszcza od mojego.

Znów słyszę lekkie stukanie w szybę, uchylam firankę, następnie okno i krzyczę „Wypierdalaj!” — anioł podrywa się do lotu z cichym „Alleluja” na ustach. Niedługo wróci, a może nawet cała grupa i jeszcze archanioł. Te są najgorsze, bo mają trąby.

Patrzę jak znika za dachami miast, zamykam okno, wracam do biurka i myślę, że znów niczego nie zrobiłem i nie wiem, czy znajdę temat do pisania. Tymczasem anioły obsiadły już linie elektryczne i nucąc „Maryjo, królowo Polski…” czekają na odpowiedni moment do powrotu.


Raspberry z papierka

Jeśli definicją szaleństwa jest „robieni tego samego, spodziewanie się innego rezultatu” to należy powiedzieć, że programowanie i administracja muszą być przeciwieństwem szaleństwa. Oba zawody polegają na rozkładaniu problemu na części pierwsze, ekstrakcję sensu i zamykanie całości w powtarzalny element, który raz wykonany oszczędzi nam technologicznego jąkania.

Szaleństwo w obu zawodach wypływa z innego źródła: nasze rozwiązania często są kruche i produkcja ich zajmuje dłużej niż suma powtórzeń. Nikt nie powiedział, że mamy wszystkie odpowiedzi, zwykle nie znamy nawet pytań.

Po raz kolejny zgrzytałem zębami, gdy przegrywałem czysty obraz dystrybucji na kartę SD abym mógł zaprząc Raspberry do męczenia się nad moim nowym pomysłem. Mimo tego, że mam dostęp do dziesiątek serwerów znajduję przyjemność w zerkaniu przez ramię na lodówkę i szydercze uśmiechanie się w kierunku zwisających z za krótkich kabli ethernetowych mikro-komputerów.

Do tej pory widzieliście już jak Jeżyna mrugała LED-ami czy też pieczołowicie zbierała klatki z kamer. Ostatnio zacząłem zostawiać laptopa w pracy i zbudowałem sobie „maszynę do pisania” w nadziei, że to natchnie mnie twórczo. Głównym rezultatem było szukanie fontów, które dają się czytać na 3.2 calowym ekranie i które mają polskie znaki.

Raspberry na biurku

Dziś znów coś wymyśliłem i od razu rozbolała mnie głowa. Znów ustawianie WiFi, znów parowanie urządzeń BT, przegranie tego czy owego. Zawsze to samo. Ale przecież nie trzeba tak żyć. Postanowiłem zobaczyć, czy uda się łatwo zmodyfikować obraz tak, abym zawsze mógł startować z wygodnego mi miejsca. Rozważałem Ansible, ale to zakłada obecność sieci.

Rozpocząłem od pobrania czystej wersji systemu i rozpakowania jej. Dostajemy wtedy plik YYYY-MM-DD-raspios-ver-distro.img. Jest to obraz zawierający dwie partycje: /boot i rootfs. Teoretycznie można je zamontować przy użyciu -o loop, ale trzeba znać ich przesunięcia, a my tu gadamy o automatyzacji. Na szczęście istnieje kpartx zajmujący się czytaniem tych informacji.

% sudo kpartx -v -a 2020-05-27-raspios-buster-lite-armhf.img
add map loop8p1 (254:0): 0 524288 linear 7:8 8192
add map loop8p2 (254:1): 0 3088384 linear 7:8 532480

Otrzymaliśmy dwa urządzenia reprezentujące wyżej wspomniane partycje. Teraz możemy je normalnie podmontować.

% mkdir /tmp/{1,2}
% sudo mount /dev/mapper/loop8p1 /tmp/1
% sudo mount /dev/mapper/loop8p2 /tmp/2

Mając dostęp do zamontowanych partycji możemy podciągnąć nasz system do stanu, który nam bardziej odpowiada. Przykładowo sudo touch /tmp/1/ssh, zgodnie z dokumentacją odpali nam SSHd przy piewszym uruchomieniu. Oto kilka modyfikacji, które dodałem dla własnej wygody:

  1. Edycja hostname, bo komputer musi się jakoś fajnie nazywać.
  2. Wgranie własnego klucza żebym się nie musiał bawić we wpisywanie haseł. Wystarczy stworzyć katalog .ssh w home/pi w ścieżce drugiej partycji i wrzucić co trzeba do authorized_keys
  3. Dostaję wścieklizny, gdy za każdym razem muszę usuwać odcisk palca hostu. Utworzyłem więc i przegrałem do etc/ssh/ wcześniej wygenerowane pliki ssh_host_* upewniając się, że nigdy nie zobaczę spanikowanego komunikatu o potencjalnym zagrożeniu. Jedna uwaga do tego, unit systemd odpowiedzialny za tworzenie kluczy ignoruje obecność już istniejących. „Rozwiązałem” ten problem usuwając go z lib/systemd/system. Pewnie jest mądrzejszy sposób, np. usunięcie symlinka.
  4. Podobnie jak z aktywacją SSHd możemy wrzucić do podmontowanego /boot wpa_supplicant.conf z definicją domowego/pracowego WiFi.
  5. Dograłem trochę oprogramowania, którego i tak zawsze potrzebuję, a nie znajduje się w pakietach.

Jest jeszcze jedna sztuczka, której nie będę opisywał, bo już zrobili to za mnie. Używając qemu możemy dokonać chroota w obcy architektonicznie system i poinstalować/poodpalać rzeczy bez potrzeby wkładania karty do Raspberry.

Kiedy skończymy modyfikacje kluczowe jest odmontowanie partycji i usunięcie mappera stworzonego przez kpartx. Podczas pierwszych eksperymentów udało mi się dokonać sztuki, w której co innego widziała karta, a co innego obraz.

% sudo umount /tmp/1 && sudo umount /tmp/2
% sudo kpartx -d 2020-05-27-raspios-buster-lite-armhf.img
loop deleted : /dev/loop8

Po tej operacji nasz zmodyfikowany obraz możemy odłożyć gdzieś na bok i w przyszłości generować systemy typu „zupka chińska”, tylko zalać wodą.

Pomiędzy dwoma rozwiązaniami, które rozważałem: uruchamianie z TFTP lub modyfikacja obrazu źródłowego ten drugi okazał się być dużo mniej wymagający. Może w przyszłości zautomatyzuję tę automatyzację (zwłaszcza tę część z qemu, ale wpierw naciszę się tym małym, środowym, sukcesem.


Dobre rzeczy, gorzej: Jajeczka w 302 liniach Lua

W mojej przygodzie z programowaniem jest wiele rzeczy, których nie próbowałem. Umościłem się wygodnie na dnie stosu i ciężko jest mi się wygrzebać z tego barłogu, gdzie ciepło, a wszystkie kąty są znane. Cierpię też na przypadłość, która trapi wielu programistów: mój zmysł estetyczny jest przytłumiony. Jeśli coś wygląda paskudnie, a działa doskonale to znaczy, że jest piękne. Dlatego też podchodziłem do programowania gier z wielką nieufnością. Trzeba się piekielnie napracować żeby coś dobrze wyglądało. Żeby grający wiedział, co dzieje się na ekranie.

Do tego trzeba mieć pomysł. Najlepiej dobry pomysł.

Dlatego latami czytałem sobie rozmaite „jak to się robi”, ale nigdy nawet nie wyszedłem poza kompilację załączonych przykładów do tej czy innej biblioteki, mądre potrząsanie głową i mówienie „Acha!”.

Kilka dni temu zamknąłem dzień w pracy straszną awanturą. Jedną z tych, która jak śniegowa kula zaczyna się gdzieś od płatka, a kończy się groźbą rozpłaszczenia nas wszystkich. Potrzebowałem zająć się czymś do końca dnia żeby nie usiąść i nie zacząć komponować e-maila z kategorii „jak ja to widzę”.

Potrzebowałem czegoś absorbującego uwagę, więc najlepiej czegoś, czego nigdy nie robiłem. Wiem, napiszę grę. Problem braku pomysłu i jakości rozwiązałem w iście holiudzkim stylu. Zrobię to, co już było, ale gorzej!

Mój wybór padł na kultową grę elektroniczną zwaną kolokwialnie „Jajeczkami”. Zasady są proste, grafika jest prosta. Powinienem sobie dać radę. W temacie narzędzi padło na Luę i Love2d. Nie znałem jednego ani drugiego, więc idealnie wpasowywały się w mój plan zajęcia głowy nowymi problemami.

Po godzinie udało mi się uzyskać kontrolę nad środowiskiem na tyle, że patrząc na biały prostokąt rozpierała mnie duma i wiara we własne możliwości. Postanowiłem udokumentować ten cały proces i podzielić się nim z Wami. Na początku wymyśliłem, że będzie to doskonały tekst dla początkujących, ale im bardziej piętrzyły się przede mną problemy tym bardziej traciłem wiarę, że dam radę.

Powstały więc zapiski chaotyczne, które ani nie uczą, ani nie tłumaczą. Przynajmniej powstrzyma mnie to od napisania „Re: jak ja to widzę”.

„Jajeczka”

Wpierw o samej grzej. „Jajeczka” to klon Mickey Mouse, gry elektronicznej wydanej w 1984 przez Nintendo. Postacie zostały wymienione na mniej reakcjonalne maskotki z kreskówki „Ну, погоди!”. Wcielamy się w postać Wilka, który w kreskówce przedstawiany jest jako bumelant i opryszek. Tym razem zajmuje się pracą na kurzej fermie, najwidoczniej w wyniku resocjalizacji.

Na czterech grzędach siedzą cztery kury, które znoszą jajka, a te pod wpływem grawitacji toczą się rynnami w dół. Naszym zadaniem jest złapanie ich do koszyka. Trzeba też nadmienić, że kury te są niesamowicie produktywne, Trofim byłby dumny.

Wyświetlacz to segmentowane LCD. Znaczy to, że wszystkie możliwe elementy są predefiniowane, a ruch symulowany jest przez zapalanie odpowiednich kształtów. Znacząco ułatwia mi to kradzież, gdyż nie muszę się przejmować skomplikowanymi fazami ruchu.

Wyświetlacz LCD ze wszystkimi komponentami

Postanowiłem wyciąć wszystkie elementy, które pozostają w ruchu i potem poukładać je samemu w grze.

Mamy więc:

  1. Wilka patrzącego w lewo i prawo
  2. Ręce Wilka sięgające do dolnej i górej grzędy dla lewego i prawego kierunku
  3. Pięć faz animacji toczącego się jajka dla każdej rynienki
  4. Cztery fazy animacji „stłuczonego jajka”
  5. Wskaźnik liczba „stłuczonych jajek”

To powinno wystarczyć za część graficzną. Teraz pozostaje zebrać całość do kupy. Ale zanim zaczniemy, kilka słów dla czytelników, którzy nigdy nie interesowali się jak to się dzieje, że rzeczy się ruszają i są w odpowiednich miejscach. Choćby amatorsko doświadczeni w sztuce będą wiedzieli, że te definicje nie są idealne, ale to neofita tłumaczy ludziom krok za nim.

Ekran

Możecie myśleć o ekranie komputera jak o kartce papieru w kratkę, gdzie każdy segment to pojedynczy piksel, który można zaświecić na dowolny kolor z dostępnej dla komputera palety. Pozycję na ekranie wyrażamy jako koordynaty X i Y.

W przypadku Love2d, lewy górny róg ekranu znajduje się pod pozycją (0, 0). Więc (10, 0) znaczy jedenaście pikseli (liczymy od zera) w prawo od brzegu w pierwszej linii. Idąc dalej tym tropem (4, 5) znajdzie się w szóstej linii od góry, pięć pikseli od lewego brzegu ekranu.

W większości przypadków nie będziemy rysować grafiki piksel po pikselu. Zwykle wczytujemy gotowy element graficzny, który umieszczamy na naszej płaszczyźnie. Sam wczytany obiekt ma własną, wewnętrzną siatkę koordynat, ale umieszczamy go wskazując miejsce, gdzie znajdzie się jego (0, 0).

Więc jeśli chcemy wczytać niezmiernie estetyczną żółtą twarz i umieścić ją gdzieś na ekranie, powiemy, że pod (9, 5) to wyląduje tam lewy górny bok, reprezentowany wewnętrznie przez (0, 0)

Animacja pokazująca siatkę

Myślę, że to wszystko czego potrzebujemy na tę chwilę.

Stan

Stan to wiedza o wszystkich właściwościach świata stworzonego w grze. Co jest stanem w Jajeczkach? W którą stronę obrócony jest wilk i jak ma ułożone ręce. Ile razy przegraliśmy. W jakiej pozycji znajdują się jajka i ile ich jest na ekranie. Punktacja. Wszystkie elementy, które tworzą grę są odzwierciedlone przez zmienną, która jest potem interpretowana przez nas.

Zmienna score w consts.lua trzyma naszą punktację, miss liczbę skuch, w main.lua hands i face reprezentują pozycję wilka.

W Love2d stan jest globalny, tj. wszystkie komponenty mają bezpośredni dostęp do zmiennych. Jest to uważane za bardzo zły pomysł™, gdyż niepowiązane komponenty mogą sobie stawać na palcach i doprowadzać do nieokreślonego stanu, ale myślę, że obniża to też znacząco wysokość pierwszego stopnia, który potencjalny twórca musi pokonać.

Pętla

Istnienie czasu to problem, który spędzał sens z powiek wielu filozofom. Czy to rzeczywiście taka prosta linia z przeszłości w przyszłość? Czy może cały czas istnieje na raz, a nasza świadomość odbiera tylko echa takiej projekcji. Być może zmiany są w ogóle niemożliwe?

Jakakolwiek jest rzeczywistość skryta przed naszymi oczami, zmechanizowaliśmy czas, pocięliśmy go na plasterki sekundową wskazówką zegarka i empirycznie jest nam z tym dobrze.

W grze zmiana i czas muszą być przez nas odtworzone, nikt nie znajdzie przyjemności patrząc w statyczny obraz na ekranie kiedy miał zamiar grać.

Love2d posiada dwie funkcje, które są wywoływane na okrągło, w nieskończonej pętli. To w nich implementujemy zmianę (co się rysuje) i czas (zmiany stanu gry). Są to odpowiednio love.draw() i love.update(dt).

Może zauważyliście, że w przypadku update mamy parametr dt — jest to zmienna, która mówi ile czasu minęło od ostatniego jej wywołania (Δ czasu). Pozwala nam to kontrolować czas w którym rzeczy się dzieją. Przykładowo chciałem aby można było poruszać Wilkiem w każdej chwili, ale ruch spadających jajek musi zachować jednolite tempo, niepowiązane z ruchem postaci (inaczej gra nie była by uczciwa: gdyby Wilk poruszał się w tempie spadających jajek, sięgnięcie trzech będących na granicy rynny byłoby niemożliwe).

Popatrzmy w kod:

function love.update(dt)

    require('wolf_movement') 
    wolf_movement()

    time_since_movement = time_since_movement + dt
    if(time_since_movement >= ms_to_roll) then
        time_since_movement = 0
        -- a jednak się rusza!
    end
end

Mamy zmienną time_since_movement w której składujemy wszystkie mikrosekundy, które do nas przyszły w wyniku wykonywania funkcji. Jeśli ta suma jest większa niż zdefiniowana w ms_to_roll ruszamy spadającymi jajkami. Funkcja odpowiedzialna za ruch wilka znajduje się w wolf_movement i jest poza blokiem, pozwalając mu ruszać się w każdej chwili.

Po tym jak Love2d skończy wykonywać ciało funkcji love.update(dt) wywoływane jest love.draw(), gdzie nasza grafika jest rysowana zgodnie ze stanem ustawionym wcześniej.

Elementy graficzne

Każda klatka animacji znajduje się w osobnym pliku i jest wczytywana podczas inicjalizacji programu. Wymyśliłem sobie, że będę je wszystkie trzymał w tabeli (nomenklatura Lua znacząca listę/hashmapę), dzięki czemu animowanie będzie polegało tylko na zwiększaniu indeksu o jeden.

W przypadku Wilka musiałem zastosować nieco inną metodę. Ponieważ rusza się on niezależnie i jest sterowany przez nas, możemy jego fragmenty pochować pod ładnymi nazwami

-- pozycje wilka
wolf_left = {
    171, 134, -- koordynaty
    love.graphics.newImage('assets/wolf_left.png'), -- obrazek
    'left' -- nazwa
}
wolf_right = {
    250, 134,
    love.graphics.newImage('assets/wolf_right.png'),
    'right'
}
left_up = {
    124, 134,
    love.graphics.newImage('assets/left_up.png'),
    'up'
}
left_down = {
    116, 193,
    love.graphics.newImage('assets/left_down.png'),
    'down'
}
right_up = {
    309, 138,
    love.graphics.newImage('assets/right_up.png'),
    'up'
}
right_down = {
    300, 198,
    love.graphics.newImage('assets/right_down.png'),
    'down'
}

Każdy fragment Wilka składa się z czteroelementowej tablicy, która zawiera: koordynaty, reprezentację wczytanego obrazka, a następnie string. Ten ostatni dodałem nie mogąc wymyślić jak zaimplementować sytuację, gdy Wilk patrzy w jedną stronę i zmieniamy go na drugą. Logika mówi, że jeśli trzymał ręce w górze w lewo, po zmianie na prawo ta pozycja będzie zachowana. Niestety, nieznajomość Lua spowodowała, że nie mogłem wymyślić lepszego pomysłu niż wulgarne nazwanie kierunku.

Ruch jajek miał dużo mniej problemów merytorycznych.

-- ruch jajek
eggs_pos = {
    {
        {37, 86, love.graphics.newImage('assets/left_up_egg_1.png')},
        {54, 99, love.graphics.newImage('assets/left_up_egg_2.png')},
        {75, 104, love.graphics.newImage('assets/left_up_egg_3.png')},
        {92, 117, love.graphics.newImage('assets/left_up_egg_4.png')},
        {107, 137, love.graphics.newImage('assets/left_up_egg_5.png')}
    },
    {
        {39, 156, love.graphics.newImage('assets/left_down_egg_1.png')},
        {55, 164, love.graphics.newImage('assets/left_down_egg_2.png')},
        {71, 176, love.graphics.newImage('assets/left_down_egg_3.png')},
        {92, 183, love.graphics.newImage('assets/left_down_egg_4.png')},
        {105, 204, love.graphics.newImage('assets/left_down_egg_5.png')},
    },
    {
        {416, 87, love.graphics.newImage('assets/right_up_egg_1.png')},
        {399, 95, love.graphics.newImage('assets/right_up_egg_2.png')},
        {381, 106, love.graphics.newImage('assets/right_up_egg_3.png')},
        {359, 117, love.graphics.newImage('assets/right_up_egg_4.png')},
        {346, 128, love.graphics.newImage('assets/right_up_egg_5.png')},
    },
    {
        {418, 159, love.graphics.newImage('assets/right_down_egg_1.png')},
        {399, 164, love.graphics.newImage('assets/right_down_egg_2.png')},
        {380, 174, love.graphics.newImage('assets/right_down_egg_3.png')},
        {364, 184, love.graphics.newImage('assets/right_down_egg_4.png')},
        {343, 200, love.graphics.newImage('assets/right_down_egg_5.png')},
    }

}

Mamy więc tabelę z czterema elementami, które odwzorowują cztery rynny. A w nich pięć faz animacji spadającego jajka: koordynaty i plik graficzny. Czyli eggs_pos[1][1] to pierwsza rynna, pierwsza pozycja jajka. I tak, zanim zapytacie: tabele w Lua zaczynają indeks od 1. Miałem przynajmniej trzy błędy związane z moim — najwidoczniej optymistycznym — założeniem, że liczymy od zera!

Podobnie wygląda definicja animacji skuchy.

I to byłoby na tyle w temacie przygotowania elementów graficznych.

Wilk lewy, Wilk prawy

Miałem wielką ambicję zrobienia jakiejś dobrej abstrakcji w temacie ruchu naszym protagonistą. Nauczyłem się jednak, że zła abstrakcja boli całe życie. Zwłaszcza, gdy robi się ją kompletnie bez znajomości idiomów języka. Postanowiłem, że prosty if() nikogo nie zabił, nawet jeśli powtarzam się powtarzam się przy tym przy tym.

Czytanie klawiatury w Love2d jest trywialne, nie trzeba znać nawet kodów klawiszy.

function wolf_movement()
    if love.keyboard.isDown("up") then 
        if face[4] == 'left' then
            hands = left_up 
        else
            hands = right_up
        end
    end
    if love.keyboard.isDown("down") then 
        if face[4] == 'left' then
            hands = left_down 
        else
            hands = right_down
        end
    end
    if love.keyboard.isDown("right") then
        face = wolf_right
        if hands[4] == 'up' then
            hands = right_up
        else
            hands = right_down
        end
    end
    if love.keyboard.isDown("left") then
        face = wolf_left
        if hands[4] == 'up' then
            hands = left_up
        else
            hands = left_down
        end
    end
end

Zmienne face i hands przechowują obecną pozycję Wilka. Widzimy tu moje tchórzliwe użycie czwartego elementu do zachowania stanu rąk. Teraz trzeba wrócić do love.draw i powiedzieć mu, co rysować.

love.graphics.draw(face[3], face[1], face[2])
love.graphics.draw(hands[3], hands[1], hands[2])

I to wszystko! Już można hasać po ekranie. Programowanie gier to czysta przyjemność, gdy nie przejmujesz się detalami!

Demonstracja ruchu

Jajka się toczą

Nabuzowany tym sukcesem postanowiłem powoli zabrać się za następny element, ruch spadających jajek. Pierwsza wersja przyszła szybko.

Piersze jajka za płoty

Mina mi jednak szybko zrzedła. Okazało się, że zapomniałem o grze w grze. Moja pierwsza implementacja nie mogła działać. Muszę mieć możliwość losowego spuszczania jajek dowolną rynną oraz dodawania nowych. Dodatkowo jest też zwiększający się poziom trudności, zaczynamy od jednego jajka, a po uzyskaniu jakiejś liczby punktów muszą być dwa. I nie mogą zaczynać w tym samym momencie. Dobrą chwilę patrzyłem w kod nie potrafiąc się wyrazić wystarczająco jasno w Lua.

Na przykład zmienną trzymającą stan rynien normalnie ująłbym używając binarnej reprezentacji. 0x1010 i wiemy, że jajko toczy się po rynnie 1 i 3. Ale Lua nie ma w standardowej bibliotece odpowiednich narzędzi, nie chciałem utknąć w trybie „jak się instaluje biblioteki”. Zrobiłem więc następującą rzecz, wiedząc już, że moje zapiski będą bezużyteczne dla absolutnie początkujących: dodałem zmienne eggs = {0, 0, 0, 0} i roll_on = {0, 0, 0, 0} reprezentujące odpowiednio klatkę animacji na danej rynience i to, czy coś się po niej toczy. Następnie napisałem okropne sum(), które przyjmuje tabelę i sumuje elementy. Aplikując to na roll_on wiem ile rynienek jest zajętych. Teraz tylko sprawdzić, czy chcę mieć więcej jajek niż jest widoczne, zapisać indeksy tych, które są puste (==0) i losowo wcisnąć jajko.

A co z opóźnieniami? Okazało się, że Lua jest cierpliwe i zaakceptowało mój szalony pomysł: ustawię pozycję na ujemną!

I jakimś cudem zadziałało, uff…

function gutters_logic()
    if sum(roll_on) == 0 then -- nic się nie toczy
        -- znieś jajko byle gdzie
        roll_on[math.random(1,4)] = 1
    end

    if sum(roll_on) < eggs_on_screen then
        -- jest mniej jajek niż chcemy
        print("Sum(roll_on) ", sum(roll_on))
        print("eggs_on_screen ", eggs_on_screen)
        pick = {}
        how_many_we_need = eggs_on_screen - sum(roll_on)
        print('how_many_we_need ', how_many_we_need)
        for i=1, table.getn(roll_on) do
            -- wybieramy puste rynienki
            if roll_on[i] == 0 then
                table.insert(pick, i)
            end
        end

        for i=1, how_many_we_need do
            -- losowa rynna z dostępnych
            choice = math.random(1, table.getn(pick)) 
            if roll_on[pick[choice]] == 1 then
            else
                roll_on[pick[choice]] = 1
                -- ileś „tyknięć nim się pojawi”
                eggs[pick[choice]] = math.random(1, 4) * -1
            end
        end
    end
end

Jak Doktor Frankenstein byłem zafascynowany i przerażony, że to żyje!

Rysowanie poszło dużo łatwiej.

for i=1, table.getn(roll_on) do
    if eggs[i] > 0 then
        current_egg = eggs_pos[i][eggs[i]]
        love.graphics.draw(current_egg[3], current_egg[1], current_egg[2])
    end
end

Goń i łap

Nie pozostało nic innego jak zacząć łapać te jajka. Po raz kolejny zawiesiłem wszystko na choince if()ów.

function success_or_failure(i)
    if i == 1 and face == wolf_left and hands == left_up then return true end
    if i == 2 and face == wolf_left and hands == left_down then return true end
    if i == 3 and face == wolf_right and hands == right_up then return true end
    if i == 4 and face == wolf_right and hands == right_down then return true end
    return false
end

Należało to jeszcze wpiąć w love.update(dt)

for i=1, table.getn(roll_on) do
    -- jeśli jajko się tu toczy
    if roll_on[i] == 1 then
        -- daj następną klatkę animacji
        eggs[i] = eggs[i] + 1
        if eggs[i] == fail_at then
            -- jajko jest na brzegu? A gdzie patrzy wilk?
            if(success_or_failure(i)) then
                score = score + 1
                -- agresywnie zwiększam ilość jaj dla debugu
                if score == 2 then
                    eggs_on_screen = 2
                end
                if score == 5 then
                    eggs_on_screen = 3
                end
            else
                miss = miss + 1
                if i == 1 or i == 2 then
                    failure_left = 1
                else
                    failure_right = 1
                end
                print("Bams", i, failure_left, failure_right)
            end
            -- jajko znika, komora losowania jest pusta
            eggs[i] = 0
            roll_on[i] = 0
        end
    end
end

I tak, krok po kroku, całość zaczęła przypominać pierwowzór. Osiągnąłem swój cel główny: zmarnowałem prawie 5h1. Cel poboczny, tj. zrobić coś, czego nigdy nie robiłem, uznaję też za osiągnięty.

Teraz myślę nad zmianą kariery, napędzany zadufaniem początkującego.

Kod dostępny jest w repozytorium wraz z półproduktami.

PS. jeśli na serio chcecie się czegoś dowiedzieć o projektowaniu gier polecam Wam książki wydane przez moich przyjaciół z „Inżynierii Wszechświetności”, choćby Level design.


  1. I 2h pisząc to, a za 7h muszę przejechać na rowerze 60Km, proszę o współczucie. 


Oczy wielkie jak spodki, a na nich rzęsy jak łyżki

Siedzieliśmy na betonowych schodach z nogami spuszczonymi przez balustradę i rozmawialiśmy o przyszłości. To były czasy kiedy rozmawianie o przyszłości było zajęciem przyjemnym, taśma na nienagranej szpuli życia była zdecydowanie dłuższa. Karolina chciała zostać pielęgniarką lub weterynarzem. Ja planowałem zostać lumpem. Ona została samotną matką, a mnie się udało.

Karolina wyszła na chwilę do mieszkania, by wrócić z herbatą i pudełkiem pełnym papierów. Wyciągnęła z niej jedną kartkę i powiedziała: znalazłam ostatnio list miłosny od Radka. I choć to faux pas czytać cudze listy, dwakroć miłosne, a po trzykroć powtarzać ich treść w Internecie, jedna linijka utkwiła mi w pamięci do teraz.

Listy miłosne w podstawówce mają dwie cechy: próbują naśladować język dorosłego romansu zagapiony z popularnej kultury i kart książek do języka polskiego, ale są jeszcze wystarczająco pozbawione elementu cielesności by nie być „w sedno”, mają też okropną gramatykę i interpunkcję. Gdy przeczytała mi więc zdanie „[…] Twoje czerwone usta oczy” nie mogłem przestać wymyślać zabawnych anegdot o tym, co powoduje, że Karolina ma czerwone oczy. Płacze nad przecinkiem, nie śpi, a może ma nieustanny katar? Debatowaliśmy to aż do wystygnięcia herbaty.

Mijają lata, a ja za każdym razem, gdy trafiam na porównanie w książce odpalam w głowie proces, który modyfikuje ckliwości w głupoty. Nie mogę się tego pozbyć, co pewnie tłumaczy, czemu nie czytam romansów. Za dużo „śmierci autora” na centymetr kwadratowy. A mówię Wam to żeby Was zakazić, może gdy wszyscy będziemy porażeni tą samą przypadłością środowisko medyczne weźmie nas pod uwagę i wynajdą proszki na cynizm. Byle nie w formie czopka.

Miała usta jak jagody: czarne, łatwo było je rozgnieść, pożerały je niedźwiedzie.

Miała oczy jak diamenty: ślepe, rysował jej szkła kontaktowe, sprowadzały nieszczęście na afrykańskie wioski.

Jej piersi jak arbuzy, dawały wiele rozkoszy, gdyby nie te pestki.

Jej łabędza szyja utrzymywał małą głowę, a twarz zakończona dziobem utrudniała picie z filiżanek.

Jej porcelanowa skóra była twarda w dotyku, uniemożliwiała ruch, a kolor nabrała dopiero wypalona w piecu.

Włosy koloru siana: jesienią sino-brunatne, zmatowiałe, martwe.

Była mądra jak sowa: wiedziała wszystko o jedzeniu myszy w locie.

Miała wielkie serce, co martwiło kardiologów.

Śpiewała jak skowronek, monotonnie, bez słów, budziła cię świtem.

Była potulna, jak baranek. Nocą rodzice spuszczali na nią psy by zapędzić ją do łóżka.

Rzuciła mu perłowy uśmiech. Małe, okrągłe zęby świeciły się tęczowo gdy padało na nie światło pod dobrym kątem.

EDIT: ojej, wymsknęło się z drafts. No trudno.


Rezygnacja: automatyzacja

„Zautomatyzowałem zadanie, które zajmowało mi 2 minuty raz na miesiąc. Poświęciłem 8 godzin pracy i już mogę je robić w minutę. Póki nie zmienią się parametry.”

Na dworze administracja prowadzi wiosenną wojnę z okalającym nas betonem. Piechota uzbrojona w młoty pneumatyczne kruszy wszelki opór. Zwycięstwo jest blisko, może jeszcze tydzień. Cywilne ofiary wojny, czyli ja, są wliczone w koszta tej bitwy.

Nie mogę tak pracować, co znaczy, że muszę poczekać na wieczór, aż świat pójdzie spać. Muszę jednak jakoś wypełnić te godziny. Co mogę zrobić? Tylko rzeczy głupie. Głupie rzeczy nie wymagają myślenia, a zajmują tyle samo, co rzeczy dobre!

Kilka dni temu wysłałem moim kolegom-programistom komediowe wideo o tragediach czających się w świecie mikroserwisów. Nigdy nie robiłem mikroserwisów, ale mam bardzo mocne opinie na ich temat dlatego staram się uzyskać społeczny dowód na moje racje od ludzi, którzy dłubią je każdego dnia. Podczas krótkiej wymiany opinii powiedziałem, że DevOops powinni nauczyć się od projektantów i DTP-owców i nazywać serwisy tak, jak oni nazywają pliki. Losowe liczby, daty, wulgaryzmy.

Zawsze lubiłem patrzeć na ich metodologię. Historia wprost wycieka z takiej nazwy. Czy jest data? Może to już któryś dzień walki? Czy jest _final, i czy jest coś po _final? Nieodpowiedzialny hurra-optymizm został ukarany. Czy są „ozdobniki”, które powodują, że sortowanie katalogu wyciąga je na górę?

Wymyśliłem, że jedynym dobrym zajęciem jest przygotowanie kodu, który mógłby zostać zamieniony w mikroserwis ułatwiający utworzenie takich nazw. Użyłem najlepszej technologii AI (tak na serio to ML (tak na serio to if(random() >= .5))) i utworzyłem następujące rozwiązanie™.

params = {
    'crazyness': .5, 
    'optimism': .6, 
    'vulgarity': .7, 
    'timekeeper': .6, 
    'decorations': .6
}

from despyration import despyration

files = [
    'podanie_o_nienapierdalanie_mlotem.docx',
    'reklama-plynu-do-mycia.psd', 
    'umowa_o_dzialo.pdf'
]

[despyration(f, **params) for f in files]

A oto rezultaty:

2020-05-19-PODaNIe_O_NiENapIerDalanIE_mloTem!!!.docx

rEKLAMa-plYNu-DO-mYciA__fuck-2020-05-19@.psd

umowa_o_dzialo_final_final_final+++.pdf

Myślę, że udało mi się oddać ducha, choć pozostaje wiele pracy. Trudno jest zasymulować prawdziwy proces, sztukę, intuuicję oraz frustrację, która rodzi te nazwy. Stoję na ramionach gigantów, a oni mi mówią żebym się odwalił, co to w ogóle znaczy wspinać się po ludziach, zwłaszcza teraz, w epoce zarazy.


To się nie nadaje do druku

Każda przygoda ma swój punkt zapalny. U mnie były dwa. Pożyczyłem okropnego tableta z Windowsem przyjacielowi, którego laptop nagle wykitował. To okropny tableto-laptop. Okropna klawiatura, 2GiB pamięci, 32GiB wlutowanego dysku i 64GiB karta, którą dodałem żeby się coś dało zrobić pomiędzy aktualizacjami. To dlaczego go mam? Waży mniej niż kilogram, więc nadaje się do plecaka, gdy idę w świat (wszystkie systemy czekają z kręceniem powrozu na swoje karki do momentu w którym moja stawiam nogę na dworcu), dodatkowo ładuje się z USB.

Ma też niezły ekran, więc używam go do czytania tych średnio-długich tekstów. Pożyczając go pozbawiłem się tej opcji.

Kupiłem też drukarkę. Wyrzucenie z biur klientów przez zarazę odebrało mi możliwość bezczelnego podsyłania ludziom e-maili o tytule „wydrukuje mi Pani?”. Do tego moja lokalna poczta jest bardzo popularna, więc każdego dnia o każdej godzinie wystaje z niej ludzka gąsienica petentów. Dowiedziałem się, że można drukować własne znaczki, więc zakup wydał się jeszcze bardziej usprawiedliwiony.

Bo kto ma teraz lepsze znaczki niż ja?

Zdjęcie znaczka

Pomyślałem, że połączę utratę urządzenia do czytania i nabycie urządzenie do drukowania w nowe rozwiązanie. Wydrukuję sobie zaległe teksty i będę sobie w spokoju czytał do kawy. Cóż może być trudniejszego niż wydrukowanie dokumentu? Z pewnością nic.

Zbadajmy jak to wygląda!

Wybrałem do testów serwisy, których artykuły gniją w moim Pocket’cie. Nie testowałem prywatnych stron, bo wydaje mi się to nie fair. Nie tylko teksty są zwykle krótsze, ale też nie mogę oczekiwać, że mają budżet/czas na picowanie swojej oferty. Dodatkowo, teksty „prywatne” są głównie o programowaniu, więc mają wartość dodaną na ekranie komputera, głównie naukę metodą Kopiego-Pasty.

the Bellows: Tekst wygląda dobrze. Nagłówek, wraz z elementami nawigacji powtarza się co stronę. Takoż guzik udostępniania. Stopka dodaje całą stronę A4 niczego ważnego.

Places Journal: Tekst sformatowany jak na stronie, mała czcionka, elementy takie jak odgrywaczka audio pozostały. Stopka dodaje bezużyteczną stronę. Nieczytelne, bezużyteczne.

Damage: Układ praktycznie doskonały. Niestety, stopka znów dodaje bzdety, których nikt nie potrzebuje na kartce.

Claremont Review of Books: <div> z reklamą ciągnie się całą długość dokumentu, powodując, że tekst zajmuje 70% strony i jest przesunięty do prawego brzegu. Dwie strony stopki. Koszmar.

The Point: Idealnie. Pierwszy przypadek, gdy wszystko jest gotowe. Tekst, który próbowałem dodał pustą stronę A4, ale ponieważ ostatni paragraf kończył się idealnie na poprzedniej zakładałem, że to przykry zbieg okoliczności. Zbadanie innego tekstu potwierdziło. Pierwszy sukces!

Harper’s: Nagłówek zawiera logo i pustą stronę. Potem jest strona tekstu, która się urywa, gdyż jest „zabezpieczone JavaScriptem”. Siadaj, dwója. Jutro przyjdź z matką.

Public Books: Font à la „Retina, ale na kartce”, dwie strony stopki. Znacie tę piosenkę.

Times Literary Supplement: Szatan, piekło, antychryst. Czyli Single Page Application. Jedna strona nagłówków, wraz z banerem polecającym żebym dał im dolara, jedna strona tekstu, ucięta, a na niej baner proszący o dolara. Stopka. I baner proszący o dolara.

Ars Technica: Sztywna nawigacja, ślepe galerie, paginacja. Desperacja.

Increment: „drukuje się” jedna strona.

Jeden dobrze. Jeden OK. Trzy powodują, że drzewa ronią łzę. Cztery nawet nie próbują udawać, że ktoś kiedyś myślał o papierze.

Umówmy się: gówno wiem o projektowaniu wyglądu, potrzebach „spieniężania” treści i innych problemach z którymi mogą się borykać magazyny internetowe. Jestem tylko kolesiem, który chciał sobie wydrukować trochę tekstu do czytania. Te rezultaty podsycają jednak moją nienawiść do tumiwisizmu współczesnej sieci.

Jeśli zboczysz z wyznaczonej ścieżki choćby o krok nagle znajdujesz się na brzegu klifu, a za Tobą materializuje się dobrze ubrany konsultant, który uprzejmymi gestami zachęca cię do skoku. Najlepiej bańką do przodu.


Chromecast dla Linuksiarza

Przyznaje się, przegrałem. Jest sobota, a ja miałem dobry pomysł na zabawny tekst. Tekst, który wymagał może zbyt wiele kompetencji, których nie posiadam. Od siódmej rano walczyłem z oprogramowaniem do edycji wideo, zbyt starym cmake, nagrywaniem akcelerowanego wideo, faktem, że pliki instalacyjne wyparowały mi z archiwum i tym, że firma, od której kupiłem oprogramowanie mentalnie jest w 1990 i strzeże swoich fantów jak oczka w głowie.

Rzuciłem się z motyką na słońce, a na dodatek słońce było uzbrojone i mnie obstrzelało ostrą amunicją. Wybiła trzynasta, a ja mam jedno źle skadrowane wideo — testowe wideo, nawet nie to, co chciałem — które się chybocze, dyga i ma zły aspekt. Czas powiedzieć sobie: OK, zjedz coś, usiądź. Po co się denerwować.

To prowadzi nas do miejsca, w którym, jak mawiają Amerykanie jestem all dressed up with nowhere to go. Pójdę więc po linii najmniejszego oporu i po prostu opiszę, co mam na biurku.

Chromecast

Chromecast to odbiornik strumieni medialnych, produkowany przez Google. Małe pudełeczko, które wpina się do telewizora/monitora przez HDMI i pozwala na przesyłanie audio/wideo z rozmaitych serwisów. Mimo mojej niechęci do dawania Google wiazdu do mojego życia, podobnie jak w przypadku porannego projektu, trzeba wiedzieć kiedy się poddać. Mimo niemiłej mi natury produktu nie udało mi się zbudować niczego samemu, bądź też z półproduktów, co byłoby choćby w ułamku tak funkcjonalne.

Normalni ludzie mogą używać aplikacji, które wspierają Chromecast. Praktycznie każda popularniejsza aplikacja mobilna (YouTube, Spotify, Netflix, etc) potrafi rzucić swoje bity na ekran. Działa to bardzo dobrze. Dla normalnych ludzi z komputerami biurkowymi jest Chrome, który będąc IE6 dla nowożytności1, potrafi przesyłać zawartość zakładki.

Co pozostaje dla ludzi z pryszczami, Firefoksem i terminalem? Bardzo dużo bardzo dobrych opcji, o dziwo!

catt

catt to program po którego opisaniu mógłbym skończyć tę notkę. Robi praktycznie wszystko, czego mogę chcieć. Potrafi odpalać strumienie serwisów, które nie wymagają autoryzacji (YouTube, Twitch, Vimeo, etc), oddaje kontrolę nad głośnością, wspiera przewijanie, listy odtwarzania, kolejkowanie, potrafi użyć wbudowanej w Chromecast przeglądarki, by wyświetlić stronę WWW, a ostatecznie odtworzyć plik z dysku lokalnego tworząc serwer HTTP i serwując klatki.

Kilka przykładowych zaklęć:

  1. catt cast https://www.youtube.com/watch?v=0cQA6d3adPs — odtworzy nam wideo znajdujące się pod tym adresem

  2. catt seek 1:00 — przesunie nas na osi czasu

  3. catt add https://www.youtube.com/watch?v=h0rSYEoBMYM — doda następny plik do kolejki (tymczasowo wspierany jest chyba tylko YouTube)

  4. catt cast_site https://fuse.pl/beton/chromecast-linux.html — wyświetli stronę

  5. catt cast Pobrane/HoliłudzkiFilm.Grupa.Nick.x264.mkv — wyświetli lokalny plik

Dostępny jest przez PyPI oraz jako źródło na GitHubie.

Na boku: znalazłem ciekawe zastosowanie dla catt cast_site. Opisywane wcześniej ttyd może zostać „rzucone” na ekran, co wyciąga nam sesję terminala. Oczywiście, nie ma jak z nią działać, ale wymyśliłem obejście tego problemu przy użyciu screen. Na początku tworzymy i odczepiamy sesję przez screen -d -m -S shared, następnie odpalamy ttyd screen -x shared, to startuje nam usługę. Używamy catt cast_site aby wyświetlić stronę ttyd. Teraz wystarczy odpalić lokalnie screen -x shared i już możemy pisać. A tam już co Wam się podoba, htop czy tail -f. Działa znośnie.

VLC

VLC potrafi odtwarzać do Chromecasta, podobnie jak catt. Z tą jednak różnicą, że umie przekodowywać pliki w locie (kosztem procesora). Jest to szczególnie przydatne w sytuacji, gdy mamy pliki „z Internetu”. AVI, mkv, mp4 z x265, rzeczy do których Chromecast nie ma kodeków. Dodałem sobie alias vlcast dla własnej wygody:

cvlc --sout "#chromecast" --sout-chromecast-ip=IP --demux-filter=demux_chromecast

mkchromecast i pulseaudio-dlna

Oba programy potrafią utworzyć sink (jak to będzie po naszemu? Przecież nie „zlew”?) PulseAudio dzięki czemu dźwięk odtwarzany lokalnie może zostać przesłany do urządzenia będącego pod kontrolą Chromecasta. pulseaudio-dlna jest dużo bardziej monotematyczny i robi tylko to, mkchromeast ma więcej funkcji, ale żadnej nie spełnia tak dobrze jak catt. Oba znajdują się w oldoldstable2, zakładam więc, że Wasza dystrybucja też je posiada.

pychromecast

Nic nie stoi na przeszkodzie żebyście sami spróbowali porobić własne zabawki. Odpowiednia biblioteka, która implementuje API Chromecasta pozwoli Wam przejąć kontrolę nad urządzeniem. Gdybym miał kiedyś zrobić info-kiosk to pewnie rozważyłbym takie rozwiązanie. Mam nadzieję, że nie będę nigdy robił info-kiosku.

pychromecast jest oczywiście na PyPI i pod postacią źródła na GitHubie.

Jak widzicie, zebranie wystarczająco dużej ilości narzędzi odpalanych z terminala powoduje, że osiągnąłem stan wyjściowy normalnych ludzi, którzy klikają w Chrome „prześlij na Chromecast”.

Chromecast

Największą wadą Chromecasta jest to, że gdy nie odtwarza treści to przechodzi w tryb „elektronicznej ramki ze zdjęciami” pokazując mi najlepsze momenty moich wypraw, zachody słońca, jelenie, lasy, reklamówki z piwami. W obecnej sytuacji zmienia to znak zapytania w zdaniu „pamiętasz, jak było fajnie” na wykrzyknik.


  1. Best viewed on IE6 in 1024x768 

  2. Nie mam serca żeby się zebrać do aktualizacji mojego głównego laptopa. Działa? Działa. Chyba, że chcę cmake z tego tysiąclecia. 


UserLAnd: chroot w kieszeni

Gdybym zeskanował teraz domową sieć trafiłbym pewnie na nie mniej niż cztery komputery z Linuksem. A jeśli starczyłoby mi gniazdek, to mogę dobić i do dziewięciu. To nie mówi zbyt wiele o samym systemie, a więcej o mojej nieumiejętności używania innego środowiska. Może to Syndrom sztokholmski, ale czuję się z tym doskonale! Dla niektórych „rok Linuksa na biurku” zaczął się w 1997.

Niedawno zapytano mnie „czy możesz nauczyć mnie Linuksa”. Trochę się tym strapiłem, bo mogę oczywiście, tylko nie wiem, co rozumieć przez „Linuksa”? Czy uczenie kogoś powłoki, potoków i pisania pomocniczych skryptów to nauka Linuksa, czy na przykład Basha? Czy stawianie serwera HTTP to nauka Linuksa? Embedded? Rzuciłem okiem na spisy treści już napisanych książek typu „Wstęp do…” i wyszło mi, że zwykle jest to książka w której autor opisuje jak okiełznuje się jego ulubioną dystrybucję.

Dla mnie pytanie o „naukę Linuksa” jest jak pytanie o „naukę młotka”. Do stolarki, budowlanki, morderstwa powodowanego pasją? Nie wiem, jak do tego podejść. Żeby nie utykać w filozofii tego pytania przeskoczyłem na grunt twardszy, jak uczyć kogoś, kto może nie ma wystarczająco zasobów i intuicji żeby mógł wybrać jedną z miliona opcji. Zainstalować na komputerze jako główny lub drugi system? Ciężko. Wirtualna maszyna? Trochę pokracznie. Raspberry Pi? Ból tyłka. WSL? Obiecujące, ale mam zero doświadczenia i jak coś się wywali to nie będę umiał odkręcić.

I wreszcie wpadłem na rozwiązanie, które mi się spodobało.

Każdy telefon z Androidem chodzi pod kontrolą kernela Linuksa i jakiś śmieci na górze, które służą do wyświetlania reklam. Teoretycznie nic nie stoi na przeszkodzie żeby „dorobić” telefonowi przedrostek GNU/. Przez lata było kilka takich projektów, nigdy nie przykładałem do nich jednak uwagi, gdyż jak wspomniałem na górze, mam dziewięć innych komputerów. Przebiegłem się po Biedronce Aplikacji i znalazłem jeden, który mi wybitnie odpowiada: UserLAnd.

Po pobraniu aplikacji i jej odpaleniu zostaniemy powitani przygotowanymi dystrybucjami, które możemy odpalić na swoim telefonie. Są to po prostu drzewa plików spakowane i gotowe do pobrania. Osobiście testowałem tylko Debiana, ale zakładam, że inne działają tak samo. Poza surowymi dystrybucjami można porać pojedyncze aplikacje, takie jak IDE Pythona, Firefoks, GIMP czy zork.

Wybór dystrybucji

Po kliknięciu rozpocznie się proces pobierania i ekstrakcji. Trzeba zwrócić uwagę na to, że pliki te trafią na miejsce z którego mogą być czytane przez inne aplikacje (albo nie: nie jestem na bieżąco z Androidem) więc składanie ważnych danych takich jak hasła, klucze SSH i dane osobiste nie jest polecane.

Konfiguracja użytkownika

Następnie zostaniemy poproszeni o podanie nazwy użytkownika i haseł do SSH i VNC. Nic prostszego.

Tworzenie połączenia

Potem deklarujemy jak się chcemy łączyć z naszą maszyną. Osobiście, co nie jest dziwne, preferuję SSH. Jak będę potrzebował okienek to zawsze mogę dodać -X.

I to wszystko. System podniesie się po chwili i możemy na niego wskoczyć. Ponieważ aplikacja nie może przypisać sobie niskich portów domyślnym jest 2022. Podczas uruchamiania sesji aplikacja będzie chciała użyć jednego z dostępnych klientów aby ustanowić połączenie na telefonie, ale możemy to zignorować. Ekran dotykowy plus magiczne | zaklęcia | z --toną --parametrów to nie jest świat w którym chcę żyć i którego i Wam nie życzę.

λ ~/ ssh emil@192.168.1.204 -p 2022
emil@192.168.1.204's password:
Welcome to Debian in UserLAnd!
emil@localhost:~$ uname -a
Linux localhost 4.9.117+ #2 SMP PREEMPT Thu Feb 13 01:10:05 CST 2020 aarch64 GNU/Linux

I już mamy „prawdziwego Linuksa” chodzącego pod kontrolą kernela dostępnego w Androidzie. Czy to metoda „lepsza” niż te, które wspomniałem wyżej? Wątpliwe. Ale wydaje się najmniej skomplikowana i inwazyjna.