Béton brut

Kanał subskrybcji Napisz do mnie…

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”.

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.

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.

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

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.


Światy wytworzone

Kiedy usłyszałem jak dziecko koleżanki z pracy relacjonuje fantastycznego gola strzelonego przez Christiano Ronaldo ucieszyłem się w duchu. Było lato z turniejem piłkarskim i myślałem, że młody człowiek siedzi i ogląda zmagania na boisku, jak i ja. Nie mając specjalnego talentu do rozmawiania z dziećmi (choć kiedyś byłem dzieckiem jeśli wierzyć zdjęciom, pewnie zapomniałem co one robią w wolnym czasie) zagadałem do niego o inną spektakularną bramkę. Popatrzył na mnie podejrzliwie, coś burknął i wycofał się w kierunku matczynego biurka.

OK, nie wiem czego się spodziewałem, dyskusji o funkcji raumdeutera we współczesnym, ofensywnym futbolu? Nic to. Po pewnym czasie, łowiąc jednym uchem strzępki monologów odkryłem powód naszego braku porozumienia.

Ja mówiłem o Ronaldo z krwi i kości, a on mówił o jego podobiźnie zbudowanej z poligonów, którą kieruje grając w FIFĘ na konsoli. I to on jest tym prawdziwszym, choć w rzeczywistości to tylko faksymile Portugalczyka.

Trochę się zeźliłem, a w brzuchu zrobił mi się koktajl z ogórków konserwowych i jogurtu. Raz, że nie kumam bazy. Dwa, że jak tak można żyć z fałszywym obrazem kogoś! Kiedy wyszedłem z biura nie mogłem przestać myśleć o tym, jak dziwny to świat w którym można żyć kompletnie w oparach cyfrowych fatamorgan. Winiłem oczywiście współczesność, rozpasany konsumeryzm i głupotę dzieci, które grają w gry, których nawet nie trzeba wczytać z taśmy.

Im dłużej jednak nad tym myślałem tym bardziej dobijała się do mojej świadomości myśl w tle. I szeptała cicho Newcastle United… Newcastle United… — ale co, Newcastle? Ach.

Odkryłem nagle, czemu tak bardzo mnie ta myśl gnębiła od rana.

Przez kilka lat moim życiem zawładnęła gra komputerowa: Championship Manager (teraz: Football Manager). Był to symulator ekonomiczno-sportowy, który pozwalał się wcielić w rolę managera jednego z klubów angielskiej ligi. Gra z daleka wyglądała jak arkusz kalkulacyjny i nikt w temacie nie mógł zrozumieć czemu biały pasek wypełniający się po prawo powoduje, że wpadam z szału w ekstazę by zaraz wsiąść w pociąg powrotny do szału. Jednej wiosny postanowiliśmy z moim boiskowym kolegą że już się wystarczająco nauczyliśmy w tym roku szkolnym i możemy wziąć dwa miesiące wolnego i poświęcić się rzeczy, która jest na serio ważna: graniu od rana w Championship Managera.

Od razu był problem. Obydwaj chcieliśmy prowadzić Manchester United, który był tytanem piłkarskim tamtych lat. Kto by nie chciał być Fergusonem podwórka? Rzuciliśmy monetą i wyszło, że przegrałem. Musiałem wybrać inną drużynę. Mając nikłe pojęcie o angielskiej piłce postanowiłem przyjąć następującą heurystykę: Machester. United. Manchester City jest dziadowskie. Więc to nie pierwszy człon decyduje o sukcesie w piłce. W takim razie jasne jest, że to United jest sygnałem „to dobra drużyna”. Wybrałem więc Newcastle United.

I zaczęliśmy grać. Po dwóch miesiącach okazało się, że nasze szkoły nie rozumieją potrzeby walki o ligowe tytuły i obaj zostaliśmy na tym samym roku. Co nam wybitnie pasowało, bo to znaczyło, że mamy dwa miesiące wakacji i dodatkowo mamy już wszystkie książki i zeszyty, więc nie musimy się nawet przygotowywać! Lekko 4 miesiące luzu, świetnie.

Jak pisałem wcześniej granie w Championship Managera wymagało wyobraźni. Cała gra to tylko kolumny cyfr i trochę tekstu. Ludzka natura lubi historie, uczłowieczaliśmy więc te ciągi znaków, dorobiliśmy się własnego zestawu przesądów, mieliśmy drużyny z którymi nie lubiliśmy grać. Wspominaliśmy ciekawe momenty w naszych karierach. Żyliśmy w alternatywnej rzeczywistości, gdzie nie pojedynczy piłkarz, a cała drużyna, była ofiarą naszej nieskrępowanej fantazji.

Ponieważ byłem bramkarzem szczególnie urzeczywistniałem w mojej głowie wyczyny mojego bramkarza Srok1. Któregoś dnia wyznaczyłem go do strzelania rzutów karnych. Strzelił. Dla żartu zostawiłem go jako egzekutora. I strzelił następnego. I następnego. A jego legenda rosła. Kiedy chciał zakończyć karierę próbowałem przerobić stan gry tak żeby został. Co się nie udało.

Przez lata myślałem o nim, o Hopperze, moim strzelającym karne bramkarzu Newcastle z rozrzewnieniem. Tyle wspaniałych wspomnień. I gdy odbiłem się od katalizującego incydentu z Ronaldo i synem koleżanki zdałem sobie sprawę, że… ja nie wiem nawet jak Hopper wygląda. Doszedłem do domu, usiadłem do komputera. OK, jest, widzę. Strasznie mało coś o nim. I w trzecim linku na Google czytam, co następuje.

Hooper started with a clean sheet against West Ham. But things soon declined as he was beaten by a long-range last- minute free-kick by Matt Le Tissier in a 2-1 loss.

Newcastle United’s Worst XI: Worst goalkeepers

Okazał się, że Hopper nigdy nie był bohaterem, nigdzie, poza moją głową. Był kiepskawym bramkarzem, który wyleciał z startowej jedenastki i praktycznie nigdy niczego nie dokonał. Ja się oburzyłem na kogoś, kto strzela bramki w FIFA, a sam mam 12 sezonów fałszywych wspomnień, które sobie opowiedziałem patrząc w kilka rubryczek. I kiedy on symuluje człowieka sukcesu odnosząc sukces, ja wymyśliłem człowieka sukcesu z piłkarskiego nikogo.

Kto jest bez winy niech pierwszy rozpocznie grę długim wyrzutem.


  1. „Sroki” to przydomek Newcastle United 


Szybkie życie

W Internecie bulgocze mem o tym, jak to w czasach zarazy mądrzy ludzie dokonali wielkich czynów i jakie ważne dzieła wyprodukowali. Oczywiście, jak w każdym inspirational porn pomijane są pewne fakty. Na ten przykład twórcy wspaniałych rzeczy nie wdzierali się na intelektualną scenę, a byli na niej już od dawna. Albo to, że nie musieli się w większości przejmować czynszem, zamkniętą szkołą, ani też doświadczać pierwszy raz zdalnej pracy.

Ja celuję dużo niżej. Każdemu jego dzieło w miarę możliwości.

Znudzony i niechętny pracy kręciłem się tu i tam, szukając ciekawego zajęcia. Wyciągnąłem stare numery „Młodego Technika”. Przeczytałem kawałek tekstu o tym jak działają świece zapłonowe. Nie było ognia w moim sercu. Wyciągnąłem Tołstoja, ale na pierwszej stronie było od razu pięć długich, dwuczłonowych rosyjskich nazwisk i wiedziałem, że nie ma szans żebym się odnalazł w tym bez tablicy korkowej i czerwonych sznurków do utworzenia relacji pomiędzy bohaterami historii.

Zastanawiałem się jak wygląda miasto. Od tygodnia wyszedłem z domu trzy razy. Na 5 minut. Dokupić alkoholu i jajek. Jajka jem na śniadanie, alkohol na kolację. Te dumania przypomniały mi o zapomnianej dziś instytucji „publicznych webcamów”. Kiedyś były bardzo popularne, ludzie oglądali obce miasta, kurze fermy, małpy, psy i co jeszcze komu wpadło do głowy. Wpisałem więc frazę w wyszukiwarkę i po chwili widziałem swoją okolicę. Popatrzyłem chwilę jak pan chodzi z miejsca w miejsce, zaparkował samochód, a później odjechał. Pan, śledzony nieustępliwie przez śmieciarkę na światłach, opróżniał kubły. Świat istniał, choć nie wyglądał ciekawie.

Pomyślałem, że mógłbym sobie rzucić to wideo na mały, dziesięciocalowy telewizorek, który stoi w kącie mojego biurka i zabawia mnie wyświetlając anime z lat 80 kiedy pracuję. Stworzyłbym sobie wirtualne okno na ulicę.

Ostatecznie, gdzieś tam pod spodem, jest pewnie jakiś strumień wideo, który można zawinąć.

Poszedłem sprawdzić i oczywiście, jest jakiś. Po pierwsze lista M3U, po drugie powtarzający się cykl fragmentów wideo. Dla testu skopiowałem jeden z linków i podałem do wget. Coś się ściągnęło. mplayer odtworzył 2 sekund wideo z kamery. OK, czyli to tak działa. Wideo jest serwowane w tej serii plików i po osiągnięciu ostatniego, 92 fragmentu, lista zawraca do pierwszego, oznaczonego 42.

Dobra, a czy da się je jakoś seryjnie ściągnąć? Znaczy, na pewno się da, ale tak żebym potem mógł coś z tym zrobić? Otworzyłem nową powłokę terminala i wydałem klasyczne zaklęcie mkdir, git init, vi.

Wpierw wymyśliłem bardzo skomplikowany sposób pobierania tego, z wątkami, sprawdzaniem ETag i kto wie, co jeszcze. A potem uznałem, że głupia metoda jest równie dobra, a doprowadzi mnie do sukcesu szybciej.

Czyli tak:

  1. Wezmę wszystkie kawałki klipów w momencie odpalenia
  2. Zapiszę je sobie na boku
  3. Zobaczę ile czasu mi to zajęło i odejmę od maksymalnej długości wszystkich klipów
  4. go to 1
import requests # klient HTTP
from time import sleep # chcemy pauzować

# wpisany na twardo adres z którego będę pobierał informacje
URL = 'https://cdn-3-go.toya.net.pl:8081/kamery/lodz_piotrkowskaschillera_0{}.ts'

# formad do zapisywania, index poprzedzony dopełnieniem 12 zer
OUTPUT = 'output/{:012}_frame.mpg'

""" Żeby się było łatwiej kręcić, wartości [42…91] w liście """
frames = range(42, 92)

idx = 0
while True:
    # Cała lista otwarzania ma (92-42)*2 sekund 
    rotation_time = len(frames) * 2

    #Kiedy zaczynamy proces
    start_time = datetime.now()

    for frame in frames:
        print("Grabing {}".format(frame))
        # Klasyczny HTTP GET / i zapisanie pliku docelowego
        response = requests.get(URL.format(frame))
        if response.status_code == 200:
            with open(OUTPUT.format(idx), 'wb') as f:
                f.write(response.content)
            idx = idx + 1
    # Jak przelecieliśmy wszystkie ramki to czekamy resztę sekund, aż 
    # się wszystkie podmienią
    after_downloading = datetime.now()
    remaining_seconds = rotation_time - int((after_downloading - start_time).total_seconds())
    print("Clips fetched, sleeping for {}".format(remaining_seconds))
    # …i do łóżka
    sleep(remaining_seconds)

Udało się za pierwszym razem. Pokombinowałem jeszcze z nazwami i takimi tam, ale wyglądało na to, że całość ściągnęła się bez problemu. No dobra, ale co z tym teraz zrobić? Chwilowo nie miałem pomysłu, więc sklonowałem repozytorium na lodówkową RaspberryPi i pozwoliłem się jej kręcić, naciągnąć mi nieco danych.

Minął czas, a ja wymyśliłem. Zrobię tzw. timelapse czyli przyśpieszone wideo z źródłowych fragmentów. Mam w vimwiki całą stronę poświęconą rozmaitym zaklęciom, którymi można przymuszać ffmpeg do robienia fantastycznych rzeczy.

Kiedyś spędziłem wieczór na brzegu zalewu żeby zamienić 6 minutowy filmik z zachodu słońca w taki, który byłby ustabilizowany, krótszy i jeszcze miał muzykę. Wyzwanie: tylko przy użyciu połączenia SSH do domu. Wyszło OK, ale nie spektakularnie.

Nie było sensu zaprzęgać do tego Pythona, wsadziłem całość w prosty skrypt Basha. 1

#!/bin/bash

# Wczytaj z katalogu output wszystkie pliki *.mpg
for file in output/*.mpg ; do
    # Weź obecną nazwę, utnij ją przy kropce, dodaj png
    new_file=`echo $file | cut -d. -f1`.png
    echo $new_file
    # Weź pierwszą klatkę animacji i zapisz pod nową nazwą
    ffmpeg -i $file -vf "select=eq(n\,0)" -vframes 1 $new_file
done

# Zakoduj nowopowstałe klatki w mp4/h264 żeby się przeglądarki nie czepiały
ffmpeg -pattern_type glob -i 'output/*.png'  -an -vcodec libx264 -pix_fmt yuv420p -profile:v baseline -level 3 out.mp4

Po kilku testach postanowiłem, że osiągnąłem znośny efekt (mimo kilku momentów w których uzyskałem duplikaty serii klatek. Mogłem usunąć to post factum ale jak mówił Bob Ross, “There are no mistakes, just happy accidents“), wysłałem wszystko na RaspberryPi i postanowiłem dać się całości kręcić przez noc.

Wysłałem jeszcze e-mail do mojego przyjaciela Łukasza żebrząc o jakiś utwór muzyczny z mojej ulubionej płyty jego projektu, Coffee Sounds. Na moje szczęście zgodził się, za co chcę mu jeszcze raz podziękować.

Wstałem o piątej, zebrałem 17200 klatek i oto przed Wami efekt bezcelowej, nocnej dłubaniny. Łódź, Piotrkowska, Pasaż Schillera. Od 22:30 do 8:00.

  • :15 zaczyna padać deszcz, ulice się świecą odbitym światłem latarni
  • :37 „Do Poloneza? Ale Panie Władzo, ja nie tańczę”
  • 3:15 wschód słońca

Te, zdecydowanie zbyt rzadkie, momemty w moim życiu gdy zamieniam „czy da się?” w „da się” przy pomocy śliny, mchu i oglądania problemu przez palce sprawiają mi zawsze najwięcej radości.

Polecam Wam zaprzęgać komputery do bezużytecznej, kreatywnej pracy. Komputer jako odpalarka do przeglądarki to takie marnotrastwo nieomal nieograniczonej mocy.

Czas szybciej płynie, gdy dłubiesz. Lokatorzy więzień próbujący wykonać podkop też Wam to powiedzą.


  1. Potem trochę pozmieniałem rzeczy, całość dostępna jest w repozytorium git 


ttyd

W dzieciństwie jednym z moich ulubionych formatów kawałów był ten o magicznej istocie, która spełnia życzenia w sposób dosłowny, obracający pragnienie petenta w jego nieszczęście.

Żołnierz poszedł łowić do pobliskiej rzeki i zdziwił się, gdy dyndająca na końcu żyłki ryba przemówiła: „Oszczędź mnie, a spełnię Twoje życzenie”. Długo się nie zastanawiał i powiedział rybce: „Chcę być odznaczony ważnym orderem”. Puf! Gdy dym — jasny sygnał spełnionego zaklęcia — opadł, żołnierz zauważył, że stoi w okopie. Po lewej flance przedzierają się nieprzyjaciele, po prawej to samo. A frontem czołgi i karabiny maszynowe. Słyszy hasło „Naprzód!” i ściana kamratów popycha go do walki. Biegnąc myśli, „No kurwa, pośmiertny dała”.

Należy pamiętać żeby uważać czego się pragnie. Spełnienie może być gorsze niż pragnienie. Bo weźmy na przykład jedno z pragnień w sferze technologii: żeby napisać aplikację raz i odpalać ją na wielu różnych systemach. Przez dekady podejmowane były różne próby. A to systemy, które są kompatybilne na poziomie źródeł w stopniu wystarczającym by proces portowania był niezbyt bolesny (C/PM, POSIX), albo platformę sprzętową (MSX, czy potem x86), albo maszyny wirtualne i bytecode (Z-Machine czy JVM).

Jak się to wszystko powiodło? Trudno powiedzieć, to sytuacja jak z za krótką kołdrą. Jednym marzł nos, innym stopy, ale ogólnie zgadzano się, że kołdra jest dobrym pomysłem i któregoś dnia uda nam się uszyć taką o zadowalającej długości.

I wtedy ktoś poszedł wyłowić tę złotą rybkę siecią. I rybka dała nam uniwersalną platformę aplikacji: przeglądarkę internetową.

Ludzie często błędnie rozumieją ewolucję, myślą, że obecny stan wynika z jakiegoś planu, a nie tylko wypadkowych czynników, które promują jakąś właściwość nad inną. Tak samo w przypadku przeglądarki jako platformy aplikacji rzeczy nie rozwijały się pod okiem bogów, a były wypadkową dostępności, pewnej wolności, ceny i kilkuset sprytnych gości, którzy ciągnęli kołdrę w kierunku własnym, czyli słusznym. Tak jak w przypadku ewolucji organizmów prowadziło to czasem do dziwnych rezultatów: nasze oczy widzą świat do góry nogami i potem kradną cykle mózgu na obracanie obrazu, jest też JavaScript.

Nie da się ukryć, że jestem internetowym sceptykiem. To naturalna droga, którą przebywa każdy entuzjasta, gdy okazuje się, że „jego dziecko” pali za szkołą, przynosi same jedynki i nie chce zostać filozofem etyki medycznej. Głębokie rozczarowanie równe pokładanych nadziei.

Większość dnia, a już z pewnością jego produktywną część, spędzam ślepiąc w terminal tekstowy. Znajduję spokój w środowisku, które pokornie czeka mrugając na mnie zalotnie kursorem, aż powiem mu czego chcę. Proste aplikacje, które komunikują się tekstem. Kontrola, automatyzacja i surowa estetyka. I prawie ezoteryka, którą ciężko jest wytłumaczyć ot, tak.

A ten przydługi wstęp ma służyć wyłącznie temu żebym Wam mógł powiedzieć o moim odkryciu, które cieszy me serce i być może ucieszy Wasze. Jest to ttyd, serwer podający terminal przez przeglądarkę.

ttyd to serwer napisany w C, który serwuje jednostronicową aplikację opartą o xterm.js i WebSockety. Jest trywialna w użyciu i działa spektakularnie dobrze. Próbowałem praktycznie wszystkiego, czego używam na terminalu, nawet najbardziej fikuśnych aplikacji. Wystarczy wpisać na terminalu:

ttyd -p 3000 aplikacja

…i już na http://localhost:3000 mamy uruchomiony wirtualny terminal z którego możemy nią operować. Wspiera SSL, BASIC AUTH, autoryzację certyfikatami (bardzo przydatne w pewnych okolicznościach), tryb „tylko do odczytu”, pojedyncze i wielokrotne sesje.

Po co?! O dziwo znalazłem wiele zastosowań!

Po pierwsze używam tego do moich różnych eksperymentów z RaspberryPi. Nie wszyscy mają pod ręką klienta SSH i wystarczająco samozaparcia by zmieniać konfigurację, ale wystarczy, że powiem im „kliknijcie na ten adres i wpiszcie informacje”, podłączę skrypt w powłoce pod ttyd i voilà. I tak, mógłbym napisać webaplikację, ale zapewniam Was, że nawet używając mikroframeworku zejdzie mi dłużej dłubiąc HTML niż kilka razy wywołać input().

Po drugie, sytuacja podobna, często czytam logi używając tail -f, w połączeniu z trybem „tylko do odczytu” mogę go udostępnić ludziom, którzy mają może potrzebę zerknięcia, ale nie muszą mieć dostępu do systemu.

Po trzecie, to bardzo dobrze zbudowane narzędzie i strasznie mi się podoba. To będzie mój finalny i rozstrzygający argument.

A teraz czas na część wizualną dla tych, którzy przebrnęli przez te ściany tekstu. Uruchomię ttyd, które uruchomi browsh czyli terminalową przeglądarkę, która używa Firefoksa jako silnika, w Firefoksie. Pamiętajcie, „…bo mogę” to nie powiedzonko, to styl życia.


Klik, klik. Dziadek znikł.

Robiła się późna niedziela, a to znaczyło, że muszę powoli wyrwać się z ciszy otaczających mnie gór i wrócić na łono ogarniętego świątecznym amokiem miasta. Ciągnąłem więc nogę za nogą i oddawałem się mojej pasji oglądania lokalnego życia. Natrafiłem na przykład na szyld, który nie tylko oferował wideofilmowanie, ale także usługę przegrywania kaset VHS na płyty DVD. Jak przepisywanie kamiennych tablic na papirus. To zawsze napełnia mnie radością, że mogę uciec w miejsca, gdzie technologiczny postęp jest na chorobowym.

Jak większość górskich dróg ta też była pełna dzikich zakrętów, a przy jednym z nich zauważyłem kolejny szyld: „zakład pogrzebowy”. Uśmiechnąłem się do siebie: taki ostry zakręt i zakład pogrzebowy to doskonałe miejsce na skecz o tym jak klient dosłownie sam stuka do drzwi biznesu.

Pokonałem zakręt i co widzę na jego końcu. Drugi zakład pogrzebowy, po przeciwnej stronie ulicy. Jak stacje benzynowe obsługujące wielopasmową autostradę. To spowodowało, że rozbudowałem moje gdybania: jak dwa zakłady pogrzebowe znajdują wystarczająco biznesu dla osady, która ma cztery tysiące dusz?1

Wykluczając scenariusz taniego horroru w którym oba zakłady pogrzebowe wynajmują morderców, którzy są kołem zamachowym biznesu, zacząłem gdybać jak funkcjonuje tak specyficzny biznes w obliczu konkurencji. Czy drzwi do gabinetu lokalnego dyrektora szpitala zamykają się non-stop za właścicielami tych zakładów, trzymających pod pachą coraz to wykwintniejsze butelki alkoholi? A może kosze owoców.

I jak ja, adept współczesnego świata, mógłbym im pomóc w polepszeniu „lejka konwersji” trupa w przelew.

Na początek należy zacząć od rzeczy prostych. Reklama na Facebooku dla targetu, zgromadzić marketingowe dane o umieralności, posegregować w grupy docelowe: ludzie, którzy umierają normalnie, ze starości. Ludzie, którzy konsumują alkohol aby zapomnieć. Operatorzy maszyn rolniczych zakończonych ostrzami. Zaoferować zniżki dla tych, którzy wybiorą usługi zanim utracą zdolność decydowania.

Potem trzeba przejść do argumentów cięższych. Zakupienie danych o zdrowiu i nawykach od firm, które inwigilują obywateli w ramach „darmowych usług”. Od producentów elektronicznych krokomierzy przez producentów urządzeń podsłuchowych, które potrafią powiedzieć jaka jest pogoda, co pozwala inwigilowanym na zaprzestanie wyglądania przez okno. Tak uzyskane informacje, wielka-mała data, nadaje się idealna do wsadzenia do paszczy modeli sztucznej inteligencji. Wyłuskane dane trzeba skorelować z już istniejącymi informacjami o denatach i wejść w biznesowy układ z okolicznymi sklepami aby promować zachowania, które są denatogenne.

Hasła jak „Na co ci fura, pij denaturat”, „Siała baba mak i zrobiła kompot dla dzieci” oraz „Bądź eko, usuwaj odpady, pal oponami” powinny pomóc we wzroście.

Nie można też zapominać o klientach drugiego stopnia, tj. rodzinie i bliskich, którzy pozostają po zmarłym. Mobilna aplikacja pozwalająca na zatrudnienie aktorów w rolach „płaczek”, wybierania im strojów i ról, zatrudnienie blogera do napisania przemowy kaznodziei, nagrobek z NFC pozwalających odhaczyć się rodzinie wraz z tabelą wyników. Mikropłatności za duszę przez BLIK. Streaming dla tych, którzy wyjechali za chlebem do San Francisco.

To wszystko zrodziło się w mojej głowie jako cyniczna obserwacja bezdusznej maszyny, która pożera ludzkie interakcje i nas samych, dlatego też jestem pewien, że ktoś właśnie siada do pisania biznesplanu i wysyła e-maile do znajomych kapitalistów wysokiego ryzyka. Do tej osoby: proszę mi odpalić z 5% żebym mógł dłużej siedzieć w lesie i snuć okropne wizje. Gwarantuje, że mam jeszcze paskudniejsze pomysły, które da się zrealizować.


  1. Ponieważ wróciłem znów w to samo miejsce udało mi się znaleźć trzeci zakład pogrzebowy. Skala przemysłowa. 


Mrygaj, mrygaj mała gwiazdko

Człowiek potrafi się nabawić kompleksów. Bez względu na wiek, dokonania czy stancję w życiu w głębi duszy wiemy, że dookoła są ludzie mądrzejsi, ładniejsi i lepiej poukładani. W mojej prywatnej księdze przewin i uchybień dodałem kilka lat temu paragraf pt. „nawet dzieci teraz robią rzeczy elektroniczne podłączone do Raspberry, a Ty może przeczytałeś kiedyś na Wikipedii opis SPI i tyle”.

Czułem się z tym po dwójnasób źle, że od elektroniki zaczęła się moja przygoda z byciem dziwakiem. Jak zapomnienie pierwszej miłości tak bardzo, że nie możesz przywołać jak miała na imię. I ta nękająca wątpliwość: może jej nigdy nie kochałem? A może nawet nie istniała?

Podczas grzebania na Allegro trafiłem na segment diod LED. Zagooglałem za symbolem i widzę, że ktoś już odwalił za mnie całą robotę i jestem jedno PIP-nięcie od wejścia w posiadanie działającego sterownika. Dziewięć nowych polskich złotych zmieniło ręce. Przyszła paczka. Otwieram. Jedyną dokumentacją załączoną do płytki był paragon fiskalny, a one zwykle niewiele pomagają w podłączaniu elektroniki. No trudno, zalogowałem się na Raspberry, która leży pod moim łóżkiem i powiedziałem poweroff.

Na szczęście dokumentacja biblioteki zawierała instrukcje podłączenia. Pomyliłem się tylko raz, co było spowodowane w większości przez moje grube pazury. Zainstalowałem biblitekę odpowiedzialną za gadanie do MAX7219 i sklonowałem repozytorium żeby mieć katalogów przykładów pod ręką.

I ruszyło! Lecą napisy, pięknie. Polałem sobie drinka żeby dołączyć do setek tysięcy równie uzdolnionych dzieci ze szkół podstawowych. Po krótkiej zabawie stwierdziłem, że przesuwanie tekstów niezbyt mnie cieszy, a nawet wywołuje przykre skojarzenia z <marquee>1 i szyldami reklamowymi. Przy matrycy 8x8 jest to trochę komiczne. Oczywiście będę indywidualnie zapalał piksele. Tylko jak? Wyniki wyszukiwań prowadziły do przykładów, które nie działają już w obecnej wersji. Ale przecież musi być jakiś sposób.

Zerknąłem do kodu źródłowego i oczywiście! Jest metoda display, która przyjmuje monochromatyczny obraz reprezentowany przez PIL.Image. A skoro tak, to mogę przecież od ręki zrobić obrazek i go wstawić.

x = randint(0, 7)
y = randint(0, 7)
image = Image.new("1", (8, 8))
image.putpixel((x, y), 255)

Wcisnąłem to do mojego skrawka kodu i zaświeciły mi się losowo diody. Czułem jak pnę się po drabinie kompetencji. Już widzę jak ze szczytu macha mi Wielki Elektronik. No to teraz trzeba zaprogramować jakieś obrazki. I tu stał się problem. Mam gust, ale nie mam talentu. Bez wątpienia należy ten problem zwalić na kogoś innego.

Napisałem więc „interpretator”, który potrafi zamienić tekst w obrazek i oddałem sprawę mojemu demoscenowemu przyjacielowi, thungowi. On akurat nie miał czasu, ale „narysował” mi ludka.

...**...
..*..*..
...**...
.******.
...**...
..*..*..
..*..*..
........

Prawdziwa sztuka!

Następnego dnia przybyłem na stadion siatkarek ełkaesu godzinę za wcześnie.2 To był dobry czas żeby zrobić z wcześniejszego kodu „format animacji”, tak żebym mógł wyprodukować serię obrazów z jednego pliku. Jak postanowiłem, tak zrobiłem i chwilę przed gwizdkiem sędziny miałem już gotowy prymitywny generator serii obrazków.

Wlazłem znów pod łóżko żeby odpiąć Jeżynę i zniosłem ją na biurko. Stosując metodologię Sir Copy’ego i Lorda Paste nawtykałem jeden kod w drugi.

I stało się. Eppur si muove, parabole tańczą, ludek skacze.

To prawie krępujące chwalić się takimi bzdurami, ale na serio byłem z siebie zadowolony. Nie tylko zabrałem się za coś od razu, ale nawet osiągnąłem wszystko co chciałem i nikt nie musiał nade mną stać i obijać kijem. Pomyślałem: zaskoczę wszystkich jeszcze bardziej jak napiszę notkę. Prawdziwy hat-trick zdziwienia.

Gdy żyjesz życie pełne Logiki Biznesowej, Formatów Wymiany Danych, Garbage In / Kłopoty Out, każda dioda LED świeci jak prywatne słońce, co budzi do życia florę i faunę, która żyje w mojej głowie.


  1. kiedy zagooglacie za <marquee> bo nie jesteście pewni pisowni zwróćcie uwagę, że górny status wyników wyszukiwania przesuwa się w dobrze znany sposób. 

  2. po ekscytującym meczu wygraliśmy 3:1 


Rodzina

Coraz częściej zauważam pełzający wolno, ale nieustępliwie, rozpad podstawowej komórki społecznej, którą jak wiemy jest rodzina. Ale i dalej, wygasającą potrzebę bliskości i czułości. Chińskie z dowozem, zdalna praca, anonimowe ruchaj-randki, a najbliższy kontakt to karta/terminal płatniczy.

I to wszystko jest prawda, ale czy trzeba z tego powodu załamywać ręce i wpadać głową do przodu w okopy konserwatyzmu?

Nie trzeba!

Wśród tysięcy głosów, szepczących wam do ucha słowa pełne lęku, ja niosę wam ukojenie. Narodziła się bowiem nowa forma rodziny, która uniknęła socjologicznej analizy i pierwszej strony prasy kolorowej. Forma rodziny, która może zaspokoić potrzeby wielu.

Zbudowania na zaufaniu i wolnorynkowa, ale też gardząca strukturą i płciami. Nowoczesna, niezbędna, sycąca.

Patrzę z dumą jak w biurach rodzą się nowe rodziny. Tu trzy, tam cztery osoby biorą się pod ramiona i mówią sobie szczerze: weźmiemy pakiety rodziny platformy streamującej seriale. Tam znów, jawnie i z podniesionym czołem, powstaje homoseksualny związek, gdzie chłopak może mieszkać z innym chłopakiem pod jednym dachem Spotify.

Wolna miłość (za niewielką opłatą) wreszcie przybyła.


Demonów okiełznanie

Internet jest jak ogrodzone płotem osiedle. Nowe, błyszczące, praktycznie wszyscy żyją tu na cudzym, a sąsiedzi są anonimowymi wałami do których w najlepszym wypadku czujemy zimną obojętność.

Ktoś non stop donosi też dzielnicowemu o wszystkich małych przewinieniach i szeptanych słowach, a on, zdaje się, zawsze ma kary nieprzystające do ich wagi. Mówią, że tylko dlatego nikt nie szcza na klatkach, co jest ceną wartą płacenia. Zwłaszcza, gdy płacą inni.

Ja? Ja jestem ostatnim rdzennym mieszkańcem tych regionów. A przynajmniej lubię tak o sobie myśleć, bo daje mi to poczucie godności. Jestem pasożytem tego ekosystemu, jedząc z jego śmietników i gdy nikt nie widzi, wygrażając pięścią w kierunku sączącego się z okien światła.

Tyle metafora.

Nienawidzę, gdy strony nie mają kanału wiadomości. Jeszcze bardziej, gdy mają, ale jest zepsuty przez miesiące i nikt nie reaguje na moje ponaglające e-maile donoszące o tej sprawie. Równie niedobrze jest, gdy strona, której zmuszony jestem używać, zakłada, że mój komputer jest identyczny jak ten suto opłacanych rozwijaczy. „U mnie nie tylko działa, u mnie nawet wygląda”, zdają się mi szeptać do ucha.

Ostatnim przykładem jest strona z ramówką w serwisie Eleven Sports. Dwa paski do przewijania, które zwykle wymagają indywidualnego masażu myszką aby ujawnić jakie drużyny kopiące piłkę mogę zobaczyć na żywo tego wieczoru. Każdego dnia czułem się z tym coraz gorzej, aż wreszcie postanowiłem, że zadaniem komputerów jest przetwarzanie informacji.

Napisałem więc mały serwis, który kradnie informacje, przetwarza je i zamienia w format wymiany informacji o kalendarzach.

Klik, klik, klik: Eleven Sports w ICS

Plik kalendarzowy wyświetlony w calcurse

Teraz mogę wreszcie żyć jak człowiek, nie muszę naciskać guzików na domofonie licząc, że ktoś mieszkający na osiedlu mi powie, kto gra.


Trzy kolory: seledynowy

Bywacie czasem nieszczęśliwi? Co wtedy robicie? Pijecie? Palicie? Snujecie się po zaułkach? Programujecie?

Ja robię wszystko powyżej, naraz. W ramach nieustającej akcji „im więcej myślisz, tym bardziej nie chcesz” znalazłem się w momencie, gdzie potrzebowałem dnia ucieczki od zgiełku zwykłego dnia. Zamiast iść do biura poszedłem zwiedzać, a podczas zwiedzania wpadł mi do głowy pomysł na zajęcie umysłu. Na Twitterze jest sobie taki bot, który produkuje — zabawnie nazywane — palety kolorów. Nazywa się toto colorschemer.

Oto przykład:

schemer

Myślę sobie: a gdyby napisał bota, który potrafi wyekstrahować kolory z załączanych na Twitterze obrazków tym samym doprowadzając do SKYNET-u? Mógłbym generować z nich arkusze stylów z deklaracjami, palety do GIMP-a, czy to tam.

Brzmi jak marnowanie czasu!

Konsumujemy

Zanim zaczniemy naszą podróż po obrazku musimy zamienić plik znajdujący się na dysku w kupkę informacji. Dla Pythona dostępna jest biblioteka Pillow zawierająca w sobie wszystkie potrzebne funkcje. Użyjemy jej aby uzyskać piksele, kolory oraz rozmiar obrazka.

Na boku Bardziej zaawansowani czytelnicy mogą się skrzywić, że piszę funkcje zawierające tylko return — normalnie używam takich funkcji aby ułatwić sobie odpluskwianie i obsługę błędów. W tym przykładzie nie chcę dodatkowo zaciemniać, więc pozostawiłem tak, jak jest, no i funkcje mają bardziej zrozumiałe nazwy niż oryginalne metody.

def load_image(filename: str):
    return Image.open(filename)

def get_pixels(image: Image):
    return image.load()

def get_bounds(image: Image):
    return image.getbbox()

I tak, w kolejności: load_image wczytuje obrazek z dysku, get_pixels zwraca piksele na których możemy dokonywać analizy, get_bounds zwraca cztery wartości, które określają obszar zajmowany przez obraz.

Kolory na ekranie

Ekran komputera możemy reprezentować jako dwuwymiarową płaszczyznę której każdy punkt reprezentuje para wartości X i Y. X odpowiada za oś lewo-prawo, a Y, odpowiednia góra-dół. Pozycje zaczynamy liczyć od lewa w prawo i od góry w dół. To znaczy, że miara koordynat (0, 0) to piksel znajdujący się w górnym, lewym rogu.

Jeśli obraz ma rozdzielczość 1980x1080 to jego prawy dolny róg znajduje się na (1979, 1079) gdyż liczymy od zera.

Pod każdym z tych punktów kryje się święta trójca, Zielony, Czerwony i Niebieski, składowe kolorów w systemie RBG.

Kolory w RBG są reprezentowane przez bajt, który to bajt może przechowywać wartości numeryczne od 0 do 255. Czyli jeden piksel to trzy bajty informacji przybite do jakiejś pozycji na ekranie. Gdybyśmy chcieli sobie wyobrazić bardzo mały kwadrat, który ma bok składający się z dwóch pikseli, to moglibyśmy zapisać te dane w następujący sposób:

square = (
             (255, 0, 0), (0, 255, 0),
             (0, 0, 255), (128, 128, 128)
     )

Kolory RBG

Skoro wiemy w jaki sposób otrzymamy dane, zobaczmy, z czym nam przyjdzie pracować.

Pierwszy krok: w którą stronę ciąć

Przykładowy obrazków

Wszystkie obrazki zamieszczane na koncie przychodzą w dwóch formatach. Kolory są ułożone góra/dół lub lewo/prawo. Wykrycie typu obrazka będzie naszym pierwszym zadaniem. Utworzymy sobie typ wyliczeniowy (enum) żeby było nam łatwiej czytać kod.

Nazwałem mój enum Gravity, bo wydawało mi się, że to dobra, wiele mówiąca nazwa. „W którą stronę «spadają» kolory. Kiedy usiadłem do tego tekstu stało się oczywiste, że dużo lepszą nazwą byłoby Orientation. Udowodniłem tym samym teorię, że nazywanie rzeczy w programowaniu jest sztuką trudną.

class Gravity(Enum):
    VERTICAL = 0
    HORIZONTAL = 1

Zastanówmy się, jak wykryć, czy powinniśmy badać kolory idąc z góry w dół, czy też idąc z lewa w prawo.

Jeśli weźmiemy piksel znajdujący się pod koordynatami (0, 0), a potem weźmiemy piksel znajdujący się w przeciwległym rogu (0, szerokość obrazka) to jeśli są one takie same, znaczy, że układ obrazka jest góra/dół, bo cała pierwsza linia jest jednego koloru! Proste! W przeciwnym przypadku obrazek zorientowany jest lewo/prawo, gdyż wiemy, że kolor w lewym rogu jest inny niż ten w prawym.

Jak wykryć kierunek

Zrobimy z tego funkcję, która zwróci nam typ „grawitacji”.

def detect_gravity(pixels, bounds):
    max_width  = bounds[2]
    max_height = bounds[3]

    top_left_corner = pixels[0, 0]

    top_right_corner = pixels[0, max_width - 1]
    bottom_left_corner = pixels[0, max_height - 1]

    if top_left_corner == top_right_corner:
        return Gravity.HORIZONTAL
    return Gravity.VERTICAL

Wszystkie te kolory

OK, wiemy już jakiego typu obrazek wczytaliśmy. Teraz naszym zadaniem jest wybranie unikalnych kolorów. Zrobimy to idąc po linii i zapisując znalezione kolory. Powinno być całkiem prosto, wystarczy wybrać kierunek, zwiększać licznik o jeden i zapisywać do tablicy rezultatów unikalne wartości RGB.

Zerknijmy na kod.

def extract_distinct_colors(pixels, gravity, bounds):

    idx = 0

    if gravity == Gravity.VERTICAL:
        max_travel = bounds[3]
    else:
        max_travel  = bounds[2]

    distinct_colors = []

    while idx < max_travel:
        if gravity == Gravity.VERTICAL:
            pixel = pixels[0, idx]
        else:
            pixel = pixels[idx, 0]
        idx += 1
        if pixel not in distinct_colors:
            distinct_colors.append(pixel)
    return distinct_colors

Ustawiamy indeks idx na zero, ustawiamy rozmiar boku, którym będziemy podróżowali zależnie od «grawitacji», tworzymy pustą tablicę na rezultaty. Następnie kręcimy się aż do wyczerpania boku i sprawdzamy, czy właśnie odnaleziony piksel (dokładniej, trójca jego kolorów) jest już w distinct_colors, jeśli nie ma, dodajemy. Po zakończeniu operacji zwracamy zawartość tablicy.

Odpaliłem kod i wszystko działało, może nawet za dobrze, bo otrzymałem piętnaście kolorów, gdy spodziewałem się trzech. Dałem się nabrać swoim starym oczom, ale też udało mi się zapomnieć o faktach dotyczących obrazków w Internecie: kompresji. Jeśli popatrzymy na ofiarę naszej inspecji będziemy jasno widzieć (dosłownie) trudne do wyodrębnienia wahania w kolorze. Wahania, które ten naiwny kod, który szuka tylko unikalności, dokłada do listy. I dobrze robi, bo są to unikalne kolory, ale nie to chcieliśmy uzyskać.

Wiele kolorów w jednym pasku

Co teraz? Podglądanie obrazka pod lupą upewniło mnie, że te przekłamania w kolorze występują w niewielu miejscach, głównie tam, gdzie spotykają się dwa różne kolory. Rozsądnym sposobem byłoby liczenie ilości wystąpień. To pozwoli nam odrzucić sieroty po kompresji. Zmodyfikowałem więc kod w następujący sposób: dodałem occurance_counter, który zawiera liczniki wystąpień danego koloru. W bloku try…except sprawdzam w jakim miejscu w liście znajduje się obecnie odkryty kolor, a jeśli się nie znajduje (co podniesie wyjątek ValueError na metodzie .index()) znaczy, że widzimy go pierwszy raz. Tym razem z funkcji zwracamy dwie wartości: listę kolorów oraz ich liczniki.

def extract_distinct_colors(pixels, gravity, bounds):

    idx = 0

    if gravity == Gravity.VERTICAL:
        max_travel = bounds[3]
    else:
        max_travel  = bounds[2]

    distinct_colors = []
    occurance_counter = {}

    while idx < max_travel:
        if gravity == Gravity.VERTICAL:
            pixel = pixels[0, idx]
        else:
            pixel = pixels[idx, 0]
        idx += 1

        try:
            found_at_index = distinct_colors.index(pixel)
            occurance_counter[ found_at_index ] = occurance_counter[ found_at_index ] + 1
        except ValueError as e:
            distinct_colors.append(pixel)
            occurance_counter [ distinct_colors.index(pixel) ] = 1
    return (distinct_colors, occurance_counter)

Teraz muszę dodać tylko funkcję, która użyje obu tych informacji i zwróci mi n najczęściej występujących kolorów. Muszę przyznać, że byłem tu już trochę zmęczony, siedziałem na ławce w ciemnym parku, offline, paląc papierosy. Dlatego funkcja filter_top_entries nie jest może najbardziej przyjazna dla oczu początkujących, dlatego rozłożę ją może na czynniki pierwsze.

def filter_top_entries(count, distinct_colors, occurance_counter):
    filtered = sorted(occurance_counter.items(), key=lambda x: x[1], reverse=True)[0:count]
    return [distinct_colors[ x[0] ] for x in filtered]

Pierwszym paraemetrem jest liczba elementów, które chcemy uzyskać, dwa pozostałe to produkt extract_distinct_colors.

occurance_counter zawiera dane w następującym formacie:

    {
      '0': 12,
      '4': 1,
      '2': 34,
      []
    }

Indeksem w tym słowniku jest pozycja koloru w distinct_colors, a jego wartością jest liczba wystąpień. W Pythonie słownik posiada metodę .items(), która zwraca pary elementów, czyli gdybyśmy użyli jej na tym przykładowym kodzie, otrzymalibyśmy ( ('0', 12), ('4', 1), ('2', 34)). To właśnie przekazujemy do sortowania. Ale sorted() nie wie jak posortować dwuelementową listę. Dlatego też w parametrze key podajemy kawałek kodu, który wskaże jaki element z tej listy jest parametrem, który nalezy posortować. Pod indeksem 0 znajduje się pozycja koloru, pod indeksem 1 znajduje się liczba wystąpień. x: x[1] znaczy „do sortowania użyj ilości wystąpień, które znajdziesz w liście na pozycji pierwszej.

Ponieważ sorted() domyślnie sortuje od najmniejszej do największej musimy też poprosić o odwrócenie tego zachowania, gdyż szukamy najczęściej występujących kolorów. Do tego właśnie służy parametr reversed=True.

Produktem sorted() jest lista, więc możemy na niej użyć pythonowej składni do przycinania list, w tym wypadku [0:count] zwróci nam tylko fragment posortowanej listy do ilości podanej w pierwszym parametrze.

I to jest pierwsza linia. ;-)

Python posiada wygodną składnię do „kompresowania” wyrażeń normalnie zamykanych w for, to właśnie robi druga linia. Można ją przeczytać „dla każdego elementu w filtered, które uzyskaliśmy z sorted() weź element pod indeksem zero, który jest indeksem koloru na liście «unikalności» i zwróć to wszystko jako tablicę”

Alternatywnie możnaby to zapisać jako:

results = []
for x in filtered:
    results.append(distinct_colors[ x[0] ])

I już! Teraz powinniśmy mieć możliwość uzyskania trzech najważniejszych kolorów!

Składanie tego wszystkiego do kupy

Teraz możemy przetestować wszystko razem. Normalnie nie pisze się kodu testującego bezpośrednio w bibliotece, ale… wiecie, jak to jest. Zrobiłem sobie listę obrazków skradzionych z Twittera, wsadziłem je do listy i dla każdej z nich wywołałem wszystkie, dyskutowane wcześniej, funkcje.

Dopisałem jeszcze to_hex_expression, które zamienia RGB w znany nam dobrze format heksadecymalny używany w programach graficznych oraz CSS.

test_cases = [
    'test-cases/Dk82gZuVsAAcGho.jpg',
    'test-cases/Dk666IVUUAALxRx.jpg',
    'test-cases/Dk7kG4qU0AAJ5RL.jpg',
    'test-cases/Dk8oxdUVAAY6-JY.jpg',
    'test-cases/Dk9EPPVV4AA0obD.jpg',

]

from writers import to_hex_expression

for test in test_cases:
    print()
    image = load_image(test)

    bounds = get_bounds(image)
    pixels = get_pixels(image)

    gravity = detect_gravity(pixels, bounds)

    distinct_colors, occurance_counter = extract_distinct_colors(pixels, gravity, bounds)
    colors = filter_top_entries(3, distinct_colors, occurance_counter)
    for color in colors:
        print(to_hex_expression(color))

A oto rezultat:

test-cases/Dk82gZuVsAAcGho.jpg Gravity.VERTICAL
#446bae
#a10499
#35530b

test-cases/Dk666IVUUAALxRx.jpg Gravity.HORIZONTAL
#fcf779
#77ab56
#1fa874

test-cases/Dk7kG4qU0AAJ5RL.jpg Gravity.VERTICAL
#9eff00
#ff5c01
#cc406f

test-cases/Dk8oxdUVAAY6-JY.jpg Gravity.HORIZONTAL
#7f8f4e
#aca588
#ff6bb5

test-cases/Dk9EPPVV4AA0obD.jpg Gravity.VERTICAL
#24ff29
#1fb47a
#4a5d98

Trzy kolory „wyssane” z obrazka. Pełen sukces, dzień zmarnowany, wszyscy są szczęśliwi. Niestety, nie dotarłem do momentu w którym nauczyłbym kod łażenia „osobiście” na Twitter i podkradania obrazków, gdyż skończył się mi dzień.

Jeśli ktoś z czytelników uważa, że jest sens napisać drugą cześć, gdzie wpadlibyśmy grabić via API to można mi zostawić e-mail.

Przepraszam też jeśli ten tekst był zbyt chaotyczny i/lub bezużyteczny. Próbuję pobić prokrastynację przez brute force. Repozytorium z kodem jest dostepne na bitbucket, bronikowski/kaleidoscope.


Palec w oko

Homo erectus, homo sapiens, homo vatis1. Człowiek, co powstał z kolan, pomyślał po to, by opowiadać historie z dużego i małego „ha”. Człowiek z natury chce się wygadać, a czasem nawet chce być wysłuchany, ale głównie gadać.

Opowiadanie historii demokratyzowało się przez cały nasz czas na tej planecie. Od garstki liderów religii tłumaczących początek świata i bogów, aż po miliony użytkowników sieci społecznościowych z których wielu tłumaczy, jak świat się skończy i kto (zwykle „Oni”) się do tego przyczyni.

Gdzieś pomiędzy teraz a wtedy istniał świat w którym dostęp do technologii był ograniczony, ale ludzie nadal chcieli gadać. Był to świat w którym komputery osobiste były nadal zabawkami, a obliczeniowych mięśni dostarczały systemy UNIX-owe, popularne głównie w instytucjach naukowych, militarnych i uniwersytetach.

Każdy pracownik i student posiadał swoje konto, które było centrum cyfrowego życia. To tu przychodziły e-maile, tu kompilowało się oprogramowanie, tu odpalało aplikacje. Nic dziwnego, że katalogi użytkowników znajdowały się na partycji nazywanej tradycyjnie /home, był to prawdziwy dom dla e-bytów.

Ktoś w 1977 wpadł na pomysł protokołu, który pozwalałby „zapytać” systemu o fakty dotyczące danego użytkownika. Kiedy ostatnio był zalogowany, a jeśli jest, jak dawno dotknął klawiszy, jaki jest najnowszy e-mail czekający nań w skrzynce, kiedy ostatnio czytał pocztę, jak się nazywa i kilka innych, zbytecznych rzeczy.

Protokół ten został nazwany finger.

Informacje uzyskane tą drogą wydają się być trochę dziwne, ale jeśli weźmiemy pod uwagę, że „wsadzało się palec” w konto kolegi lub koleżanki z pracy/studiów, wiedza o tym, czy są przy terminalu i czy czytali już pocztę od czasu, gdy wysłaliście e-maila jest całkiem użyteczna.

Finger działał też w Internecie, gdy ten stał się faktem, człowiek mógł dla własnej frajdy dziabać paluchem znanych ludzi. No, znanych ludzi, którzy mieli konta na maszynach UNIX-owych, choć nie wiem, kto chciałby znać innych.

Co to ma jednak wspólnego z moim wstępem o potrzebie wygadania się? Finger czytał też dwa pliki z katalogu domowego użytkownika: .project i .plan.

W zamyśle miało to pomóc w organizacji pracy, gdzie .project opisywałby nasze długoterminowe działania, a .plan byłby zdaniem odpowiadającym na pytanie „co dziś robisz?”.

Niektórzy ludzie używali tych dwóch plików zgodnie z przeznaczeniem, związani obowiązkiem służbowym lub kompletnym brakiem poczucia humoru. Inni wsadzali do .planu tyrady o jedzeniu na stołówce, żarty, cytaty z książek, matematyczne dowody o wyższości Star Treka nad Star Wars i wszystko, co przyszło im do głowy.

Homo vatis1 nie zrodziło się wraz z erą Facebookiem, MySpace czy Twittera. Jeśli dacie ludziom możliwość napisania zdania, to znajdą się natychmiast ludzie piszący zdania ważne, zabawne i irytujące. Oraz ich czytelnicy.

W latach dziewięćdziesiątych finger został uznany przez większość administratorów za daemon niebezpieczny: program uruchamiany zewnętrznie, przez Internet, który czyta prywatne pliki z katalogu domowego użytkownika, czasem z podwyższonym dostępem to źródło potencjalnego bólu głowy.

Jeden z pierwszych robali używających Internetu do rozprzestrzeniania się, Morris, używał dziury znajdującej się w implementacji protokołu.

Tym samym popularność .plan spadła niemal natychmiast do zera. Ludzie jednak nie przestali opowiadać historii, zmieniły się tylko platformy i media, od rylca do glinianych tablic po pióra wieczne, od .plan do mediów społecznościowych. Nikt nie zamknie nam ust póki jest miejsce gdzie można napisać zdanie, szalet miejski jest na to dowodem ostatecznym.

* * *

W Internecie ciężko znaleźć jakieś archiwa wpisów do .plan, jego natura była bardzo efemeryczna. Jedyne popularne archiwum to .plan Johna Carmacka, autora wolf3d.exe i quake.exe.


  1. człowiek bard w kłamczo-łacinie 


Wolniej

Wiek średni to taki okres w życiu człowieka, gdy mimowolnie staje się „kołczem rozwoju osobistego” zaskarbiając sobie nienawiść wśród ludzi bliskich i przygodnych. Wszystkie błędy popełnione w życiu przepasuje czerwoną wstążką i obnosi je jak relikwie nie potrafiąc rozpoznać, że nie ma w nich nic wyjątkowego ani odkrywczego.

Uprawomocniony wchodzeniem w ostatni zakręt — już mocno przedłużonej — młodości, chciałbym Wam powiedzieć coś o uczeniu się. Jest to podwójnie skandaliczne, gdyż mury szkoły widziałem tylko od strony szarego tynku, gdy odbijałem odeń piłkę.

Struktura społeczeństwa zmieniła się już nie raz. Tak jak kiedyś chudy i spalony słońcem był z pewnością chłopem, którego jedynym dorobkiem jest garb tak bladaporcelanowa i pulchna była Hrabina. I gdy nawiniemy taśmę czasu w nasze okolice, sygnały statusu odwróciły się.

To samo stało się z „wolnym czasem”, choć w ogóle rzecz taka jak „wolny czas” w naszym rozumieniu jest produktem zupełnie nowym na rynku kultury. Kiedyś człowiek, co mógł się wyciągnąć na tapczanie i tak po prostu leżeć i wypierdywać dziury w materiale, był królem życia. Dziś kto nie uprawia wspinaczki i garncarstwa, najlepiej za jednym zamachem, jest prostakiem po stokroć. Wolny czas należy wypełnić zajęciami tak szczelnie żeby narastało w człowieku marzenie o rozwinięciu talentu do wypróżniania się w biegu, jak to czynią konie, między galopem od jednej aktywności do drugiej.

Są tylko dwie ważne rzeczy w uczeniu się nowych zdolności. Jak drogi jest sprzęt zakupiony do uprawiania hobby i jakiej klasy ludzie widzą Cię podczas go uprawiania. Kpię oczywiście.

Pierwszą rzeczą, o dziwno często pomijaną podczas skoku w nowe zajęcie, jest fakt, że trzeba te hobby na serio uprawiać. Mam pełen strój bramkarski, ale boisko widziałem pewnie 10 lat temu, nie wypada mi się nazywać „bramkarzem”, nawet „były bramkarz” brzmi głupio, jak „byłe dziecko”.

Jestem zwolennikiem pozytywistyczno-praktycznej definicji. Piszesz? Jesteś pisarzem. Nie piszesz? Nie jesteś. Biegasz? Jesteś biegaczem. Nie biegasz, nie jesteś. I może nie jesteś najszybszym biegaczem albo najbłyskotliwszym pisarzem. To jednak ocena wartości, a świat nosi wielu twórców, którzy są lepsi ode mnie, a nie naplułbym im na łeb, gdyby się palili. To wszystko są truizmy, ale bardzo łatwo się je zapomina, czasem nawet z premedytacją, gdy podczas wiosennego sprzątania przekładasz notatnik Moleskine z jedną zapisaną stroną (zakupy), buty do biegania i gitarę z zerwaną struną.

To prawda pierwsza: jeśli chcesz mieć jakąś przyjemność z uczenia się nowej rzeczy musisz ją uprawiać. Bardzo łatwo odstawiać teatr i grać przed sobą komedię. Ale nikt się nie śmieje, bo nikt tego nie ogląda.

Prawda druga: czym wolniej się uczysz tym większa szansa, że się nie poddasz.

W świecie zoptymalizowanym pod natychmiastową gratyfikację ciężko jest się przestawić na żmudną drogę. Jakby Jezusowi powiedzieć: „będziesz cierpiał, ale jaka to historia z tego wyjdzie”. Dlatego współczesnych synów bożych separuje się od zdrowego społeczeństwa w zakładach psychiatrycznych, komu by pasowała taka opcja!

Od miesięcy próbowałem nauczyć się Rusta. I moja droga zawsze przebiegała tak samo. Pobieżnie skonsumowany wstęp w dokumentacji. Kompilacja println!("Twoja stara");. Próba napisania czegoś. Frustracja. Porzucenie nauki na miesiące. GO TO 10.

Kilka dni temu postanowiłem, że przestanę skakać z jednego miejsca dokumentacji w drugie, próbując zmusić kompilator do respektowania mojego autorytetu wieloletniego programisty.

Godzina po godzinie, tworzyłem sobie katalog z nazwą jakiegoś elementu języka np. 03.array, 04.struct, 05.enum i mozolnie, pokornie, przepisywałem przykłady, modyfikowałem je, wymyślałem inne, testowałem hipotezy. Czasami aż mnie szczypało w dupę, że muszę znów pisać kod, który „wypisuje wszystkie elementy z tablicy wraz z ich indeksem”. I kiedy wreszcie zesztywniał mi kark okazało się, że podczas tych zupełnie głupich zajęć nie tylko załapałem idee, których opisy czytałem wcześniej na wyrywki, byłem też wewnętrznie zadowolony mimo że nie stworzyłem niczego oczywistego.

Teraz myślę do siebie, że „wolno” to może złe słowo, lepszym byłoby „metodycznie”, ale dychotomia „wolno” ↔ „szybko” brzmi mi lepiej niż „metodycznie” ↔ „chaotycznie”.

„Szybkość” to to, co marketingowcy umieszczają w dużym czerwonym kółku w nadziei, że odmieni Ci się to w głowie na „wygodę”. I w pewnym sensie jest to prawda. Ludzie spędzili wiele lat budując świat w którym 20% dostępnej wiedzy pozwala wykonać 80% zadań z zadowalającym skutkiem.

Dlatego dobicie do 21% spowoduje, że pobijesz większość. Dlaczego? Bo wolno.


Nazwa pliku jako UX

Ze wszystkich mądrych rzeczy, które powiedziałem i napisałem przez lata, tak o życiu, jak i o programowaniu, szczególne miejsce w moim sercu ma ta obserwacja:

Bardzo łatwo rozpoznać interface projektowany przez programistę: „godzina i piętnaście minut” jest wyrażone jako 1.25

Ta obserwacja była formą samokrytyki, gdyż podczas prowadzenia dema zauważyłem, że sam wykonałem takiego „międzymordziowego bazyliszka”. Od tego czasu, aż do teraz, oddałem wszystkie prace związane z tworzeniem interakcji ludziom, którzy się na tym znają. A przynajmniej powinni.

Zaszyłem się więc w ciemnej norze backendu, gdzie użytkownicy istnieją tylko jako miraże, tworzone i niszczone na potrzeby automatycznych testów. Bez historii, bez potrzeb, nie wysyłają świątecznych kartek. Perfekcyjna harmonia.

Ostatni projekt zmusił mnie jednak do opuszczenia mojej kryjówki, gdyż przypadła mi kluczowa rola, a że i projekt przypadł mi do gustu, byłem całkiem zadowolony i dałem nura.

Jednym z produktów systemu, który pisałem, były dokumenty do druku, gdyż część z naszych użytkowników jest cyfrowo wykluczona i nie chcemy aby potrzeba posiadania komputera z dostępem do Internetu była barierą. Ponieważ jedna osoba może mieć maksymalnie sto takich dokumentów, wymyśliłem i przeforsowałem zmianę. Dokumenty można scalać w pojedynczą grupę dokument, będący dla systemu równoważnikiem. Każdy dokument zawiera numer seryjny oraz sygnaturę kryptograficzną, dlatego zbudowanie takiej paczki jest całkiem proste i pozwala na łatwą weryfikację spójności.

Przepchnąłem ten pomysł zaczynając od współpracowników, przez kierownika projektu ze strony klienta, kończąc na akceptacji urzędu marszałkowskiego. Kiedy dostałem glejt z pieczęcią „no dobra, rób” usiadłem i zaprogramowałem.

Wszyscy żyli szczęśliwie kilka miesięcy, aż do momentu w którym Panie z rozliczeń zaczęły zwracać uwagę na rosnącą liczbę pomyłek przy zdawaniu paczek dokumentów. Bardzo dziwne, bardzo dziwne. Zalogowałem się jako użytkownik i poszedłem oglądać.

I wtedy zrozumiałem, że znów mam 1.25 jak w cytacie wyżej.

Dla własnej wygody trzymam paczkę jako SHA512 robiący za sumę kontrolną. To oczywiste, że tak robię. Kiedy piszę automatyczny test mogę od razu stwierdzić, czy dokument zapisany na dysku zgadza się z tym, czego się spodziewałem.

Dla mnie SHA512 jest oczywiste. Dla użytkownika natomiast otrzymanie pliku 4143aaf85e1a825463a8a202b9ee6ffa486[…]9a5edc944e3e473f89a889c85e093abe7adce5164dfefef0f3eded1e.pdf niesie bardzo niewiele informacji. W sytuacji, gdy mamy jedną paczkę problem rozwiązuje się naturalnie. Gdy użytkownik ma tych plików 12, heksadecymalny jazgot jest nie do przetrawienia.

Pracownik za kwadrans do fajrantu nie ma już mocy na sprawdzanie każdego dokumentu. A to rodzi błędy.

Dodałem więc nagłówek Content-Disposition: attachment; filename="%s_%s_%d" i sformatowałem nazwę pliku używając imienia, nazwiska i liczby dokumentów w paczce. Jan_Kowalski_15.pdf jest trudniej źle zinterpretować.

Od tego czasu liczba błędów spadła do zera.

Jedna linijka, a taka różnica. Nie wiem, czy być dumny z tej, szybkiej, reakcji czy też zawstydzony, że nadal mentalnie siedzę w backendowej jaskini.


Za kwadrans wiosna

Otworzyłem okno. Mimo ostrzeżeń o zanieczyszczeniu powietrza podjąłem decyzję, że lepszy jest dym płonących opon unoszący się z kominów łódzkich slumsów niż moja własna tytoniowa wędzarnia. Przez szparę wlał się chłód będący idealnym towarem zastępczym świeżości.

Usiadłem na fotelu i patrzyłem się tak w okno. Laptopa zostawiłem w biurze żeby się odtruć, widocznie nawyku patrzenia się w okna z tępym wyrazem na twarzy nie da się wyzbyć w jeden dzień odwyku. Kontemplowałem wszechświat, ale bardzo krótko, bojąc się że przez przypadek coś odkryję i będę musiał temu stawić czoło.

Zabrałem się za odpisywanie na listy i okłamywanie się, że nie jest mi zimno z powodu tego okna. Jak ludy prymitywne wierzyłem, że moje przekonanie o komforcie udzieli się, zwykle nie zważającym na byt ludzki, sferom niebieskim. I że będzie wiosna.

Po trzech godzinach, gdy wiosna się nie zjawiła, a w jej miejsce przyszła noc, musiałem uznać przewagę materii nad umysłem. Zamknąłem okno. Zapaliłem papierosa żeby nie dać się tej nowo nabytej świeżości zbyt łatwo.

I wtedy usłyszałem to leniwe, monotoniczne bzyczenie.

Tłusta mucha, pobudzona jak i ja, tą pierwszą obietnicą wiosny, podniosła swój zielony brzuch i zaczęła latać mi nad łbem.

Ja pisałem do paryżanki o chińskim atramencie, a ona przerywała mi co zdanie.

Zdałem sobie sprawę, że sam doprowadziłem do tej sytuacji. Nie przez otwieranie okna, nie. Widzicie, to wszystko przez technologię. 15 lat temu zwinąłbym w rulon gazetę i postawił się w roli sędziego, oskarżyciela i kata w jednej osobie. Po krótkiej gonitwie zgniótłbym ją na jakiejś płaszczyźnie i wydał z siebie pomruk zadowolenia; prymat homo sapiens zostałby zachowany.

Po upadku prasy papierowej mógłbym jej najwyżej przyjebać tabletem.

W sumie i tak nic na nim nie czytam.


Umówiłem się z nią na @833

Internet od zawsze był przestrzenią przyjazną eksperymentom i wynalazczości. I zgodnie z nazwą mojej ulubionej kolumny w „Młodym Techniku” — „Pomysły genialne, zwariowane i takie sobie”1 niektóre przetrwały nie tylko próbę czasu, ale stały się budulcem współczesnego świata. Inne wypadły z rąk twórców i z hukiem roztrzaskały się na betonowej posadzce rzeczywistości.

Pomysł, o którym chciałem Wam dziś opowiedzieć, tańczy na granicy tych trzech przymiotników. No, chyba, że będziemy patrzeć z punktu widzenia przyjęcia rozwiązania na rynku, wtedy nawet „takie sobie” to raczej laurka niż opis stanu faktycznego. Popatrzmy na niego oczami cyber-futurystów roku pańskiego 1998, kiedy Internet miał już pierwszy zarost.

Najważniejszym zadaniem sieci było połączyć nas wszystkich i stworzyć Globalną Wioskę, gdzie wektory wiedzy, różnorodności i zaradności dodadzą się rodząc sytuację, w której co drugi obywatel będzie Królem Filozofem. Dziś z perspektywy czasu widać, że idea wioski się spełniła: kumoterstwo, plotkarstwo i disko polo ma się dobrze.

Zostawmy jednak cynizm.

Kiedy zaczęliśmy pracować w globalnej wiosce okazało się, że wszyscy tyrają w systemie trójzmianowym. Idziesz do piekarza, a on śpi, gdyż jest na innym kontynencie, choć metaforycznie, na wyciągnięcie e-ręki. Strefy czasowe podstawiły nogę rozpędzającej się, globalnej, ekonomii. Próba umówienia się z kimś wymagała powtórki z geografii, ustalenia stref czasowych wszystkich uczestników, oraz tego, czy używają obecnie czasu letniego czy zimowego.

Swatch wpadł na pomysł jak rozwiązać ten nowy — na tę skalę — problem, sprzedając przy okazji niezłą górę zegarków. Swatch Internet Time!

Francja, po rewolucji, wprowadziła czas decymalny, oparty na 10 godzinach, które składały się z 100 minut po 100 sekund. Jako że ciężko się patentuje rozwiązania, które są jasno opisane w podręcznikach do historii, Swatch dokonał lekkiej modyfikacji: doba składała się z 1000 .beat, nie posiadały one strefy czasowej, więc były uniwersalne dla świata. Wystarczało, że umówisz się z nią na @833, weźmiesz od szefa akonto i wszyscy będą wiedzieć, kiedy to jest! Proste!

Oczywiście to nie zmieniło niczego w fakcie, że podróżujemy dookoła kuli plazmy i ludzie nadal śpią gdzieś kiedy zegarek Swatcha „wybija” @833.

Ja jednak byłem urzeczony pomysłem i choć nie miałem kontaktów z nikim, kto potrzebowałby się ze mną umówić w różnych strefach czasowych, dumnie włączyłem renderowanie ilości .beat na belce systemowej mojej Amigi. Próbowałem nawet nieśmiało podawać tak sformatowaną godzinę różnym znerdziałym znajomym, ale oni patrzyli tylko na mnie jak na dziwaka. Dwadzieścia lat później sytuacja nie uległa zmianie w tej kwestii.

Swatch nie był zadowolony z tego, że ich wynalazek jest tak beztrosko implementowany przez różnych obszarpańców, co pewnie nie mają zegarka ni garnituru i zrobił to, co każde lajfstajlowe korpo, zaczął ścigać „nielegalne dzielenie”, aż do momentu w którym nikt nie chciał się w to bawić. Trudno wymagać żeby każdy, z kim się umawiasz, miał zegarek tego samego producenta.

Dodatkowo Swatch, chcąc zapewne podbić wartość swojego wynalazku, wprowadził swoją własną strefę czasową, Biel/Switzerland, od której liczony był czas bazowy dla Internet Time.

Ktoś mógłby zapytać, czy jest jakaś merytoryczna różnica między umawianiem się na godzinę wg. UTC a tym oto wynalazkiem? Jest jedna, oczywista. Godzina z prefiksem @ jest bardziej e-cyber.

I tak pomysł genialny, bo stymulował fantazję o Jednym Świecie, zwariowany, bo ciężko wyobrazić sobie coś tak radykalnie dobrego żeby cały świat entuzjastycznie przytaknął, ale też taki sobie, bo w przeciwieństwie do innych zdobyczy epoki internetowej nie dane mu było oderwać się od cyca korpowładców.

A piszę o tym dlatego, że wracając wczoraj, lekko intelektualnie zmęczony imprezą, przypomniałem sobie o tym moim zegarku na belce Amigi i wymyśliłem, że dopiszę sobie to samo, tylko jako element belki tmuxa. Sama procedura jest trywialna.

  1. Weź obecną godzinę
  2. Policz ile sekund minęło od północy
  3. Ponieważ w 24h jest 86400 sekund, a chcemy 1000 jednostek, dzielimy to przez 86.4 i odrzucamy resztę
  4. Dzwoniący telefon to prawnicy szwajcarskich zegarmistrzów
  5. No division is illegal, hack the planet

Natychmiast po napisaniu kodu zdałem sobie sprawę, że jestem o godzinę za daleko. Jasne, muszę przekręcić datę na ich strefę czasową. Programowanie z uwzględnieniem stref czasowych przechodzi atrofię za każdym razem, gdy przestaję o nim myśleć. Poszedłem więc czytać dokumentację, ale za nic na świecie nie mogłem się dobrać do, nieoficjalnej przecież, strefy czasowej Swatcha.

Rzutem na taśmę odkryłem, że jest on równoważny UTC+1, dodałem więc brzydką arytmetykę na datach. Jestem pewien, że zrobiłem coś źle. Apple dwa lata wydawało iOS z błędem, który przestawiał budziki użytkownikom, a Microsoft miał firmware w Zune, które spowodowało, że jeden dzień nie dało się włączyć odtwarzacza. Skoro oni nie wiedzą, co robią, to ja też sobie pozwolę.

Efekt działania na terminalu:

#!/usr/bin/env python3
from datetime import datetime, timedelta
import pytz
import sys

def swatch_time(datetime_object = None, timezone_literal = 'Europe/Warsaw'):

    reset_clock = {
            'hour': 0,
            'minute': 0,
            'second': 0,
            'microsecond': 0
    }

    if not datetime_object:
        datetime_object = datetime.now()

    if not datetime_object.tzinfo:
        timezone = pytz.timezone(timezone_literal)
        datetime_object = timezone.localize(datetime_object)

    # Biel TZ is a unrecognized TZ that can be expressed as UTC+1
    # Thanks, Swatch
    swatch_timezone = pytz.timezone('UTC')
    datetime_object = datetime_object.astimezone(swatch_timezone) + timedelta(hours=1)

    midnight = datetime_object.replace(**reset_clock)
    time_delta = datetime_object - midnight

    if time_delta.seconds == 0:
        # don't divide against zero
        return 0

    return int(time_delta.seconds / 86.4)

if __name__ == "__main__":
    print("@{}".format(swatch_time()))
  1. Dział ten nazywałem też „Nygusem”, gdyż numery z lat 80-tych miały pana leżącego niedbale dookoła liter loga, standardowym zawołaniem bojowym w weekendy było „Babcia, poczytaj mi «Nygusa»”.

Opóźniona gratyfikacja

Ze wszystkich rzeczy, które najbardziej oczarowały mnie w tym całym komputerowym bajzlu, musiałbym wymienić automatyzację na pierwszym miejscu.

Mimo płynących lat nadal odnajduję okruchy magii w tym, że komputer, raz nauczony, potrafi powtarzać rzeczy bez czujnego oka operatora. Kiedy otrzymałem swoje pierwsze konto z dostępem do powłoki, napisałem na szybko dwa skrypty, które wysyłały e-maile na specjalny adres, przesyłający informację dalej na telefon komórkowy via SMS. Pierwszy informował mnie o loginach na mój shell. Siadałem do terminala, logowałem się i… pik! Drugi śledził mój /var/spool/mail/opi i przysyłał mi każdego ranka informację o ilości e-maili. Serce aż bije mocniej, gdy wspomnę tę ekscytację czymś, co dziś brzmi jak błahostka. Zabawne, że dziś moje skrypty działają odwrotnie i ukrywają pocztę, która do mnie przyszła. Odwrotność miłości to nie nienawiść — to obojętność.

Zanim otrzymałem to konto cierpliwie wertowałem „książkę do nauki Linuksa”, jedną z tych książek, które leniwie tłumaczą to, co i tak jest dostępne na stronach podręcznika man, ale to było jak uczenie się języka przez zapamiętywanie słówek, bez wymowy, bez kontekstu, ale z pełnym nabożeństwem iluzji zdobywania wiedzy.

Tam też natknąłem się na atd, daemon wykonujący polecenie — bądź serie poleceń — opóźnione o zadany czas. Prawie zemdlałem. Idea, że jest komputer, który nie tylko jest non-stop włączony, ale także non-stop „w Internecie”, a do tego mogę mu powiedzieć, co zrobić za kilka godzin wydawała mi się jak odkrycie podróży międzyplanetarnych przy użyciu puszki mielonki, kawałka sznurka i bardzo silnego postanowienia woli: niesamowite, a w ogóle nieprawdopodobnie, że ludzie nie siedzą godzinami wymyślając, co komputer może zrobić za godzinę! To musi zmienić cały świat.

Nie zmieniło świata, a wraz z upływającym czasem ludzie w ogóle przestali wiedzieć o atd. Kiedy zainstalowałem Debiana na nowym laptopie atd nie było w standardowym zestawie pakietów. Jak wtedy, gdy Twoja matka komunikuje Ci na obiedzie, że znalazła twoje stare magazyny i wyrzuciła je do śmieci. Maska dorosłości przykrywająca doskonale uczucie żalu.

Mimo to, myślę sobie, at jest jedną z tych rzeczy, która spadła za ladę i może znajdzie się jak będziecie malować, w przyszłości. Nie wiem, jak ludzie żyją bez tego, ale może to tylko ja. Może po prostu nikt nie powiedział ludziom, że mają non-stop takie nisko-profilowe cudeńko w systemie? Może jeśli im powiem, na ten przykład w notce, trochę wstawiony, to odnajdziemy wspólny język.

at to komenda, która jest klientem daemona atd, pozwalająca na uruchomienie polecenia, lub serii poleceń. W odróżnieniu od Crontaba zadania te są jednokrotnego użytku. Można oczywiście wywoływać skrypty.

Przykładowo, mój skrypt odpowiedzialny za deploy nowej wersji oprogramowania ma linijkę:

echo "./skrypt.sh" | at 1:00

Znaczy to ni mniej, ni więcej że o pierwszej w nocy, kiedy użytkownicy już zasną, pojęte zostaną działania integracyjne, które teraz powodowałyby ból zębów użytkowników. Gdybym używał do tego Crona lub innego cyklicznego odpalacza musiałbym przekazać w jakiś sposób stan, stworzyć pusty plik albo odłożyć wartość do redisa, to tylko komplikuje rzeczy.

Kiedy wychodzę z domu, a pasek „podstępu” pobierania tego czy owego waha się non-stop pomiędzy 30 a 40 minutami piszę:

sudo at now+1 hour, podaję hasło i w linii poleceń at piszę poweroff. Za godzinę komputer złoży się bez mojej interwencji i nie będzie marnował prądu.

Mieliście kiedyś do wykonania zadanie na serwerze, który jest pod sporym obciążeniem, które to obciążenie powoduje, że zadanie wykonywałoby się zdecydowanie zbyt długo lub — co gorsza — spowodowało śmierć ważnych części systemu przez wysycenie I/O? W skład at wchodzi polecenie batch, które nie czeka na dopełnienie się konkretnej daty, odpala zadane kiedy load spadnie do 1.5; jeśli wydaje się Wam to bezużyteczne nigdy nie widzieliście aplikacji, która rozpędzona łyka zasoby jak odkurzacz-fetyszysta.

Kolejkę oczekujących zadań obsługujemy przy pomocy atq, które wyświetla listę wraz z unikalnym identyfikatorem, którego możemy użyć wraz z atrm celem usunięcia.

Tak wiele, tak niewiele.

I wiem, że jest pewnie lepszy, współcześniejszy, daemon. Wysyła powiadomienia na Slacka, całuje użytkownika w czółko i w ogóle. Ale! Te narzędzia nie przeżyły tyle lat jako część *NIX-a dlatego, że panowie z workami, na których widnieje symbol dolara, sypali mamoną aż do momentu w którym krytykanci się poddali i odlecieli prywatnymi odrzutowcami. To po prostu jednofunkcyjne narzędzie, które robi, co powinno.

KISS your atd.


Rozszczepienie

Zanim Reddit stał się pierwszą stroną Internetu, był trzecią. Nie istniał jeszcze ekosystem pozwalający zwykłym użytkownikom na relatywnie tani dostęp do zawszedostępnego składu informacji, a serwisy hostujące obrazki dzieliły się na trzy rodzaje.

Ofertę darmową, obsraną wyskakującymi okienkami, obwieszoną reklamami, pod których ciężarem usługa czołgała się, irytując użytkowników. Ofertę płatną, obłożoną ograniczenami transferów i relatywnie kosztowną, często powiązaną z życiem profesjonalnym lub prywatnym, które może nie każdy chciał wiązać ze swoimi postami na Reddicie, gdzie tematem przewodnim jest dmuchanie kreskówkowych postaci, dosłownie. Istniały wreszcie serwisy chałupnicze, które studenci budowali w ramach podpieprzania zasobów serwera .edu.pl. Serwisy te często zapewniały szybkość i wygodę, a także pewność, że znikną one prędzej czy później bez słowa wyjaśnienia, grzebiąc twoje bardzo zabawne zdjęcia i łamiąc nieskończoną ilość odnośników ućkanych po forach.

Nie było dobrze, zwłaszcza w świecie, w którym obrazki — na serwisach takich jak Reddit, będących bezpośrednią ewolucją imageboardów — są największym dobrem.

Ktoś rzucił kiedyś pomysł, żebyśmy sfinansowali jeden z serwisów, który został demokratycznie wybranym docelowym miejscem do wieszania obrazków, bo prawdopodobieństwo podzielenia przez niego losu innych „dobrych serwisów powstałych z potrzeby społeczności bez pieniędzy” zaczęło oscylować dookoła jedynki.

Ludzie rzucili jakieś dolary i orkiestra grała dalej. O tym, że też rzuciłem, dowiedziałem się po latach z e-maila z podziękowaniami. Jestem tak szczodry, że nawet się nie chwalę i nie pamiętam, czyj serwis ratuję przed zgonem. Skromnie.

Minęły lata. Życie z datków, reklam i „sponsorowanych obrazków” było ciężkim chlebem.

W przemyśle podwykonawczym nie ma miłości. Nikt nie kocha gościa obierającego ziemniaki na zapleczu czy pilnującego, żeby mieszadło mieszało z dobrą szybością. Reddit używał serwisu Imgur tak, jak się używa podwykonawcy: z obojętnością, kiedy wszystko idzie dobrze, z nienawiścią, jeśli coś nie działa.

Nie widząc innej szansy na przetrwanie, Imgur postanowił zbudować własną społeczność, umożliwiając komentowanie i gromadzenie się pod różnymi banderami — sprawdzony przepis na zwabienie ludzi. Był dużo mniej przerażający niż Reddit (nie widzę młodych ludzi, którzy zacierają ręce, myśląc „Ojej, spartański design, gdzie w wątku o meczu są tysiące — wątkowanych! — komentarzy i osiem lat kultury opartej na sraniu we własne gniazdo! Dołączam!”). Użytkownicy wsiąkali więc na tyle szybko, że pojawili się nawet kapitaliści wysokiego ryzyka (cudzego) z workiem pełnym twardej waluty.

Większość użytkowników Reddita nadal używa Imgur jako miejsca zrzutu obrazków.

Uf, to historia, której mogłem nie pisać, ale mam pół litra zielonej herbaty do wypicia.

Użytkownicy Reddita wrzucają obrazki na Imgur bezwiednie, często anonimowo, półautomatycznie lub nawet automatycznie. Wszyscy nadal myślą o nim w kontekście serwisu usługowego. Gdy czasem kliknę jakąś galerię (praktycznie jedyny przypadek, kiedy ląduję na stronie ich serwisu bezpośrednio), widzę to, co widzi ich społeczność. I tu ostatnio zadumałem się.

Mamy sytuację, gdy jedna strona traktuje drugą przedmiotowo, ale ta druga, bez wiedzy pierwszej, rozwinęła własną kulturę i społeczność. Wszystkie obrazki trafiają więc do mieszkańców serwisu obrazkowego bez jakiegokolwiek kontekstu, a sam wrzucający nie ma najmniejszego powodu, żeby podejmować interakcję z elementem lokalnym.

Serwisy się widzą

Nie uderzyłoby mnie to, gdybym któregoś dnia nie nadganiał galerii subreddita /r/fountainpens — który, jak nazwa wskazuje, służy do chwalenia się piórami lub charakterem pisma („those who can’t, buy”) — i nie poczytał załączonych komentarzy. Ludzie pisali jakieś bzdety, bzdety, jakich nikt zainteresowany tym hobby by nie pisał. Popatrzyłem jeszcze, sytuacja się powtarzała.

Wyobraź sobie, że żyjesz gdzieś, gdzie jest nowocześnie i młodzieżowo. Co jakiś czas twój dom najeżdzają barbarzyńcy i wieszają na ścianach barokowe obrazy podpisane łaciną. Nigdy nie mówią nic, nie usprawiedliwiają się i nie tłumaczą. Wieszają i wychodzą. Żyjecie w dwóch przenikających się wszechświatach, obserwujecie to samo, widząc zupełnie coś innego. Nie w materialnym sensie, bo piksele są te same, ale cały sens pojawiający się wraz z odpowiednio umocowanym punktem widzenia jest inny.

Ten tekst nie zawiera żadnej puenty, gdyż do niczego Was nie przekonuję. To tylko jedna z tych obserwacji, od których robię „huh…”. Kiedyś bym ją zamienił w zbyt długą notkę o niczym.

Punkt widzenia zależy od zalogowania się.


Tay, otwórz drzwi

Technologia nie zwalnia. Przeszliśmy od komputerów, których nie można podnieść, przez komputery, które można, następnie takie, które można rzucić, aby zakończyć na tych, które upuszczamy niechący. Wielkimi krokami nadchodzi era osobistych asystentów w ogóle odpiętych od idei „urządzenia, które się posiada”, takich jak Amazon Echo czy Google Assistant.

Sukces jest jednak daleko, bo mimo olbrzymich skoków, nadal technologie Udające Inteligencję podczas interakcji bardziej przypominają grę w 20 pytań niż dramatyczny dialog z HAL-em 9000 o zamykaniu drzwi. Wielkie firmy już dawno zauważyły, że ciężko jest zbudować taką technologię bez dobrego źrodła informacji. Jeśli algorytmy mogą być „uprzedzone” uprzedzeniami autorów, to co dopiero dane, które są dużo mniej rygorystyczne w swej naturze. Czasem myślę, że Douglas Adams stworzył Marvina, robota z depresją, jako ostrzeżenie przed uczeniem algorytmów sztucznej inteligencji na korpo-poczcie i zgłoszeniach błędów, których z pewnością międzygalaktyczny rząd miał pod dostatkiem.

Najtańszą siłą roboczą na rynku są obecnie użytkownicy. Nie tylko robią rzeczy za darmo (ewentualnie za „odznaki”, które można spieniężyć), ale reprezentują w miarę szeroką gamę opinii, pochodzą z różnych kultur, rozmawiają różnymi językami. Nie ma takiej akcji świadomościowej, która mogłaby wtłoczyć w firmy technologiczne równie zróżnicowany wycinek świata.

Użytkownik skataloguje obrazki, użytkownik zabawi parser lingwistyczny rozmowami o życiu, użytkownik otaguje i utworzy listy. Użytkownik nie ma związków zawodowych, nie ma też wolnego.

W świecie synergii biznesowej firmy udostępniają swoich użytkowników innym firmom tak jak pożyczasz sąsiadowi młotek czy szklankę cukru — normalne zachowanie pozwalające budować partnerstwo i wzajemne zaufanie.

Tak właśnie Microsoft wpadł na pomysł, żeby zapędzić użytkowników serwisu Twitter — który to serwis służy do niszczenia wyobrażeń o aktorach i politykach oraz jako efektywny transmiter krótkich utarczek słownych — do „pracy przez zabawę”, tj. rozmawiania z ich botem, którego przebrano za nastolatkę i nadano odpowiednie imię: Tay. Taka forma międzymordzia (pomiędzy algorytmem danych rozgryzającym zdania na części mowy celem łatwiejszego połknięcia a białym pudełkiem, w które wpisuje się wypowiedzi) miała zmiejszyć napięcia zawsze budujące się w interakcji między człowiekiem a maszyną. Oraz zawęzić grupę biorącą udział w pracy przy pomocy naturalnego filtru społecznego („kto rozmawia z nastolatkami na Twitterze?”).

Microsoft, firma przechodząca drugą młodość, po pozbyciu się starych ludzi zyskała wigor, ale straciła też wiedzę zdobytą przez lata: pytanie Internetu to rosyjska ruletka w wersji „ciężko”, pięć kul i jedna wolna komora.

Tay zaczęła jako pogodna nastolatka z ograniczonym zasobem zainteresowań i ubogim słownikiem. Blogi technologiczne, widząc opcję na odfajkowanie jeszcze jednego wpisu, przepisały notkę prasową, co zamieniło się znów w zainteresowanie. Twitter gadał do Tay, ona słuchała.

Wiadomości dosięgnęły wreszcie podbrzusza Internetu, o którym z wypiekami na twarzy korporobotnicy czytają na smartfonach w kolejce do okienka. Tajemne, mroczne, skandaliczne, bezwzględne, składające się głównie z innych znudzonych korporobotników za siedmioma serwerami proxy.

Następnego dnia Microsoft zamknął projekt. Tay, przyuczona przez element anarchistyczny, stała się grubiańska, głosiła niepopularne tezy podszyte ksenofobią i rasizmem. W jeden dzień z cichej nastolatki na Twitterze wykluł się potwór, rasista, cynik, automaton powtarzający głupoty za swoimi rówieśnikami, a przecież spuszczony z oczu tylko na chwilę przez rodziców, którzy mieli dobre intencje.

Najbardziej boli mnie, że ludzie, zamiast gratulować Microsoftowi, wieszali na nim psy. Nikt nigdy wcześniej nie dokonał tak kompletnej, dokładnej symulacji bycia nastolatkiem. Ktoś powinien dać im nagrodę. To absolutny przełom.

Być może następnym produktem będzie para botów. Na start każdy z nich będzie przekonany 100% o swojej racji i niech skalibrują się wzajemnie. Najlepiej na Fecebooku1.

  1. Kaja zgłosiła jako literówkę, ale zostawiam, gdyż piękne.