<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
    <title>mtsz</title>
    <link rel="self" type="application/atom+xml" href="https://mtsz.pl/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://mtsz.pl/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-04-04T19:11:00+00:00</updated>
    <id>https://mtsz.pl/atom.xml</id>
    <entry xml:lang="pl">
        <title>Przeładowany czytnik RSS</title>
        <published>2026-04-04T19:11:00+00:00</published>
        <updated>2026-04-04T19:11:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-04-04-przeladowany-czytnik-rss/"/>
        <id>https://mtsz.pl/blog/2026-04-04-przeladowany-czytnik-rss/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-04-04-przeladowany-czytnik-rss/">&lt;p&gt;Problem jest prosty: po dodaniu trzystu źródeł do czytnika RSS, z których wiele to strony z wiadomościami albo agregatory, ilość artykułów do przeczytania, filmów do obejrzenia i podkastów do odsłuchania rośnie do granic możliwości. Na moje szczęście, taki problem mam nie tylko ja, i dużo osób mądrzejszych ode mnie w tej materii ma coś sensownego do powiedzenia. Na początek czytanki, przez które przebrnąłem:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;enocc.com&#x2F;blog&#x2F;2025-11-12-read-web-seasonally.html&quot;&gt;https:&#x2F;&#x2F;enocc.com&#x2F;blog&#x2F;2025-11-12-read-web-seasonally.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;willhopkins.dev&#x2F;i-dont-like-to-read-later&quot;&gt;https:&#x2F;&#x2F;willhopkins.dev&#x2F;i-dont-like-to-read-later&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;willhopkins.dev&#x2F;seasonal-reading&quot;&gt;https:&#x2F;&#x2F;willhopkins.dev&#x2F;seasonal-reading&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;marco.org&#x2F;2011&#x2F;09&#x2F;04&#x2F;sane-rss-usage&quot;&gt;https:&#x2F;&#x2F;marco.org&#x2F;2011&#x2F;09&#x2F;04&#x2F;sane-rss-usage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;willhopkins.dev&#x2F;feed-readers-and-me&quot;&gt;https:&#x2F;&#x2F;willhopkins.dev&#x2F;feed-readers-and-me&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2011&#x2F;09&#x2F;why-keeping-up-with-rss-is-poisonous-to-productivity-sanity&quot;&gt;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2011&#x2F;09&#x2F;why-keeping-up-with-rss-is-poisonous-to-productivity-sanity&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Strumień świadomości w trakcie czytania:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;pomysł: oznaczenie elementu do przeczytania powinno go zapisywać z datą ważności - po jej upłynięciu element po prostu znika z listy. Do rozważenia, czy data ważności powinna być stała czy zmienna (zmienna to kolejny koszt poznawczy)&lt;&#x2F;li&gt;
&lt;li&gt;kupowanie książek i nieczytanie ich ma swoją nazwę: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tsundoku&quot;&gt;tsundoku&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;faktycznie wśród moich kanałów jest bardzo duża powtarzalność informacji, dobre miejsce do optymalizacji&lt;&#x2F;li&gt;
&lt;li&gt;napisać skrypt, który mierzy częstotliwość publikacji każdego kanału - najlepsza jest duża ilość rzadko publikujących stron&lt;&#x2F;li&gt;
&lt;li&gt;niektóre z wrzuconych wyżej artykułów zostały napisane w prehistorii - czyli wtedy, gdy RSS był jeszcze na tyle popularny, że przeglądarki domyślnie go obsługiwały, a swoje kanały miał np. Facebook czy Twittex&lt;&#x2F;li&gt;
&lt;li&gt;śmieszne: w 2011 roku dużo osób argumentowało, że w RSSach jest śmietnik, i że łatwiej jest im czerpać informacje z Facebooka i Twittexa - &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=kin601UK394#t=2m&quot;&gt;&lt;em&gt;well, well, well, how the turntables...&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Dobra, mam kilka pomysłów.&lt;&#x2F;p&gt;
&lt;p&gt;Pomysł pierwszy: powtórzenia. Bardzo dużo kanałów, które śledzę, dotyczy polityki. Większość informacji na tych kanałach mocno się powtarza. Z drugiej strony cenię sobie różnorodność komentarzy, poziom wnikliwości czy nawet styl, więc niektóre powtórzenia są akceptowalne. Moje polecajki z kategorii &quot;Polityka&quot;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;@PolitykaInsightYT&quot;&gt;Polityka Insight&lt;&#x2F;a&gt; - za kompetencje branżowe. Dodatkowo ich kanał na YouTube publikuje program &quot;Dzieje się&quot;, który też jest dobry&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;@OKOpress&quot;&gt;OKO.press&lt;&#x2F;a&gt; - za różnorodność tematów, dobre śmieszki Dominiki Sitnickiej oraz wynikowe kiśnięcie Agaty Szczęśniak&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;@ORB_NEWS&quot;&gt;ORB&lt;&#x2F;a&gt; - bo dobra piguła i poziom memiczności&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Pomysł drugi: szorty 🩳. Dużo kanałów jutubowych publikuje fragmenty swoich programów w postaci krótkich filmów, przez co zamiast jednego wpisu na publikację mamy ich siedem - pełny film plus sześć szortów. Na szczęście istnieje możliwość subskrybowania pojedynczych list, a YouTube automatycznie tworzy listy dla pełnych filmów, krótkich filmów oraz strumieni na żywo. W ten sposób z większości kanałów można wywalić spam. W przypadku innych, można subskrybować cały kanał.&lt;&#x2F;p&gt;
&lt;p&gt;Dobrym przykładem kanału z dobrej jakości szortami jest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;@Elektryfikacja&quot;&gt;Elektryfikacja&lt;&#x2F;a&gt; Jakuba Wiecha - no bo paczcie to złoto:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=few_VL-mfgo&quot;&gt;POV: dyskutujecie o podstawowej wiedzy naukowej w Internecie&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=QLJDfTjD5E4&quot;&gt;Debunk: Trump vs wiatraki&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Pomysł trzeci: wywalenie agregatorów oraz spamerów. Trzy konkretne przykłady - oczywiście jest ich więcej, to coś, co trzeba monitorować na bieżąco:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;strona mojego miasta (wspaniale, że w ogóle ma RSSa!) - na której swoje informacje publikują chyba wszystkie urzędy i wydziały. Być może warto ograniczyć do np. mojej dzielnicy oraz jednego lub dwóch najważniejszych tematów, np. transport i infrastruktura&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.macrumors.com&#x2F;&quot;&gt;MacRumors&lt;&#x2F;a&gt; - dużo ważnych informacji z branży, ale również dużo reklam udających promocje. Tutaj chyba lepiej zdać się na ludzi z branży, których jest zadziwiająco dużo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;publicystyka.ngo.pl&#x2F;&quot;&gt;Publicystyka NGO.pl&lt;&#x2F;a&gt; - wygląda jak agregator dla dziesiątek organizacji, więc liczba publikacji jest nie do ogarnięcia. Przy okazji: &lt;strong&gt;NGO.pl NIE MA WŁASNEGO RSSA - WSTYD!&lt;&#x2F;strong&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rss.mtsz.pl&#x2F;?szukaj=ngo.pl&quot;&gt;Na szczęście mają mnie.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Pomysł czwarty: testowanie subskrypcji. Utworzyłem osobną kategorię w moim czytniku, do którego będę wrzucał nowe subskrypcje do obserwacji. Jeśli po jakimś czasie stwierdzę, że mnie nie obciążają zanadto, przesunę je do głównej kategorii. Myślę, że to pomoże mi lepiej kontrolować dodawanie nowych źródeł.&lt;&#x2F;p&gt;
&lt;p&gt;Pomysł piąty: przycisk &quot;oznacz wszystko jako przeczytane&quot; nie gryzie. Nieprzeczytane artykuły nie wrócą w nocy i nie zrobią nikomu krzywdy. Za tydzień i tak będzie kolejna porcja artykułów nie do ogarnięcia. Używanie tego przycisku to wyraz szacunku do własnego czasu.&lt;&#x2F;p&gt;
&lt;p&gt;Pomysł szósty: zawsze jedno źródło. Niektórzy twórcy mają bloga, podcast, kanał na jutubie, fejsa, twittexa, instagrama - i na każdym z nich publikują coś odrobinę innego. Chęć śledzenia tego wszystkiego naraz powoduje koszmarną ilość duplikatów. Reguła jest prosta: jeden twórca - jedno źródło. Trzeba się pogodzić z tym, że niektóre rzeczy umkną. Skoro ktoś publikuje coś na Instagramie, to ta rzecz po prostu nie może być ważna.&lt;&#x2F;p&gt;
&lt;p&gt;Myślę, że to dobra podstawa do ujarzmienia chaosu. Czas na wdrożenie.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;116347607077651142&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Git jest niesamowity (gościnnie Obsidian + iCloud)</title>
        <published>2026-03-19T11:09:00+00:00</published>
        <updated>2026-03-19T11:09:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-03-19-git-jest-niesamowity-goscinnie-obsidian-icloud/"/>
        <id>https://mtsz.pl/blog/2026-03-19-git-jest-niesamowity-goscinnie-obsidian-icloud/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-03-19-git-jest-niesamowity-goscinnie-obsidian-icloud/">&lt;p&gt;No więc mam sobie tego &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obsidian.md&#x2F;&quot;&gt;Obsidiana&lt;&#x2F;a&gt;, w którym prowadzę praktycznie całe swoje życie cyfrowe. Ostatnio przeniosłem tam księgowość, dokumentację medyczną, a i rozważam rezygnację ze &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Syllogomania&quot;&gt;zbieractwa&lt;&#x2F;a&gt; zdjęć w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;immich.app&#x2F;&quot;&gt;Immichu&lt;&#x2F;a&gt; - nigdy nie przeglądam tych dziesiątek tysięcy zdjęć - i zamiast tego wrzucanie relacji z kilkoma wybranymi zdjęciami z ważnych dla mnie wydarzeń czy wyjazdów do dokumentu. Dużo lepiej się to przegląda, dużo łatwiej do tego wrócić. Obsidian ma nawet funkcję &quot;prezentacja slajdów&quot;, która robi dobrą robotę np. na slajdowisko.&lt;&#x2F;p&gt;
&lt;p&gt;Jednym z zagadnień do ogarnięcia jest temat synchronizacji danych między urządzeniami. Chcę mieć dostęp do mojego &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;help.obsidian.md&#x2F;vault&quot;&gt;skarbca&lt;&#x2F;a&gt; zarówno na komputerze, gdzie pracuję i tworzę dokumenty, oraz na telefonie, gdzie następnie &quot;konsumuję&quot; te dokumenty - na przykład odhaczam zadania z listy zadań czy zakupy z listy zakupów. Ważnym tematem jest również kopia zapasowa, najlepiej zgodnie z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Backup#3-2-1_Backup_Rule&quot;&gt;zasadą 3-2-1&lt;&#x2F;a&gt; (trzy kopie, dwa urządzenia, jedno gdzie indziej).&lt;&#x2F;p&gt;
&lt;p&gt;Mój dotychczasowy system składał się z następujących komponentów:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;w Obsidianie zainstalowałem wtyczkę &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vrtmrz&#x2F;obsidian-livesync&quot;&gt;LiveSync&lt;&#x2F;a&gt;, w której skonfigurowałem synchronizację do &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;couchdb.apache.org&#x2F;&quot;&gt;CouchDB&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;instancję CouchDB miałem postawioną jako &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Dockerowy&lt;&#x2F;a&gt; kontener wewnątrz maszyny wirtualnej z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;index.pl.html&quot;&gt;Debianem&lt;&#x2F;a&gt; postawionej w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.proxmox.com&#x2F;en&#x2F;&quot;&gt;Proxmoxie&lt;&#x2F;a&gt; na moim domowym serwerze&lt;&#x2F;li&gt;
&lt;li&gt;ponieważ wtyczka LiveSync narzekała na certyfikat SSL z podpisem własnym, wykonałem imponujący piruet, tworząc fejkowy certyfikat w domenie tej strony - więc z poprawną hierarchią i przedwstępnie zaufanym wystawcą - a następnie w moim wirtualnym routerze &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opnsense.org&#x2F;&quot;&gt;OPNsense&lt;&#x2F;a&gt; postawionym na Proxmoxie wstawiłem przekierowanie, żeby adres, którego użyłem, leciał do kontenera, zamiast do internetów&lt;&#x2F;li&gt;
&lt;li&gt;ponieważ taki system działał jedynie w mojej sieci domowej, w OPNsense dodałem również obsługę &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Wirtualna_sie%C4%87_prywatna&quot;&gt;wirtualnej sieci prywatnej&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.wireguard.com&#x2F;&quot;&gt;WireGuard&lt;&#x2F;a&gt;, a następnie każde urządzenie, na którym chciałem używać Obsidiana, dodałem jako klient VPNa&lt;&#x2F;li&gt;
&lt;li&gt;cały skarbiec wersjonowałem również w repozytorium Git, aczkolwiek pliki samego repozytorium leżały poza skarbcem, i LiveSync ich nie obejmował&lt;&#x2F;li&gt;
&lt;li&gt;od czasu do czasu LiveSync kosmicznie się wywalał, więc jako osobny punkt dodaję tę całą pracę potrzebną do przywrócenia systemu do równowagi&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Słuchajcie: to &lt;strong&gt;nie jest&lt;&#x2F;strong&gt; prosty system.&lt;&#x2F;p&gt;
&lt;p&gt;Na szczęście Obsidian oferuje dwie natywne opcje synchronizacji: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obsidian.md&#x2F;sync&quot;&gt;Sync&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;en-us&#x2F;102651#advanced&quot;&gt;iCloud&lt;&#x2F;a&gt;. Obie te opcje twierdzą, ze są szyfrowane od końca do końca, dlatego wybrałem po prostu to, co już miałem - iCloud.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz tak: ja już wcześniej używałem iClouda. Nie był najgorszy, ale w kontekście moich wymagań miał jedną fundamentalną wadę - synchronizowanie repozytorium Git w iCloudzie to jest &lt;strong&gt;KOSZMAR&lt;&#x2F;strong&gt;. Problemem jest prawdopodobnie to, w jaki sposób Git przechowuje zmiany - każda jest osobnym plikiem, ich tworzenie jest w pewnym sensie poza kontrolą; zapisujesz zmiany, i pliki &quot;się robią&quot;. Osobiście mam nawyk zapisywania małych zmian bardzo często, i pewnie iCloud tego nie lubił. Poza tym, synchronizowanie repo w ogóle nie było mi potrzebne, mój ówczesny system z LiveSync tego w ogóle nie miał. Dlatego mam jasno postawiony cel: wracam do iClouda, ale tak, żeby repozytorium się nie synchronizowało.&lt;&#x2F;p&gt;
&lt;p&gt;Zacznijmy od samego niesynchronizowania. W iCloud działa to tak, że do nazwy pliku wystarczy dopisać &lt;code&gt;.nosync&lt;&#x2F;code&gt;, i folder po prostu się nie synchronizuje (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;discussions.apple.com&#x2F;thread&#x2F;253184744&quot;&gt;źródło&lt;&#x2F;a&gt;). Tworzę folder &lt;code&gt;ObsidianRepo.nosync&lt;&#x2F;code&gt;, w jego wnętrzu uruchamiam &lt;code&gt;git init&lt;&#x2F;code&gt;, repozytorium się tworzy, ale nie jest synchronizowane w iCloud - żyje jedynie na moim komputerze - doskonale.&lt;&#x2F;p&gt;
&lt;p&gt;Tylko &quot;co teras?&quot;. Mam folder z repo (konkretnie to z folderem &lt;code&gt;.git&lt;&#x2F;code&gt;), który się nie synchronizuje, ale wszystkie inne pliki przecież powinny się synchronizować. Tutaj wchodzimy w magię Gita. Git pozwala na zmianę lokalizacji plików, które wersjonuje, przy użyciu mechanizmu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-worktree&quot;&gt;worktree&lt;&#x2F;a&gt;. Generalnie możesz powiedzieć Gitowi &quot;to nie są pliki, których szukacie&quot; i wskazać inny folder, za pomocą komendy albo wpisu w pliku &lt;code&gt;config&lt;&#x2F;code&gt;. Sposób, w jaki ja to zrobiłem, wygląda następująco:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;aplikacja Obsidian tworzy na iCloud swój &quot;folder aplikacji&quot;, w którym przechowuje wszystkie pliki do synchronizacji&lt;&#x2F;li&gt;
&lt;li&gt;w tym folderze tworzę folder &lt;code&gt;Obsidian.nosync&lt;&#x2F;code&gt; i w nim inicjalizuję repozytorium - repo się nie synchronizuje ✅&lt;&#x2F;li&gt;
&lt;li&gt;następnie do konfiguracji repo dopisuję &lt;code&gt;worktree&lt;&#x2F;code&gt; za pomocą komendy &lt;code&gt;git config core.worktree ..&#x2F;..&lt;&#x2F;code&gt; - od teraz cały &quot;folder aplikacyjny&quot; Obsidiana jest wersjonowany ✅&lt;&#x2F;li&gt;
&lt;li&gt;to tyle, koniec&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rozwiązanie działa doskonale, teraz mogę wywalić i zapomnieć o utrzymywaniu: CouchDB, fejkowego certyfikatu oraz ręcznego przekierowania w OPNsense. Docker, Debian, Proxmox i OPNsense na razie zostają - ale kto wie, może wpadnę na kolejny pomysł, w którym będę rezygnował z kolejnej rzeczy, której się uczyłem przez poprzednie pół roku. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=bGAdUOkU2Is&quot;&gt;Nie żałuję niczego 🐓&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;116255830943400743&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Smol is better - w szafie i w internecie</title>
        <published>2026-03-03T09:55:00+00:00</published>
        <updated>2026-03-03T09:55:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-03-03-smol-is-better/"/>
        <id>https://mtsz.pl/blog/2026-03-03-smol-is-better/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-03-03-smol-is-better/">&lt;p&gt;Mam taki projekt, żeby zinwentaryzować swój majątek. Głównym celem jest pozbycie się rzeczy, których nie używam i &quot;odgracenie&quot; mieszkania (sekcja &lt;a href=&quot;&#x2F;oddam&#x2F;&quot;&gt;Oddam&lt;&#x2F;a&gt; na tej stronie w końcu będzie potraktowana poważnie). Chciałem użyć do tego aplikacji &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sysadminsmedia&#x2F;homebox&quot;&gt;HomeBox&lt;&#x2F;a&gt;, ale mi nie podeszła z powodu ograniczeń dotyczących tagów albo zdjęć, których już nawet nie pamiętam. Poirytowany, porzuciłem temat na jakiś czas. Jakieś dwa tygodnie temu uświadomiłem sobie, że przecież już mam rozwiązanie: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obsidian.md&quot;&gt;Obsidian&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;Obsidian od jakiegoś czasu ma takie fajne narzędzie, jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;help.obsidian.md&#x2F;bases&quot;&gt;Bazy&lt;&#x2F;a&gt;. Baza pozwala na wyświetlanie Obsydianowych dokumentów w postaci listy albo kafelków, dokładając do tego filtrowanie, grupowanie i sortowanie. To są dosłownie wszystkie rzeczy, jakich potrzebuję. Każdy inwentaryzowany przedmiot będzie miał swój dokument, wraz z opisem, zdjęciem oraz atrybutami takimi jak rodzaj (elektronika, ubrania...) czy lokalizacja (sypialnia szafa, korytarz pawlacz...). Atrybuty w Obsidianie zapisuje się w formie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.markdownlang.com&#x2F;advanced&#x2F;frontmatter.html&quot;&gt;YAMLowego frontmattera&lt;&#x2F;a&gt;, tak wygląda szablon:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;yaml&quot;&gt;---
typ: &amp;quot;[[🗃️ Mam.base]]&amp;quot;
zdjęcie:
lokalizacja:
kategoria:
---
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rezultatem jest piękny inwentarz; poniżej jego fragment. Bez serwera, bez Dockera, bez reverse-proxy, przy użyciu narzędzia, którego już od dawna używam. To mi się podoba, o to chodzi.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2026-03-03-smol-is-better&#x2F;mam.png&quot; alt=&quot;zrzut ekranu z bazy Obsidiana z inwentarzem&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;W duchu tej zmiany postanowiłem również przeorać niniejszą stronę. Do tej decyzji zainspirował mnie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;adele.pages.casa&#x2F;md&#x2F;blog&#x2F;building-your-first-smolweb-page.md&quot;&gt;ten wpis na blogu Adële&lt;&#x2F;a&gt;, skąd dotarłem do strony projektu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;smolweb.org&#x2F;index.html&quot;&gt;smolweb&lt;&#x2F;a&gt;. Podoba się to dla mnie. Rozstaję się ze stylem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;not-matthias&#x2F;apollo&quot;&gt;Apollo&lt;&#x2F;a&gt;, którego używałem do tej pory, na ten moment strona opiera się o &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;simplecss.org&#x2F;&quot;&gt;SimpleCSS&lt;&#x2F;a&gt;, ale docelowo napiszę sobie cały styl samodzielnie. Najlepsza zależność to brak zależności! Wywaliłem też wstawianie różnych jutubów i soundcloudów na stronie, bo smolweb ma bardzo radykalną opinię na temat dżawaskryptów, szczególnie tych walących poza domenę. Także komci z Mastodona też nie będzie - ale będzie link! Trudno, smolweb zobowiązuje.&lt;&#x2F;p&gt;
&lt;p&gt;Ścieżka dźwiękowa do wpisu: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=o4YKDrw5FH0&quot;&gt;Autolux - Becker&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No i wiadomo, musi być obrazek.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2026-03-03-smol-is-better&#x2F;smol.jpg&quot; alt=&quot;mem z very smol pieskiem&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;116165383676961216&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Skróty iOS ratują od YouTube&#x27;a</title>
        <published>2026-02-13T10:37:00+00:00</published>
        <updated>2026-02-13T10:37:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-02-13-skroty-ios-ratuja-od-youtube-a/"/>
        <id>https://mtsz.pl/blog/2026-02-13-skroty-ios-ratuja-od-youtube-a/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-02-13-skroty-ios-ratuja-od-youtube-a/">&lt;p&gt;Znalazłem dzisiaj coś bardzo ciekawego: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cherrilang.org&quot;&gt;Cherri 🍒&lt;&#x2F;a&gt; to język programowania (oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Transpilator&quot;&gt;transpilator&lt;&#x2F;a&gt;), w którym można pisać &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;pl-pl&#x2F;guide&#x2F;shortcuts&#x2F;welcome&#x2F;ios&quot;&gt;Skróty iOS&lt;&#x2F;a&gt;. Skróty iOS to takie skrypty, które można sobie można wyklikać w aplikacji Skróty, a które automatyzują różne rzeczy. Dostępna jest cała paleta czynności, takich jak sterowanie muzyką, obróbka tekstu, wyciąganie pojedynczych informacji ze stron internetowych na podstawie adresu. Dane można przekazywać z jednej czynności do drugiej, i dzięki temu tworzyć całkiem przydatne narzędzia.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz nie trzeba już karkołomnie wyklikiwać kolejnych kroków skryptu - wystarczy napisać prosty kod, i jedną komendą:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;cherri NAZWA_PLIKU.cherri --open
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;można go dodać do swojej biblioteki Skrótów. Jest nawet &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;playground.cherrilang.org&#x2F;&quot;&gt;piaskownica do eksperymentowania&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Na rozgrzewkę wrzucam dwa Skróty&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;YouTube bez reklam z działającym &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Picture-in-picture&quot;&gt;OwO (Obraz w Obrazie)&lt;&#x2F;a&gt; i odtwarzaniem w tle. Właściwie to wszystko, co obsługuje &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yt-dlp&#x2F;yt-dlp&quot;&gt;yt-dlp&lt;&#x2F;a&gt;. Do działania wymagana jest instalacja aplikacji &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;holzschu&#x2F;a-shell&quot;&gt;a-Shell mini&lt;&#x2F;a&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;us&#x2F;app&#x2F;a-shell-mini&#x2F;id1543537943&quot;&gt;jest w AppStore&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre&gt;&lt;code data-lang=&quot;c&quot;&gt;#include &amp;#39;actions&#x2F;web&amp;#39;

#define glyph fish
#define color darkblue
#define name Blub
#define from sharesheet
#define inputs url
#define noinput stopwith &amp;quot;Udostępnij mi link&amp;quot;

const command = &amp;quot;pip install --quiet yt-dlp \
yt-dlp --get-url --format best --no-warnings &amp;#39;{ShortcutInput}&amp;#39;&amp;quot;
const result = rawAction(&amp;quot;AsheKube.app.a-Shell-mini.ExecuteCommandIntent&amp;quot;, {
	&amp;quot;ShowWhenRun&amp;quot;: false,
	&amp;quot;command&amp;quot;: &amp;quot;{command}&amp;quot;,
	&amp;quot;openWindow&amp;quot;: &amp;quot;close&amp;quot;
})
openURL(result)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Przekierowanie do alternatywnych wersji stron - w tym przypadku z Reddita na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;redlib-org&#x2F;redlib&quot;&gt;RedLib&lt;&#x2F;a&gt; oraz z Twittera na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zedeus&#x2F;nitter&#x2F;&quot;&gt;Nitter&lt;&#x2F;a&gt;, ale dodanie nowych możliwości jest banalnie proste.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre&gt;&lt;code data-lang=&quot;c&quot;&gt;#include &amp;#39;actions&#x2F;text&amp;#39;
#include &amp;#39;actions&#x2F;web&amp;#39;
#include &amp;#39;actions&#x2F;scripting&amp;#39;

#define color red
#define glyph horse
#define name Redi
#define from sharesheet
#define inputs url
#define noinput stopwith &amp;quot;Udostępnij mi link&amp;quot;

const host = getURLDetail(ShortcutInput, &amp;quot;Host&amp;quot;)
const options = {
	&amp;quot;reddit.com&amp;quot;: &amp;quot;farside.link&#x2F;redlib&amp;quot;,
	&amp;quot;www.reddit.com&amp;quot;: &amp;quot;farside.link&#x2F;redlib&amp;quot;,
	&amp;quot;x.com&amp;quot;: &amp;quot;farside.link&#x2F;nitter&amp;quot;,
	&amp;quot;www.x.com&amp;quot;: &amp;quot;farside.link&#x2F;nitter&amp;quot;,
}
const alter = getValue(options, host)
const redir = replaceText(host, alter, ShortcutInput)
openURL(redir)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dzięki Wszechświatowi za ludzi cywilizujących technologię, którą giganci technologiczni... wiecie co robią.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;116062907147096057&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nie chcę, ale muszę używać poczty elektronicznej</title>
        <published>2026-02-11T20:48:00+00:00</published>
        <updated>2026-02-11T20:48:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-01-31-nie-chce-ale-musze-uzywac-poczty-elektronicznej/"/>
        <id>https://mtsz.pl/blog/2026-01-31-nie-chce-ale-musze-uzywac-poczty-elektronicznej/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-01-31-nie-chce-ale-musze-uzywac-poczty-elektronicznej/">&lt;p&gt;Niecały rok temu nieco bardziej niż wcześniej zabolało mnie to, że moje podstawowe konto poczty elektronicznej znajduje się na serwerach firmy Google - chodzi o Gmail. Właśnie miałem wypisać wszystkie powody tego bólu, ale dosłownie boli mnie myślenie o tych powodach. Jeśli wiesz, to wiesz, a jeśli nie wiesz, to albo Cię to nie obchodzi, albo właśnie teraz szukasz - wszystko w temacie już zostało powiedziane. Nie ma potrzeby, żebym cierpiał.&lt;&#x2F;p&gt;
&lt;p&gt;W ogóle: o co chodzi z tym nie-chceniem-ale-muszeniem? Tak się stało, że adres poczty elektronicznej stał się de facto identyfikatorem, nośnikiem tożsamości praktycznie w całym obserwowalnym internecie. Praktycznie każda aplikacja internetowa, usługa, serwis, portal, forum - wszystko chce ode mnie mojego emaila. Wydaje mi się - ale nie wiem, czy to nie halucynacje od czystego powietrza - że były takie czasy, gdy wymyślałem sobie unikalny login, hasło - i gotowe; nie musiałem uzależniać bytu w jednej części internetu od innego bytu w innej części. Pamiętam nawet debaty na temat tego, kiedy &quot;skończą się&quot; loginy! Są też inne sposoby na unikalną identyfikację, np. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Infrastruktura_klucza_publicznego&quot;&gt;klucze kryptograficzne&lt;&#x2F;a&gt;. Nie trzeba wtedy wymyślać żadnych loginów ani haseł, a wcześniej niż skończy się pula kluczy, nastąpi &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;%C5%9Amier%C4%87_cieplna_Wszech%C5%9Bwiata&quot;&gt;Wielki Chłód&lt;&#x2F;a&gt;. Ale tego świata już nie ma. Albo jeszcze nie ma. Po prostu - nie ma.&lt;&#x2F;p&gt;
&lt;p&gt;Takiego stanu rzeczy są plusy dodatnie i plusy ujemne. Nieskończoną zaletą emaila jest jego interoperacyjność. Całkowicie normalne jest, żeby wysłać komuś maila z Gmaila na Pocztę Onet, Pocztę WP, Outlook, Yahoo czy dosłownie cokolwiek. Zapytajcie kogoś na ulicy, czemu nie można wysłać wiadomości z Facebooka na Twittera, to popatrzy na Was jak na... człowieka z Księżyca. No więc zakładasz sobie tego jednego maila, i potem używasz go wszędzie do wszystkiego. Konto na fejsie? Email. mObywatel? Email. Prywatna placówka medyczna? Email. Oho, zaczyna robić się poważnie. Nagle od jednego konta zależy całe Twoje życie cyfrowe. I weź tu teraz oddaj pieczę nad tym wszystkim firmie Google. Ja mam obawy. Dotyczące bezpieczeństwa, prywatności, wykorzystywania danych w nieetycznych celach, manipulacji wynikami wyszukiwania. Są też poważniejsze problemy, np. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=CE0EB5bXj14&quot;&gt;taki&lt;&#x2F;a&gt; albo &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;niebezpiecznik.pl&#x2F;post&#x2F;przejete-konto-google-gmail-jak-odzyskac-pomoc-suport-kontakt&#x2F;&quot;&gt;taki&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Okej, jeśli nie Gmail, to co? W takich sprawach mam kilka domyślnych miejsc, w których szukam sugestii: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.privacyguides.org&#x2F;&quot;&gt;Privacy Guides&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;thenewoil.org&#x2F;&quot;&gt;The New Oil&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;techlore.tech&#x2F;&quot;&gt;Techlore&lt;&#x2F;a&gt;. Spędziłem trochę czasu, żeby zapoznać się ze wszystkimi opcjami i ostatecznie padło na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tuta.com&#x2F;pl&quot;&gt;Tuta&lt;&#x2F;a&gt;. To, co najbardziej mnie przekonało, to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Szyfrowanie_od_ko%C5%84ca_do_ko%C5%84ca&quot;&gt;szyfrowanie od końca do końca&lt;&#x2F;a&gt; oraz możliwość podpięcia &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Domena_internetowa&quot;&gt;własnej domeny&lt;&#x2F;a&gt; i tworzenia aliasów. No i okazało się, że aliasy są dużo bardziej przydatne, niż myślałem, a szyfrowanie, nie dość że praktycznie bezużyteczne, to spowodowało, że z Tutą się żegnam za dwa miesiące (bo wtedy kończy się opłacona subskrypcja, tak naprawdę to już jej nie używam).&lt;&#x2F;p&gt;
&lt;p&gt;Sprawa pierwsza: własna domena. Jeśli zakładasz konto pocztowe u jakiegoś dostawcy, to również od niego dostajesz domenę (czyli tę końcówkę adresu). W przypadku Gmaila jest to &lt;code&gt;@gmail.com&lt;&#x2F;code&gt;, w przypadku Onetu może to być np. &lt;code&gt;@buziaczek.pl&lt;&#x2F;code&gt;. Jeśli z jakiegokolwiek powodu dana firma przestanie świadczyć usługi pocztowe, to ze swoim adresem możesz się po prostu pożegnać. Własna domena rozwiązuje ten problem. Dostawca poczty X wysypał się? Bierzesz swoją domenę &lt;code&gt;@zielonygroszek.pl&lt;&#x2F;code&gt; i przepinasz do innego dostawcy - wszystkie adresy pozostają takie same. Prawdziwa, niezależna od (prawie) nikogo tożsamość. Naprawdę nie wiem, co musiałoby się stać (legalnego), żeby stracić domenę - innego niż jej nieopłacenie. Tuta w najtańszej opcji pozwala na podpięcie trzech domen - super, bo mi wystarczy jedna.&lt;&#x2F;p&gt;
&lt;p&gt;Sprawa druga: aliasy. Alias to takie fajne narzędzie, które pozwala tworzyć nowe adresy email, których jedynym celem jest przekierowanie maila na inny adres. Chcesz zapisać się na jakiś newsletter i mieć łatwe filtrowanie? Robisz alias. Chcesz mieć profesjonalny adres do określonych zadań? Alias. Chcesz wiedzieć, kto dokładnie sprzedał Twój adres mailowy spamerom? Jeśli robisz osobny alias do każdego serwisu, wtedy od razu zobaczysz, że spam przychodzi na alias, którego używasz w tym dziwnym sklepie internetowym. Albo w swoim banku... Teraz już wiesz. Co więcej, możesz alias skasować i adresu już nie ma, a spamer jedyne co dostanie, to błąd &quot;Odbiorca nie istnieje&quot;. A tak naprawdę to istniejesz! Tuta pozwala na tworzenie nieskończonej (chyba) ilości aliasów do własnej domeny, wiec powinno wystarczyć.&lt;&#x2F;p&gt;
&lt;p&gt;Sprawa trzecia: szyfrowanie. W ogólności szyfrowanie jest bardzo ważne, ponieważ prywatność. W przypadku maila temat jest mocno skomplikowany. Istnieją otwarte standardy, z których korzysta promil ludzi, i które są dosyć karkołomne dla zwykłego użytkownika ajfona. Istnieją usługi, które starają się to ułatwić - takie jak Proton czy właśnie Tuta - ale znowu: robią to albo karkołomnie, albo mocno ograniczając użyteczność. W przypadku Tuta szyfrowanie działa tak, że maile pomiędzy użytkownikami Tuta są szyfrowane domyślnie, a w przypadku wysyłania do ludzi z zewnątrz, Tuta tworzy wirtualną skrzynkę dla adresu odbiorcy z hasłem, które ustala się podczas wysyłania. Trzeba potem to hasło przekazać innym kanałem. Tuta nie obsługuje protokołów IMAP czy SMTP - i z tego co wiem, nie planuje - więc nie da się podpiąć konta do swojego ulubionego programu pocztowego. Te dwa fakty połączone w jedną wielką uciążliwość sprawiły, że z Tutą się żegnam.&lt;&#x2F;p&gt;
&lt;p&gt;A gdzie ląduję? A w OVH. W OVH mam wszystkie swoje domeny, a do każdej domeny dostaję w gratisie 100MB hostingu (z którym jeszcze nie wiem co zrobię, bo hosting mam na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mikr.us&#x2F;?r=mtszpl&quot;&gt;Mikrusowym Cytrusie LINK AFILIACYJNY KLIKNIJ NATYCHMIAST&lt;&#x2F;a&gt;) oraz jedną skrzynkę pocztową 5GB. No więc robię sobie tę jedną skrzynkę, a następnie tworzę wszystkie używane aliasy za pomocą wygodnego narzędzia CLI &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ovh&#x2F;ovhcloud-cli&quot;&gt;ovhcloud&lt;&#x2F;a&gt;, które co prawda nie ma jeszcze takiej możliwości, ale zaraz powinno mieć, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ovh&#x2F;ovhcloud-cli&#x2F;pull&#x2F;134&quot;&gt;bo ją napisałem&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I teraz mogę spokojnie dodać do klienta poczty moją własną, niezależną, odizolowaną, &quot;oaliasowaną&quot; skrzynkę - tuż obok pracowego Gmaila.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;116057360298318837&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Odkurzacz Mikrob</title>
        <published>2026-01-31T17:49:00+00:00</published>
        <updated>2026-01-31T17:49:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2026-01-31-odkurzacz-mikrob/"/>
        <id>https://mtsz.pl/blog/2026-01-31-odkurzacz-mikrob/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2026-01-31-odkurzacz-mikrob/">&lt;p&gt;Plan na dzisiaj: zhakować odkurzacz.&lt;&#x2F;p&gt;
&lt;p&gt;Zacznę od tego, że w momencie pisania tej notatki, nie jest ona nawet częścią bloga - w sensie nie jest w folderze &quot;Blog&quot;, gdzie powstała większość wpisów. Na razie piszę to w moim prywatnym &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obsidian.md&quot;&gt;skarbcu Obsidianowym&lt;&#x2F;a&gt;, bo już mam notatkę dotyczącą odkurzacza, a w sumie mogę ją przeredagować na styl wpisu i opublikować. To nie jest tak, że tu będą jakieś wielkie tajemnice - a może komuś się przyda, tak jak mi dosłownie trzy dni temu przydał się mój własny wpis o konfigurowaniu tożsamości repozytoriów Git.&lt;&#x2F;p&gt;
&lt;p&gt;Dlaczego chcę zhakować odkurzacz? Kilka powodów. Bo niepokoi mnie, że urządzenie z może kamerą, może lidarem, może mikrofonem, dzwoni do domu w Chinach. Bo chcę mieć kontrolę nad moimi urządzeniami. Bo dowiedziałem się, że istnieje coś takiego jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;valetudo.cloud&#x2F;&quot;&gt;Valetudo&lt;&#x2F;a&gt;. Bo lubię &quot;komputerkować&quot;. Chyba wszystkie powody. Do rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;Pacjent: Mi Robot Vacuum-Mop P, model &lt;code&gt;STYTJ02YM&lt;&#x2F;code&gt; (spisane z naklejki na odkurzaczu). Odkurzacz kupiłem dawno temu chyba w sklepie Xiaomi - nie ogarniam wszystkich krzyżówek tych chińskich firm: Xiaomi, Mi, Mijia, Viomi i jeszcze z piętnaście innych nazw, które pojawiają się w losowych miejscach - punktem odniesienia jest numer modelu. Odkurzacz o dziwo całkiem &quot;serwisowalny&quot; - jakiś czas temu spalił się w nim jeden z silników, więc zamówiłem zamiennik na AliExpress za około 20 zł, wymieniłem, okazało się, że się pomyliłem - to nie ten silnik się spalił, tylko ten drugi, więc zamówiłem ten drugi, tym razem za 40 zł, wymieniłem, i odkurzacz z powrotem działa bardzo dobrze.&lt;&#x2F;p&gt;
&lt;p&gt;O samym Valetudo dowiedziałem się nie pamiętam skąd. Na moje szczęście, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;valetudo.cloud&#x2F;pages&#x2F;general&#x2F;supported-robots.html#xiaomi_vacuummop_p&quot;&gt;model mojego odkurzacza jest wspierany&lt;&#x2F;a&gt;. Okazuje się, że odkurzacz tak naprawdę nazywa się &quot;3irobotix CRL-200S&quot;. Albo i nie. Przy okazji: znalazłem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;codetiger&#x2F;VacuumRobot&quot;&gt;ciekawe repozytorium&lt;&#x2F;a&gt;, gdzie ktoś próbuje zrobić pełną inżynierię wsteczną, popieram! Instrukcja mówi, że model &lt;code&gt;viomi.vacuum.v8&lt;&#x2F;code&gt; jest podatny na &quot;uceglenie&quot;, i oczywiście ten model mam. Ale w innych miejscach jest napisane, że to jest takie pół na pół, więc postanowiłem zaryzykować.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwszy krok to wbicie do systemu odkurzacza. Port USB znajduje się pod baterią, która jest przykryta klapką z czterema śrubkami. Do połączenia z odkurzaczem używa się &lt;code&gt;adb&lt;&#x2F;code&gt; czyli &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;tools&#x2F;adb&quot;&gt;Android Debug Bridge&lt;&#x2F;a&gt; - bardzo ciekawe. Oczywiście nie mogło  obyć się bez kilku problemów:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;odkurzacz w ogóle nie włącza się, jeśli wykryje podłączony kabel USB,&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;adb&lt;&#x2F;code&gt; jest dostępne dosłownie przez trzy sekundy podczas uruchamiania odkurzacza, później urządzenie przestaje być wykrywalne,&lt;&#x2F;li&gt;
&lt;li&gt;powłoka, do której się łączymy, wymaga podania hasła.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Na te problemy jest rozwiązanie w repozytorium w postaci mało eleganckiego skryptu, który w pętli wali do odkurzacza komendami, aż ten zacznie słuchać. Poniżej wrzucam moje bardziej eleganckie rozwiązanie, które robi dokładnie to samo, ale jest krótsze, bardziej eleganckie, no i moje:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
adb wait-for-device # można kulturalnie? można

# naprawiamy komendę `adb shell`
temp_file=$(mktemp)
trap &amp;quot;rm -f &amp;#39;$temp_file&amp;#39;&amp;quot; EXIT
cat &amp;gt;&amp;quot;$temp_file&amp;quot; &amp;lt;&amp;lt;&amp;quot;EOF&amp;quot;
#!&#x2F;bin&#x2F;sh
export ENV=&amp;#39;&#x2F;etc&#x2F;adb_profile&amp;#39;
exec &#x2F;bin&#x2F;sh &amp;quot;$@&amp;quot;
EOF
chmod +x &amp;quot;$temp_file&amp;quot;
adb push -a &amp;quot;$temp_file&amp;quot; &#x2F;bin&#x2F;adb_shell

# usuwamy symboliczne dowiązanie do oryginalnego oprogramowania
adb shell &amp;quot;rm &#x2F;etc&#x2F;rc.d&#x2F;S90robotManager&amp;quot;

# robimy backup
mkdir -p backup
adb pull &#x2F;proc&#x2F;partitions backup&#x2F;
adb shell &amp;quot;find &#x2F;dev -name &amp;#39;nand*&amp;#39;&amp;quot; | tr -d &amp;#39;\r&amp;#39; | xargs -I {} adb pull {} backup&#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Skrypt uruchamiamy - i on sobie grzecznie czeka - a my wyłączamy odkurzacz, podłączamy kabel USB do samego odkurzacza, następnie włączamy odkurzacz i natychmiast po zapaleniu się diody na odkurzaczu podłączamy kabel USB do komputera. Skrypt w pewnym momencie odnajduje urządzenie, robi z nim co trzeba, i od tej pory dostęp do urządzenia mamy już bez problemu. Ostatnia linijka jest wielokrotnie złożona, ale co robi, to z folderu &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; na odkurzaczu pobiera wszystkie pliki, których nazwa zaczyna się od &lt;code&gt;nand&lt;&#x2F;code&gt;. Skrypt z oryginalnego repozytorium wypisuje nazwy wszystkich plików pliki po kolei, ale my będziemy bardziej eleganccy.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwszy etap za nami. Odkurzacz jest gotowy do hakowania.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejny krok to zbudowanie firmware. Do tego kroku przygotowane jest już &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;builder.dontvacuum.me&#x2F;&quot;&gt;narzędzie DustBuilder&lt;&#x2F;a&gt; i nie wiem, dlaczego twórca postanowił postawić całą infrastrukturę pod to, zamiast dostarczyć skrypty, ale nie będę narzekał - proces jest bajecznie prosty: wybieram mój odkurzacz, wpisuję adres email, podaję klucz publiczny - i po jednej minucie dostaję na pocztę linka do pobrania pliku &lt;code&gt;viomi.vacuum.v7_fw.tar.gz&lt;&#x2F;code&gt;. Na ten moment postanawiam zignorować fakt, ze nazwa ma &quot;v7&quot; zamiast &quot;v8&quot; - w formularzy pozycja nazywała się &quot;v7&#x2F;v8&quot;, więc mi się to składa w całość.&lt;&#x2F;p&gt;
&lt;p&gt;Żebym nie musiał się zastanawiać, napisałem sobie taki oto elegancki skrypt, który wrzuca pliki tam gdzie mają być, a następnie loguje się do odkurzacza i sprawdza dla pewności, czy pliki są tam gdzie są, a następnie zgodnie z instrukcją uruchamia instalację.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
adb push .&#x2F;dustbuilder&#x2F;viomi.vacuum.v7_fw.tar.gz &#x2F;tmp&#x2F;
adb push .&#x2F;valetudo-armv7.upx &#x2F;mnt&#x2F;UDISK&#x2F;valetudo
adb push .&#x2F;convert-robot.sh &#x2F;tmp&#x2F;
cat &amp;lt;&amp;lt;EOF | adb shell
ls -la &#x2F;tmp&#x2F;$firmware_name
ls -la &#x2F;tmp&#x2F;convert-robot.sh
ls -la &#x2F;mnt&#x2F;UDISK&#x2F;valetudo

cd &#x2F;tmp&#x2F;
chmod +x convert-robot.sh
sh .&#x2F;convert-robot.sh
tar xzvf .&#x2F;$firmware_name
chmod +x install.sh
sh .&#x2F;install.sh
exit
EOF
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Teraz czas na chwilę stresu. Naciskam enter i patrzę na konsolę. Poszło. Od teraz mój odkurzacz jest wolny. Elegancko.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=OFD0N4LNqKQ&quot;&gt;Classy Jim - The Office US&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115990815709186492&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Skryptozakładka do włosów</title>
        <published>2025-12-30T11:00:00+00:00</published>
        <updated>2025-12-30T11:00:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-12-30-skryptozakladka-do-wlosow/"/>
        <id>https://mtsz.pl/blog/2025-12-30-skryptozakladka-do-wlosow/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-12-30-skryptozakladka-do-wlosow/">&lt;p&gt;To było tak: jest sobie jakaś losowa strona drogerii: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.dm.pl&#x2F;wlosy&#x2F;pielegnacja-wlosow&#x2F;szampon&quot;&gt;https:&#x2F;&#x2F;www.dm.pl&#x2F;wlosy&#x2F;pielegnacja-wlosow&#x2F;szampon&lt;&#x2F;a&gt;. Ta strona - jak dosłownie każda jedna strona każdego jednego serwisu sprzedażowego w całym internecie - ma, (delikatnie mówiąc) &lt;del&gt;PRZEKLEŃSTWO&lt;&#x2F;del&gt; sortowanie. Co mam konkretnie na myśli? Że to nigdy nie działa sensownie. W przywołanym przykładzie sortowanie odbywa się po cenie danego produktu, więc kolejność ceny jest wypadkową ceny jednostkowej oraz ilości. Super, dokładnie o to mi chodziło, żeby szampon 10 ml za 500 zł za litr (czyli 5 zł) pojawił się przed szamponem 500 ml za 20 zł za litr (czyli 10 zł). Już pomijam fakt, że ceny jednostkowe są podane raz w kwocie za 1 litr, raz za 100 mililitrów, albo za kilogram, albo za pół, albo za 100 gramów, więc nie można ich na szybko porównać. Ja już się na tym blogu denerwowałem z dokładnie tego powodu pięć lat temu!&lt;&#x2F;p&gt;
&lt;p&gt;Na szczęście strona drogerii jest... stroną internetową - co oznacza, że możemy potraktować ją JavaScriptem, czyli tym, na co zasługuje. Plan  jest taki, jak zawsze: skrobiemy dane, zmieniamy format z internetowego na ludzki, sortujemy jak człowiek, aktualizujemy DOM, jemy pomarańcze.&lt;&#x2F;p&gt;
&lt;p&gt;Krok pierwszy. Potrzebujemy, żeby wszystkie elementy były pobrane i załadowane. Strona wyświetla 15 produktów na stronę, a żeby zobaczyć kolejne, trzeba kliknąć przycisk &quot;Więcej&quot;. Albo nie trzeba. Inspekcja przycisku &quot;Więcej&quot; pokazuje, ze ma on nadany identyfikator &lt;code&gt;load-more-products-button&lt;&#x2F;code&gt;. A to oznacza, że możemy:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;let retries = 0;
while (true) {
  await new Promise((resolve) =&amp;gt; setTimeout(resolve, 100));
  const loadMoreButton = document.getElementById(&amp;quot;load-more-products-button&amp;quot;);
  if (loadMoreButton) {
    loadMoreButton.click();
    retries = 0;
  } else retries++;
  if (retries &amp;gt; 10) break;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Co tu się dzieje? Mamy sobie nieskończoną pętlę, która robi następujące rzeczy:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;czeka 100 milisekund, żeby przeglądarka nie zestresowała się za bardzo&lt;&#x2F;li&gt;
&lt;li&gt;wyszukuje na stronie element o identyfikatorze &lt;code&gt;load-more-products-button&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;jeśli go znajdzie, to go klika - a jeśli nie, to odnotowuje nieudaną próbę&lt;&#x2F;li&gt;
&lt;li&gt;jeśli nieudanych prób będzie 10, nieskończona pętla kończy się&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Przycisk pojawia się dla każdej kolejnej strony oprócz ostatniej, stąd mamy takie wyrafinowane mechanizmy powtarzania. Podejść do tego fragmentu kodu miałem wiele. Próbowałem takich cudów jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;MutationObserver&quot;&gt;MutationObserver&lt;&#x2F;a&gt;, który sprawdza, czy jakiś element pojawił się na stronie; próbowałem nasłuchiwać wywołań metod &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;History&#x2F;pushState&quot;&gt;history.pushState&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Window&#x2F;fetch&quot;&gt;window.fetch&lt;&#x2F;a&gt; korzystając z techniki &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Monkey_patch&quot;&gt;monkey patch&lt;&#x2F;a&gt;, o której dosłownie dzisiaj się dowiedziałem; próbowałem skomplikowane układu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&#x2F;Reference&#x2F;Global_Objects&#x2F;Promise&quot;&gt;Promise&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Window&#x2F;setTimeout&quot;&gt;window.setTimeout&lt;&#x2F;a&gt;, sprawdzając wartość &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Location&#x2F;href&quot;&gt;location.href&lt;&#x2F;a&gt;. Jednak nic nie zastąpi prostego łomotania pięścią w drzwi aż do skutku. Kod działa spektakularnie. Można go sobie wkleić w konsoli przeglądarki i patrzeć, jak problemy rozwiązują się same.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejny krok to odpowiednie formatowanie i przeliczanie cen. Znowu w ruch wchodzi inspektor przeglądarkowy, z którego dowiadujemy się, że pole z ceną to &lt;code&gt;span&lt;&#x2F;code&gt; zamknięty w &lt;code&gt;div&lt;&#x2F;code&gt; z atrybutem &lt;code&gt;data-dmid=&quot;price-infos&quot;&lt;&#x2F;code&gt;.  No to zobaczmy, co tam siedzi:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;» document.querySelectorAll(&amp;quot;[data-dmid=\&amp;quot;price-infos\&amp;quot;] :first-child&amp;quot;)
  .forEach((e) =&amp;gt; console.log(e.textContent))
&amp;quot;1 l (39,95 zł za 1 l)&amp;quot;
&amp;quot;250 ml (7,98 zł za 100 ml)&amp;quot;
&amp;quot;250 ml (7,98 zł za 100 ml)&amp;quot;
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dobra, mamy ceny sklejone w jeden ciąg. Format wygląda na spójny, można go więc spróbować rozpakować regexem. Jesteście gotowi? Oto on:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;const PRICE_REGEX = &#x2F;^.*\(([\d\s,]+)\szł\sza\s([\d\s,]+)\s(.*)\)$&#x2F;;
&#x2F;&#x2F; przykład:         1 l (  39,95     zł  za    1          l   )
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Edytor, w którym piszę tego posta, nie koloruje składni regexa tak ładnie, jak zbudowany HTML, można dostać oczopląsu. Jak to zwykle bywa z regexem, jak już się go rozpisze, to on zaczyna nabierać ludzkich cech. W przykładzie starałem się umieścić znaki odpowiadające danemu fragmentowi regexa. Znów, regex mógłby być lepszy, ale wolę, żeby był prostszy. Prostszy działa.&lt;&#x2F;p&gt;
&lt;p&gt;Skoro już mamy wypakowane dane, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wiktionary.org&#x2F;wiki&#x2F;parsowa%C4%87&quot;&gt;dokonujemy analizy składniowej ciągu znaków w celu ustalenia jego struktury i dalszego przetwarzania&lt;&#x2F;a&gt;, liczymy mnożnik dla odpowiedniej jednostki, przeliczamy kwotę, i gotowe - mamy po czym sortować. Dla efektu dodajemy element z przeliczoną ceną jednostkową do DOM.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;const UNIT_CONVERSIONS = {
  &amp;quot;g&amp;quot;: { factor: 1000, to: &amp;quot;kg&amp;quot; },
  &amp;quot;ml&amp;quot;: { factor: 1000, to: &amp;quot;l&amp;quot; },
};
...
const match = priceElement.textContent.match(PRICE_REGEX);
let [, unitPrice, unitQuantity, unit] = match;
unitPrice = parseFloat(unitPrice...);
const conv = UNIT_CONVERSIONS[unit];
if (conv) {
unitPrice = (unitPrice * conv.factor) &#x2F; parseInt(unitQuantity);
unitQuantity = 1;
unit = conv.to;
}
const priceElementCopy = priceElement.cloneNode(true);
priceElementCopy.textContent = `${unitPrice} zł za ${unitQuantity} ${unit}`;
priceElement.insertAdjacentElement(&amp;quot;afterend&amp;quot;, priceElementCopy);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Teraz najważniejszy etap: zamiana kolejności elementów w DOM. Już byłem gotowy napisać jakiś srogi mechanizm do przesuwania elementów w DOM na podstawie wag, kiedy natknąłem się na fascynującą informację: w kontenerach &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Glossary&#x2F;Grid_Container&quot;&gt;grid&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Glossary&#x2F;Flex_Container&quot;&gt;flex&lt;&#x2F;a&gt; kolejność elementów można ustawiać za pomocą... CSSa! A konkretnie pola &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;CSS&#x2F;Reference&#x2F;Properties&#x2F;order&quot;&gt;order&lt;&#x2F;a&gt;. A tak się składa, ze nasza skromna lista szamponów jest dokładnie takim kontenerem. Biorąc pod uwagę, że i tak przechodzimy po każdym elemencie w pętli, po to żeby odczytać i przetworzyć jego cenę, wystarczy, że dodatkowo ustawiamy &lt;code&gt;element.style.order = Math.floor(unitPrice * 100)&lt;&#x2F;code&gt; (wartość &lt;code&gt;order&lt;&#x2F;code&gt; musi być liczbą całkowitą) i sortowanie sortuje się samosortująco!&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;tileElement.style.order = Math.round(unitPrice * 100);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ostatnią dziwnostką do rozwiązania było to, że klikanie w przycisk &quot;Więcej&quot; powoduje zmianę adresu strony, co następnie powoduje dziwne przygody np. przy jej odświeżeniu. Taki wspaniały pomysł traktujemy prostą klamrą kompozycyjną:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;const originalURL = window.location.href;
&#x2F;&#x2F; cały skrypt &#x2F;&#x2F;
history.replaceState({}, &amp;quot;&amp;quot;, originalURL);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cały skrypt dostępny jest na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;mtsz&#x2F;userscripts&#x2F;src&#x2F;branch&#x2F;main&#x2F;bookmarklets&#x2F;sort-dm.bookmark.js&quot;&gt;moim Codebergu&lt;&#x2F;a&gt;. Wystarczy utworzyć zakładkę, wkleić kod z pliku w pole adresu, wejść na stronę z szamponami i kliknąć zakładkę.&lt;&#x2F;p&gt;
&lt;p&gt;Protip 1: w skryptozakładkach trzeba uważać z komentarzami. Skyptozakładka zapsisuje się w jednej linijce, wiec wstawienie komentarza &lt;code&gt;&#x2F;&#x2F;&lt;&#x2F;code&gt; wycina cały skrypt od tego momentu do końca. Można taki komentarz wrzucić na sam koniec, ale lepiej po prostu używać &lt;code&gt;&#x2F;* *&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Protip 2: nasza drogeria ma stronę &quot;Nowości&quot;, która zawiera chyba wszystkie możliwe produkty, czyli ma nieskończoną liczbę stron, stąd skrypt ma zaimplementowane ograniczenie. Warto pamiętać o takich rzeczach, bo ja nie pamiętałem i wywaliłem przeglądarkę zapełniając dużo gigabajtów RAMu drogeriami.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115807990198610293&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Wszystkie wokół Gita fikołki</title>
        <published>2025-12-14T21:26:00+00:00</published>
        <updated>2025-12-14T21:26:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-12-14-wszystkie-wokol-gita-fikolki/"/>
        <id>https://mtsz.pl/blog/2025-12-14-wszystkie-wokol-gita-fikolki/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-12-14-wszystkie-wokol-gita-fikolki/">&lt;p&gt;Tak się zdarzyło, że w ciągu ostatnich miesięcy pracowałem nad wieloma projektami programistycznymi. Repozytoria leżały u różnych dostawców, musiałem więc użyć osobnych kont i metod autoryzacji. W moim przypadku były to jedno konto na Codebergu oraz dwa konta na Githubie - prywatne oraz pracowe. Problemem do rozwiązania stała się kwestia zarządzania tymi tożsamościami, kluczami, itp. Oto co chciałem osiągnąć: niezależnie od tego, skąd oraz dokąd sklonuję repozytorium, wszystkie zmiany powinny być opisane odpowiednim do projektu imieniem oraz adresem email, a pobieranie i wrzucanie zmian na serwer autoryzowane odpowiednim kluczem.&lt;&#x2F;p&gt;
&lt;p&gt;Do przechowywania konfiguracji repozytoriów Git używa się... &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;pl&#x2F;v2&#x2F;Dostosowywanie-Gita-Konfiguracja-Gita&quot;&gt;Konfiguracji Gita&lt;&#x2F;a&gt;. Jest to seria prostych plików tekstowych + narzędzie linii poleceń. Seria, ponieważ pliki te znajdują się w kilku miejscach i mają różny zakres działania. Mnie interesują najbardziej:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~&#x2F;.gitconfig&lt;&#x2F;code&gt; - wersja globalna konfiguracji, znajduje się w folderze domowym. Tutaj znajdują się globalne ustawienia, takie jak strategie scalania czy aliasy (o których będzie kilka zdań na końcu), które są automatycznie aplikowane do każdego repozytorium.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;PROJEKT&amp;gt;&#x2F;.git&#x2F;config&lt;&#x2F;code&gt; - wersja lokalna konfiguracji, znajduje się wewnątrz każdego repozytorium. Przechowuje przede wszystkim informacje dotyczące konkretnego repozytorium, takie jak adres zdalnego repozytorium, aktywne gałęzie, czy właśnie wspomniane wcześniej imię i adres email, używane do opisywania zmian. Można tu też nadpisać wartości z konfiguracji globalnej - lokalna wartość ma zawsze wyższy priorytet.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Przykładowy plik wygląda następująco:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;gitconfig&quot;&gt;# &amp;lt;PROJEKT&amp;gt;&#x2F;.git&#x2F;config

[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
[remote &amp;quot;origin&amp;quot;]
  url = git@github.com:osobiste&#x2F;projekt.git
  fetch = +refs&#x2F;heads&#x2F;*:refs&#x2F;remotes&#x2F;origin&#x2F;*
[branch &amp;quot;main&amp;quot;]
  remote = origin
  merge = refs&#x2F;heads&#x2F;main
[user]
  name = &amp;quot;Andrzej&amp;quot;
  email = &amp;quot;andrzej@buziaczek.pl&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Drugą częścią układanki są klucze SSH. Pozwalają one na automatyczną autoryzację dostępu do różnych zasobów, również do repozytoriów Git. Pary kluczy - jeden prywatny i jeden publiczny - najlepiej stworzyć per tożsamość+dostawca; w moim przypadku są to trzy pary. To, które klucze używane są do którego repozytorium, można ustawić w kolejnym pliku konfiguracyjnym: &lt;code&gt;~&#x2F;.ssh&#x2F;config&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Przykładowy plik wygląda tak:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;config&quot;&gt;# ~&#x2F;.ssh&#x2F;config

Host codeberg.org
  HostName codeberg.org
  User git
  IdentityFile ~&#x2F;.ssh&#x2F;id_rsa_codeberg_osobiste

Host github.com
  HostName github.com
  User git
  IdentityFile ~&#x2F;.ssh&#x2F;id_rsa_github_osobiste

Host github.com
  HostName github.com
  User git
  IdentityFile ~&#x2F;.ssh&#x2F;id_rsa_github_pracodawca
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Co uważniejsi mogą już tutaj zauważyć pewną niedogodność: pole &lt;code&gt;Host&lt;&#x2F;code&gt;, które jest identyfikatorem danej konfiguracji, nie rozróżnia pomiędzy różnymi kontami u danego dostawcy - mamy dwa wpisy oznaczone &lt;code&gt;github.com&lt;&#x2F;code&gt;. Na szczęście da się to łatwo obejść &lt;em&gt;(spoiler: to pole to jedynie alias)&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Rozwiązanie, które pozwoliło mi osiągnąć efekt, polega na użyciu dwóch intrygujących dyrektyw Konfiguracji Gita:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[includeIf hasconfig:remote.*.url]&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-config#Documentation&#x2F;git-config.txt-hasconfigremoteurl&quot;&gt;która&lt;&#x2F;a&gt; pozwala zastosować osobną konfigurację w zależności od adresu repozytorium - ma sens&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[url.&amp;lt;base&amp;gt;.insteadOf]&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-config#Documentation&#x2F;git-config.txt-urlbaseinsteadOf&quot;&gt;która&lt;&#x2F;a&gt; pozwala na całkowitą zmianę adresu danego repozytorium - ⁉️🙋‍♀️🤯&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Jak to wszystko działa? Bardzo prosto. Zacznijmy od globalnego &lt;code&gt;~&#x2F;.gitconfig&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;gitconfig&quot;&gt;# ~&#x2F;.gitconfig

[includeIf &amp;quot;hasconfig:remote.*.url:git@codeberg.org:osobiste&#x2F;**&amp;quot;]
  path = ~&#x2F;.gitconfig_osobiste.codeberg.org.gitconfig

[includeIf &amp;quot;hasconfig:remote.*.url:git@github.com:osobiste&#x2F;**&amp;quot;]
  path = ~&#x2F;.gitconfig_osobiste.github.com.gitconfig

[includeIf &amp;quot;hasconfig:remote.*.url:git@github.com:pracodawca&#x2F;**&amp;quot;]
  path = ~&#x2F;.gitconfig_pracodawca.github.com.gitconfig

[alias]
  nuke = ...
  check = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mamy tutaj trzy identyczne wpisy &lt;code&gt;includeIf&lt;&#x2F;code&gt;, które robią dokładnie to samo, czyli: dla dowolnego repozytorium, jeśli adres tego repozytorium pasuje do wzorca, to załącz do końcowej konfiguracji dla tego repozytorium zawartość pliku wskazanego w &lt;code&gt;path&lt;&#x2F;code&gt;. Nazwa i lokalizacja tych plików może być dowolna - w moim przypadku wyglądają one jak wyglądają, ponieważ:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;chciałem, żeby wszystkie pliki &lt;code&gt;.gitconfig&lt;&#x2F;code&gt; w katalogu domowym były &quot;koło siebie&quot; np. w przeglądarce plików VSCodium&lt;&#x2F;li&gt;
&lt;li&gt;chciałem od razu widzieć, który plik odpowiada jakiej wersji tożsamość+dostawca&lt;&#x2F;li&gt;
&lt;li&gt;VSCodium rozpoznaje plik o nazwie &lt;code&gt;.gitconfig&lt;&#x2F;code&gt; jako Konfigurację Gita - i ładnie koloruje składnię i oznacza ikonkę - ale pliku o nazwie &lt;code&gt;.gitconfig_osobiste.codeberg.org&lt;&#x2F;code&gt; już nie ogarnia, i dopiero dodanie &quot;rozszerzenia&quot; załatwiało sprawę&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Poniżej przykład jednego z &quot;inkludowanych&quot; plików - w tym przypadku jest to wersja dla Githuba:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;gitconfig&quot;&gt;# ~&#x2F;.gitconfig_osobiste.github.com.gitconfig

[user]
  name = &amp;quot;Andrzej&amp;quot;
  email = &amp;quot;andrzej@buziaczek.pl&amp;quot;
[url &amp;quot;git@osobiste.github.com:&amp;quot;]
  insteadOf = git@github.com:
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sekcja &lt;code&gt;[user]&lt;&#x2F;code&gt; jest oczywista. Natomiast nikt może zapytać, o co chodzi z tą podmianą adresu? To jest rozwiązanie wspomnianej niedogodności z konfiguracją SSH! Żeby to miało pełny sens, trzeba wprowadzić do niej małą poprawkę:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;config&quot;&gt;# ~&#x2F;.ssh&#x2F;config

Host osobiste.github.com # poprawiony Host, a.k.a `alias`
  HostName github.com
  User git
  IdentityFile ~&#x2F;.ssh&#x2F;id_rsa_github_osobiste
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I teraz wszystko działa automagicznie w ten sposób:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;klonujemy przykładowe repozytorium: &lt;code&gt;git clone git@github.com:osobiste&#x2F;projekt.git&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;adres repozytorium pasuje do jednej z dyrektyw &lt;code&gt;includeIf&lt;&#x2F;code&gt; w globalnej konfiguracji Git&lt;&#x2F;li&gt;
&lt;li&gt;imię oraz email są odczytane z dedykowanej konfiguracji - każda zmiana jest odpowiednio podpisana&lt;&#x2F;li&gt;
&lt;li&gt;adres repozytorium zostaje podmieniony na &lt;code&gt;osobiste.github.com&lt;&#x2F;code&gt; -  odpowiednia para kluczy może być zidentyfikowana w konfiguracji SSH, a finalnie i tak zostanie użyty poprawny adres pobrany z pola &lt;code&gt;HostName&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Od teraz każde nowe repozytorium powinno konfigurować się samodzielnie, a obsłużenie nowego dostawcy czy tożsamości jest całkiem proste.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Aliasy. Konfiguracja Gita pozwala na tworzenie własnych komend Gita. Stworzenie aliasu jest bardzo proste - polega na dodaniu do konfiguracji w sekcji &lt;code&gt;[alias]&lt;&#x2F;code&gt; pary &lt;code&gt;alias = polecenie&lt;&#x2F;code&gt;. Dla poleceń Git wystarczy podać samo polecenie (&lt;code&gt;co&lt;&#x2F;code&gt;), ale można też używać komend powłoki (&lt;code&gt;ojesu&lt;&#x2F;code&gt;) lub nawet odpalać skrypty (&lt;code&gt;nuke&lt;&#x2F;code&gt;, &lt;code&gt;check&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;gitconfig&quot;&gt;# ~&#x2F;.gitconfig

[alias]
  co = checkout
  ojesu = !find . -type f -name &amp;quot;*.js&amp;quot; | xargs wc -l | sort -nr | head -10
  nuke = !~&#x2F;.gitconfig_aliases.sh nuke
  check = !~&#x2F;.gitconfig_aliases.sh check
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rezultat:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;zsh&quot;&gt;% git ojesu
  5506 total
  3201 .&#x2F;static&#x2F;js&#x2F;searchElasticlunr.js
  1760 .&#x2F;static&#x2F;js&#x2F;mermaid.js
   270 .&#x2F;static&#x2F;js&#x2F;count.js
   103 .&#x2F;static&#x2F;js&#x2F;codeblock.js
    82 .&#x2F;static&#x2F;js&#x2F;themetoggle.js
    49 .&#x2F;static&#x2F;js&#x2F;toc.js
    25 .&#x2F;static&#x2F;js&#x2F;main.js
    14 .&#x2F;static&#x2F;js&#x2F;note.js
     1 .&#x2F;static&#x2F;js&#x2F;searchElasticlunr.min.js
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;W gratisie dorzucam plik &lt;code&gt;.gitconfig_aliases.sh&lt;&#x2F;code&gt;, w którym napisałem dwie funkcje użyte w przykładowych aliasach. Pierwsza z nich przegląda wszystkie katalogi w miejscu uruchomienia, sprawdza, czy są tam repozytoria Git i wyświetla informacje z konfiguracji. Tego aliasu używałem bardzo często podczas pracy nad przedmiotem tego wpisu. Drugi alias to tak ugrzeczniony &lt;code&gt;git clean --dfx&lt;&#x2F;code&gt;, który automatycznie działa w obrębie danego folderu i zawsze pyta o pozwolenie. Ułatwia kasowanie plików z &lt;code&gt;.gitignore&lt;&#x2F;code&gt; czy pustych folderów, których nie widać w &lt;code&gt;git diff&lt;&#x2F;code&gt;. Plik skryptu trzeba potraktować &lt;code&gt;chmod +x&lt;&#x2F;code&gt;, żeby aliasy mogły go użyć.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;zsh&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env zsh

check() {
  for dir in *&#x2F;; do
    [[ -d &amp;quot;$dir&#x2F;.git&amp;quot; ]] || continue
    {
      echo &amp;quot;$dir&amp;quot;
      git -C &amp;quot;$dir&amp;quot; config --get remote.origin.url
      git -C &amp;quot;$dir&amp;quot; config --get user.email
      git -C &amp;quot;$dir&amp;quot; config --get user.name
    } | paste -sd $&amp;#39;\t&amp;#39; -
  done | column -t
}

nuke() {
  [[ -n $GIT_PREFIX ]] &amp;amp;&amp;amp; echo GIT_PREFIX=$GIT_PREFIX
  files=$(git clean -ndfx -- $GIT_PREFIX | tee &#x2F;dev&#x2F;tty)
  [[ -z $files ]] &amp;amp;&amp;amp; echo &amp;quot;Nothing to nuke&amp;quot; &amp;amp;&amp;amp; exit
  read -n 1 -p &amp;quot;Proceed? (yY) &amp;quot; proceed
  echo
  [[ $proceed == [yY] ]] &amp;amp;&amp;amp; git clean -dfx -- $GIT_PREFIX
}

&amp;quot;$@&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115719890719181770&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Kochanie, czy Ty programujesz na iOSa NA LINUXIE?!</title>
        <published>2025-11-24T11:46:00+00:00</published>
        <updated>2025-11-24T11:46:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-11-24-kochanie-czy-ty-programujesz-na-iosa-na-linuxie/"/>
        <id>https://mtsz.pl/blog/2025-11-24-kochanie-czy-ty-programujesz-na-iosa-na-linuxie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-11-24-kochanie-czy-ty-programujesz-na-iosa-na-linuxie/">&lt;p&gt;Zaczęło się od tego, że gdzieś na Mastodonie mignęła mi informacja, że Mozilla zaczyna coraz bardziej pchać ejaj do Firefoxa. Zniesmaczony tą perspektywą przypomniałem sobie, że istnieje coś takiego jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;librewolf.net&#x2F;&quot;&gt;LibreWolf&lt;&#x2F;a&gt;, którego jedynym celem jest &quot;odchamienie&quot; Firefoxa. Nie zastanawiając się zbyt długo, wklepałem w Terminal komendę do instalacji i moim oczom ukazał się taki obraz:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;% brew info librewolf
==&amp;gt; **librewolf**: 145.0.1,2
https:&#x2F;&#x2F;librewolf.net&#x2F;
Deprecated because it does not pass the macOS Gatekeeper check! It will be disabled on 2026-09-01.
Not installed
From: https:&#x2F;&#x2F;github.com&#x2F;Homebrew&#x2F;homebrew-cask&#x2F;blob&#x2F;HEAD&#x2F;Casks&#x2F;l&#x2F;librewolf.rb
==&amp;gt; **Name**
LibreWolf
==&amp;gt; **Description**
Web browser
==&amp;gt; **Artifacts**
LibreWolf.app (App)
&#x2F;opt&#x2F;homebrew&#x2F;Caskroom&#x2F;librewolf&#x2F;145.0.1,2&#x2F;librewolf.wrapper.sh -&amp;gt; librewolf (Binary)
==&amp;gt; **Analytics**
install: 5,017 (30 days), 15,861 (90 days), 69,140 (365 days)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&quot;Deprecated because macOS cośtam&quot; - no wspaniale, nie dość, że Mozilla z jednej strony, to jeszcze Apple z drugiej. Czasami żałuję, że wyspecjalizowałem się w technologii, której właściciel może mnie zakneblować. Już wolałbym programować na Linuxie.&lt;&#x2F;p&gt;
&lt;p&gt;Ale zaraz. Przecież ja już mam komputer z Linuxem - konkretnie to z Fedorą. I co z tego, że na MacBooku, może nawet lepiej!&lt;&#x2F;p&gt;
&lt;p&gt;Ponieważ domyślnie jestem programistą aplikacji na iOSa, fundamentalnym problemem do rozwiązania stała się możliwość uruchomienia Xcode&#x27;a. Xcode będzie działał tylko i wyłącznie na macOS, więc pierwszą rzeczą, jaka przyszła mi do głowy była maszyna wirtualna. W internetach pełno jest projektów ułatwiających postawienie takiej maszyny z macOS na Linuxie, ja postanowiłem przetestować dwie opcje: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;quickemu-project&#x2F;quickemu&quot;&gt;Quickemu&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Coopydood&#x2F;ultimate-macOS-KVM&quot;&gt;ULTMOS&lt;&#x2F;a&gt;. Oba narzędzia robią mniej więcej to samo, ale ostatecznie wybrałem ULTMOSa, samodzielnie ogarnia trochę więcej rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;No więc zainstalowałem zależności, narzędzie, stworzyłem maszynę wirtualną, uruchomiłem... i matko jedyna, jak to koszmarnie wolno działa. Ja wiem, że to pewnie wirtualizacja programowa, że stary komputer, ale żeby nawet instalator macOSa się zacinał, no to jest wyczyn. Przebolałem jakoś proces instalacji, który oprócz koszmarnego laga przeszedł bez większych problemów, i odpaliłem system. O dziwo, większość rzeczy działała bardzo przyzwoicie. Ponownie, pomijając szybkość. Gdybym miał mocniejszy komputer oraz umiał bardziej w maszyny wirtualne niż odpalanie skryptów, to to mogłaby być sensowna opcja. Ale w tym momencie odpada.&lt;&#x2F;p&gt;
&lt;p&gt;Zacząłem więc szukać dalej. I dalej okazało się, że ktoś rozwija warstwę kompatybilności macOS na Linuxa! Nazywa się to &lt;strong&gt;Kochanie&lt;&#x2F;strong&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;darlinghq&#x2F;darling&quot;&gt;Darling&lt;&#x2F;a&gt;), od Darwin+Linux, Darwin to nazwa kernela używanego na macOS. No więc znowu, klonuję repozytorium i zabieram się za instalację. Żeby zainstalować Darling, trzeba go najpierw zbudować. To samo w sobie nie jest trudne, ale jest koszmarnie czasochłonne. Ale dobra, odpalam budowanie i wracam do klikania po internecie.&lt;&#x2F;p&gt;
&lt;p&gt;Gdy zbudowana była jakaś 1&#x2F;3 projektu, znalazłem coś, co wydaje się rewolucyjne i idealnie skrojone na moje potrzeby. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xtool-org&#x2F;xtool&quot;&gt;xtool&lt;&#x2F;a&gt;, narzędzie napisane w Swifcie, którego jedynym celem jest budowanie aplikacji w Xcode na dowolnym systemie! To brzmi zbyt dobrze, żeby było prawdziwe.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xtool.sh&#x2F;documentation&#x2F;xtool&#x2F;installation-linux&quot;&gt;Instalujemy.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Swift dostępny jest natywnie, więc wystarczy &lt;code&gt;sudo dnf install swift-lang&lt;&#x2F;code&gt;. Do uruchamiania aplikacji na ajfonie po USB wymagany jest pakiet &lt;code&gt;usbmuxd&lt;&#x2F;code&gt;, ale ten akurat jest dostępny na Fedorze 43 od razu. Kolejne bardzo przydatne narzędzie, które kojarzę nawet z macOSa, to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;libimobiledevice.org&#x2F;&quot;&gt;libimobiledevice&lt;&#x2F;a&gt; i ono również jest dostępne dla Fedory natywnie &lt;code&gt;sudo dnf install libimobiledevice-utils&lt;&#x2F;code&gt;. Potrzebny jest instalator Xcode&#x27;a - można go pobrać ze strony &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xcodereleases.com&#x2F;&quot;&gt;Xcode Releases&lt;&#x2F;a&gt;, trzeba jednak się zalogować na portalu developerskim Apple&#x27;a - pobieram wersję 26.1.1.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejny krok to konfiguracja SDK w xtool za pomocą &lt;code&gt;xtool sdk path&#x2F;to&#x2F;xcode.xip&lt;&#x2F;code&gt; - tutaj napotkałem na pierwszy poważny problem, który na moje szczęście &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;xtool-org&#x2F;xtool&#x2F;issues&#x2F;168&quot;&gt;ktoś inny już rozwiązał&lt;&#x2F;a&gt;. Okazuje się, że xtool próbował rozpakować Xcode&#x27;a do &lt;code&gt;tmpfs&lt;&#x2F;code&gt;, czyli do systemu plików w RAMie. Na ten system Fedora nakłada organiczenie, do którego Xcode dobił, i zaczął rzucał nieskoordynowanymi błędami. Rozwiązaniem było stworzenie tymczasowego folderu na dysku:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;mkdir .temporary
TMPDIR=~&#x2F;.temporary xtool sdk Xcode-26.1.1.xip
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Kolejny krok to autoryzacja xtoola, żeby mógł podpisywać aplikacje: &lt;code&gt;xtool auth login&lt;&#x2F;code&gt;, znowu - trzeba mieć konto w Apple.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz lecę zgodnie z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xtool.sh&#x2F;tutorials&#x2F;xtool&#x2F;first-app&quot;&gt;instrukcją budowania pierwszej aplikacji&lt;&#x2F;a&gt; i okazuje się, że projekt pięknie się kompiluje i uruchamia na telefonie. Muszę przyznać, że jestem pod wielkim wrażeniem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Ciekawe, kiedy Apple to zepsuje.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;mateusz@fedora:~&#x2F;Development$ xtool new Hello
Creating package: Hello
Creating Package.swift
Creating xtool.yml
Creating .gitignore
Creating .sourcekit-lsp&#x2F;config.json
Creating Sources&#x2F;Hello&#x2F;HelloApp.swift
Creating Sources&#x2F;Hello&#x2F;ContentView.swift

Finished generating project Hello. Next steps:
- Enter the directory with `cd Hello`
- Build and run with `xtool dev`
mateusz@fedora:~&#x2F;Development$ cd Hello&#x2F;
mateusz@fedora:~&#x2F;Development&#x2F;Hello$ xtool dev
Planning...
Building for debugging...
[8&#x2F;8] Linking Hello-App
Build complete! (13.71s)
Waiting for device to be connected...
Installing to device: iPhone (Mateusz) (udid: 00000000-0000000000000000)

[Unpacking app] 100%
[Preparing device] 100%
[Provisioning] 100%
[Signing] 100%
[Packaging] 100%
[Connecting] 100%
[Installing] 100%
[Verifying] 100%
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115604258799509967&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Homelab i jego internety</title>
        <published>2025-11-22T11:40:00+00:00</published>
        <updated>2025-11-22T11:40:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-11-22-homelab-i-jego-internety/"/>
        <id>https://mtsz.pl/blog/2025-11-22-homelab-i-jego-internety/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-11-22-homelab-i-jego-internety/">&lt;p&gt;Dzisiaj będzie o architekturze sieci, jaką planuję uskutecznić na moim homelabie. Założenie cały czas jest takie samo - wszystko na jednej maszynie. Komputer ma dwa gniazda Ethernet. Do pierwszego wpinam kabel wystający ze ściany, od teraz serwer ma (będzie miał) dostęp do internetu. Do drugiego gniazda podłączam punkt dostępu Wi-Fi - tak naprawdę to router, który dostałem od dostawcy internetu, ale robi robotę, a ja oszczędzam pieniądze - i dalej każde inne urządzenie jakie mam, podłączam do tego AP. Temat sprzętu załatwiony. Teraz oprogramowanie.&lt;&#x2F;p&gt;
&lt;p&gt;Na serwerze uruchomione będzie wiele aplikacji na maszynach wirtualnych i w kontenerach, sam homelab będzie pełnił rolę routera, zarządzającego ruchem sieciowym pomiędzy urządzeniami. I teraz: niektóre z tych aplikacji i urządzeń powinny mieć dostęp do internetu, inne nie powinny, a jeszcze inne nie powinny w ogóle mieć dostępu do czegokolwiek. Trzeba ten piękny ustrój rozbić na dzielnice.&lt;&#x2F;p&gt;
&lt;p&gt;Dzielenie sieci na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Segment_sieci&quot;&gt;segmenty&lt;&#x2F;a&gt; wymaga pewnego zrozumienia, jak sieci w ogóle działają, oraz znajomości nomenklatury. Na początek słowniczek. Interfejs sieciowy (network interface, network device) to w uproszczeniu &quot;punkt wejścia&quot; urządzenia do sieci - może to być gniazdo Ethernet w komputerze, moduł Wi-Fi w telefonie, albo wirtualny port w maszynie wirtualnej (ją też musimy jakoś do sieci podłączyć). Warto zwrócić uwagę, że jedno urządzenie (np. komputer) może mieć więcej niż jeden interfejs sieciowy. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Most_(sie%C4%87_komputerowa)&quot;&gt;Mostek sieciowy&lt;&#x2F;a&gt; to taki &quot;łącznik&quot;, do którego podłączamy różne interfejsy, tworząc w ten sposób segment. Warto wspomnieć jeszcze o &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Wirtualna_sie%C4%87_lokalna&quot;&gt;wirtualnej sieci lokalnej&lt;&#x2F;a&gt; (VLAN), który pozwala na zgrupowanie wybranych interfejsów i logiczne wydzielenie ich z danego segmentu, nawet jeśli wszystkie są podłączone do tego samego mostka. Przyda się za chwilę.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz kwestia ustalenia, jakie segmenty są mi potrzebne. Pierwsza kategoria to urządzenia fizyczne. Mam prywatny komputer oraz telefon, kilka urządzeń smart home, takich jak odkurzacz, żarówki czy odświeżacz powietrza, telewizor z webOS. Bardzo rzadko, ale czasami mam też gości, którzy przynoszą swoje własne telefony, i też chcą się podłączyć do internetu (właściwie to muszą - tłumienie sygnału komórkowego w moim mieszkaniu jest imponujące, bez &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Wi-Fi_calling&quot;&gt;Wi-Fi Calling&lt;&#x2F;a&gt; się nie da). Ale mamy też urządzenia wirtualne, a raczej aplikacje i usługi na serwerze. Do obsługi urządzeń smart home planuję użyć &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.home-assistant.io&#x2F;&quot;&gt;Home Assistant&lt;&#x2F;a&gt;, już teraz mam uruchomione wiele usług w kontenerach.&lt;&#x2F;p&gt;
&lt;p&gt;Segmenty, które wyłaniają się z tej listy pacjentów są następujące. Do obsługi wszystkich fizycznych urządzeń tworzę mostek &lt;code&gt;LAN_BRIDGE&lt;&#x2F;code&gt;, w ramach którego wydzielam sobie trzy VLAN-y. &lt;code&gt;HOME_VLAN&lt;&#x2F;code&gt;, do którego podłączam mój komputer oraz telefon, będzie miał dostęp do praktycznie wszystkiego w sieci. &lt;code&gt;GUEST_VLAN&lt;&#x2F;code&gt; będzie ograniczony jedynie do internetu - zakładam, że moim gościom niepotrzebny jest dostęp do mojego odkurzacza czy zdjęć &lt;code&gt;na&lt;&#x2F;code&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;immich.app&#x2F;&quot;&gt;Immichu&lt;&#x2F;a&gt;. &lt;code&gt;IOT_VLAN&lt;&#x2F;code&gt;, który będzie służył urządzeniom smart home, nie będzie miał dostępu nawet do internetu - za dużo razy czytałem w internecie o odkurzaczach wysyłających zdjęcia ich właścicieli na chińskie serwery, podziękuję. Do obsługi aplikacji serwerowych tworzę osobny mostek &lt;code&gt;SERVER_BRIDGE&lt;&#x2F;code&gt;. Nie hostuję co prawda żadnej strony internetowej z mojego homelaba - aktualnie używam do tego &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mikr.us&#x2F;&quot;&gt;VPSa Mikrus&lt;&#x2F;a&gt;, ale wspomnę, że istnieje coś takiego jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Strefa_zdemilitaryzowana_(informatyka)&quot;&gt;strefa zdemilitaryzowana&lt;&#x2F;a&gt; (DMZ) - jaka piękna nazwa! - gdzie można wrzucić usługi dostępne publicznie, która jest całkowicie odseparowana od wszystkiego. Ostatnia rzecz to oczywiście mostek &lt;code&gt;WAN_BRIDGE&lt;&#x2F;code&gt;, żebyśmy w ogóle mieli możliwość połączenia się z internetem.&lt;&#x2F;p&gt;
&lt;p&gt;Do ogarnięcia jest kilka &quot;pobocznych&quot; tematów.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwszy to przypisywanie adresów IP każdemu interfejsowi sieciowemu. W większości przypadków skorzystamy z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Dynamic_Host_Configuration_Protocol&quot;&gt;protokołu dynamicznego konfigurowania hostów&lt;&#x2F;a&gt; (DHCP), czyli protokołu, który automatycznie przypisuje urządzeniom w sieci adresy IP. Mostek WAN_BRIDGE możemy zignorować, bo tutaj adres IP dostaniemy od dostawcy internetu. Maszyny wpięte w mostek &lt;code&gt;SERVER_BRIDGE&lt;&#x2F;code&gt; będą miały statyczne adresy IP, dzięki temu cały system będzie deterministyczny, a musi tak być, żebym mógł go odtwarzać korzystając z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opentofu.org&#x2F;&quot;&gt;OpenTofu&lt;&#x2F;a&gt; (będzie o tym w przyszłości). W każdym VLAN-ie adresy również będą rozdawane przez DHCP. &lt;code&gt;DMZ&lt;&#x2F;code&gt;, jeśli powstanie, prawdopodobnie dostanie statyczny adres IP.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejny etap to ustawienie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Zapora_sieciowa&quot;&gt;zapory sieciowej&lt;&#x2F;a&gt;, czyli w uproszczeniu reguł komunikacji pomiędzy różnymi sieciami i interfejsami. Dla przykładu: skoro sieć GUEST_VLAN ma mieć dostęp jedynie do internetu, to reguła będzie wyglądała mniej więcej jak &lt;code&gt;Allow GUEST_VLAN → WAN_BRIDGE&lt;&#x2F;code&gt;. I takie reguły trzeba stworzyć dla każdej pożądanej konfiguracji.&lt;&#x2F;p&gt;
&lt;p&gt;Jeszcze innym aspektem do zaopiekowania jest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Wirtualna_sie%C4%87_prywatna&quot;&gt;wirtualna sieć prywatna&lt;&#x2F;a&gt;&#x2F;VPN, czyli kolejny protokół, który umożliwi mi dostanie się do mojej sieci wewnętrznej z zewnątrz, ale bez konieczności otwierania dostępu komukolwiek innemu. Mój telefon czy komputer myśli wtedy, że jestem w moim mieszkaniu, podpięty do sieci HOME_VLAN, nawet jeśli jestem w takim na przykład Peru.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejnym krokiem może być &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Domain_Name_System&quot;&gt;serwer nazw domen&lt;&#x2F;a&gt; (DNS), którego zadaniem jest tłumaczenie adresów stron WWW na adresy IP. Oczywistą sprawą jest tłumaczenie adresów takich jak na przykład &lt;code&gt;internet-czas-dzialac.pl&lt;&#x2F;code&gt; na &lt;code&gt;51.68.137.154&lt;&#x2F;code&gt;, ale w ramach DNS można też skonfigurować lokalne adresy, np. &lt;code&gt;miniflux.lan&lt;&#x2F;code&gt;, który załaduje najlepszy czytnik RSS serwowany prosto z lokalnego kontenera.&lt;&#x2F;p&gt;
&lt;p&gt;Wszystkie te rzeczy można z pomocą dokumentacji i różnych kursów internetowych bez problemu skonfigurować w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opnsense.org&#x2F;&quot;&gt;OPNsense&lt;&#x2F;a&gt;, które to oprogramowanie wybrałem do ogarniania mojej sieci. Po tym, jak postawiłem jakieś 80% wszystkiego, zdałem sobie sprawę z tego, że OPNsense jest bardziej problematyczny niż bym chciał. Jedną z tych wad jest fakt, że w samym interfejsie webowym w pakiecie dostajemy pełno usług, z których nie chcemy korzystać, i nie da się tego wyłączyć (albo mi się nie udało). Drugim, dużo poważniejszym problemem dla mnie jest brak prostego sposobu na automatyzację instalacji od nowa.&lt;&#x2F;p&gt;
&lt;p&gt;Pamiętacie wzmiankę o OpenTofu? W skrócie, jest to oprogramowanie, które potrafi &quot;stawiać serwery&quot; na podstawie konfiguracji zapisanej do pliku tekstowego. Piszesz sobie w terminalu &lt;code&gt;tofu apply&lt;&#x2F;code&gt; i homelab, wraz z maszynami wirtualnymi, mostkami, VPN-ami i wszystkimi innymi rzeczami pojawia się gotowe do użycia. OPNsense jest bardzo w tym temacie oporny i rozważam mocno przejście na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vyos.io&#x2F;&quot;&gt;VyOS&lt;&#x2F;a&gt;, którego główną przewagą jest to, że można dosłownie całą sieć zdefiniować w jednym pliku &lt;code&gt;config.boot&lt;&#x2F;code&gt;. Potem wystarczy odpalić system w wersji live, załadować konfigurację - i sieć elegancko wstaje. Coś pięknego.&lt;&#x2F;p&gt;
&lt;p&gt;Oczywiście VyOS-a trzeba sobie samemu skompilować, szczególnie jeśli chce się mieć np. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cloud-init.io&#x2F;&quot;&gt;cloud-init&lt;&#x2F;a&gt;, a jeszcze gdy robi się to na komputerze o innej architekturze, w dodatku w kontenerze, który próbuje uzyskać absurdalnie wysokie uprawnienia na hoście...&lt;&#x2F;p&gt;
&lt;p&gt;Będzie o czym pisać.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115594350831926782&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Technologia, która stawia opór - i jak się temu oprzeć</title>
        <published>2025-11-18T14:00:00+00:00</published>
        <updated>2025-11-18T14:00:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-11-18-technologia-ktora-stawia-opor-i-jak-sie-temu-oprzec/"/>
        <id>https://mtsz.pl/blog/2025-11-18-technologia-ktora-stawia-opor-i-jak-sie-temu-oprzec/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-11-18-technologia-ktora-stawia-opor-i-jak-sie-temu-oprzec/">&lt;p&gt;Mój pierwszy, prawdziwy komputer do pracy (wcześniej miałem nieprawdziwe komputery do studiowania) kupiłem gdzieś około roku 2014 - lekko licząc ponad 11 lat temu. Ponieważ pracowałem już wtedy jako programista iOS, nauczony doświadczeniami poprzednich zakupów, postanowiłem &quot;wymaksować&quot; mój najnowszy komputer, i tak oto pewnego pięknego dnia 31 marca 2014 roku stałem się posiadaczem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;pl-pl&#x2F;111946&quot;&gt;13-calowego MacBooka Pro A1502&lt;&#x2F;a&gt;. Jak na tamte czasy, wspaniała konfiguracja.&lt;&#x2F;p&gt;
&lt;p&gt;Czas sobie płynął, ja pracowałem nad coraz większymi projektami, ale komputer dawał radę. Nawet po tym, jak Apple przestał wspierać ten model na wersji &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;pl-pl&#x2F;111980&quot;&gt;macOS Big Sur&lt;&#x2F;a&gt;, wspaniali ludzie z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dortania&#x2F;OpenCore-Legacy-Patcher&quot;&gt;OpenCore Legacy Patcher&lt;&#x2F;a&gt; (OCLP) umożliwili mi wgrywanie coraz to nowszych wersji systemu - oczywiście nie bez stopniowej utraty stabilności i szybkości działania. No ale nadal było znośnie.&lt;&#x2F;p&gt;
&lt;p&gt;Jednak jakieś dwa lata temu mój ówczesny pracodawca udostępnił mi do pracy nowego MacBooka bez &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Mobile_device_management&quot;&gt;MDMa&lt;&#x2F;a&gt;, i tak moja trzynastka wylądowała najpierw na regale, a potem u osoby trzeciej.&lt;&#x2F;p&gt;
&lt;p&gt;Kilka dni temu komputer do mnie wrócił i coś mnie natchnęło, żeby spróbować jeszcze raz wgrać tam możliwie najnowszy system operacyjny, i zobaczyć jak to będzie działać. Można go więc potraktować jako taki mini-tutorial do OCLP, ale tak naprawdę to nie - a dlaczego, będzie na końcu posta.&lt;&#x2F;p&gt;
&lt;p&gt;Zasada działania OCLP jest w sumie bardzo prosta. Każda kolejna wersja macOS usuwa jakieś sterowniki, biblioteki, zmienia jakieś ustawienia, przez co niektóre komponenty w starych komputerach po prostu przestają być obsługiwane, aż do momentu, w którym system nawet się nie uruchamia. OCLP identyfikuje i łata te wszystkie dziury w taki sposób, że instalacja nowego systemu staje się możliwa, a sprzęty domyślnie nieobsługiwane, z powrotem są przez system widziane. Szczegółowa rozpiska tego, co OCLP robi, jest dostępna na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dortania.github.io&#x2F;OpenCore-Legacy-Patcher&#x2F;PATCHEXPLAIN.html&quot;&gt;stronie projektu&lt;&#x2F;a&gt;. Instalacja OCLP również jest relatywnie prosta. Po zainstalowaniu aplikacji, naszym oczom ukazuje się proste menu z dosłownie kilkoma opcjami, przez które bardzo precyzyjnie przeprowadza nas dostępna na stronie instrukcja.&lt;&#x2F;p&gt;
&lt;p&gt;W moim przypadku nie było tak kolorowo - chociaż ostatecznie udało się zainstalować możliwie najnowszą wersję systemu - macOS Sequoia. No więc jak to było?&lt;&#x2F;p&gt;
&lt;p&gt;Na sam początek MacBooka postanowiłem zresetować do fabrycznych ustawień. Oznaczało to, że z dysku odzyskiwania zainstaluje się ta wersja systemu, która była dostępna w dniu zakupu. W 2014 roku była to wersja OS X Mavericks 10.9.5. Gdy system wstał, to od razu nostalgłem. Kolejnym krokiem była instalacja OCLP. Do instalacji wszelkich programów na macOS używam &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt;, więc otworzyłem przeglądarkę, wpisałem adres - i dostałem w twarz błędem, że certyfikat nieważny, i nie połączę się z internetem. Nawet nie chciało mi się myśleć, jak to naprawić, przypomniałem sobie za to, w jaki sposób robiłem to ostatnio - aktualizacja do oficjalnie wspieranej najnowszej wersji systemu. Tak jak pisałem na początku, jest to macOS Big Sur, więc zgodnie z instrukcją od Apple otwieram aplikację AppStore, wpisuję w wyszukiwarkę &quot;Big Sur&quot; - i nie widzę żadnego Big Sura. I to nie tak, że nie widzę niczego, owszem są trzy najnowsze wersje systemów, gotowe do pobrania, które nigdy nie zainstalują się na tym komputerze, ale tego jednego, którego potrzebowałem - nie ma.&lt;&#x2F;p&gt;
&lt;p&gt;Dobra, na stronie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;download&#x2F;&quot;&gt;https:&#x2F;&#x2F;developer.apple.com&#x2F;download&#x2F;&lt;&#x2F;a&gt; na pewno jest do pobrania obraz instalatora, 12 lat doświadczenia zawodowego z oprogramowaniem Apple&#x27;a mnie w tym upewniało, no ale jednak się pomyliłem. Na tyle, na ile miałem cierpliwości żeby szukać, nie znalazłem w żadnych oficjalnych zasobach żadnej strony, z której mógłbym pobrać ten plik. To znaczy, jest sobie taki link &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;pl&#x2F;app&#x2F;macos-big-sur&#x2F;id1526878132&quot;&gt;https:&#x2F;&#x2F;apps.apple.com&#x2F;pl&#x2F;app&#x2F;macos-big-sur&#x2F;id1526878132&lt;&#x2F;a&gt;, który teoretycznie pozwala mi &quot;pobrać sobie&quot; instalator, ale na starym komputerze nie działa - aplikacja nie znajduje się w AppStore, a na nowym nie działa - zamiast tego otwiera się systemowe okno aktualizacji z informacją, że system jest nieobsługiwany. Ostatecznie udało mi się znaleźć &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mrmacintosh.com&#x2F;macos-big-sur-full-installer-database-download-directly-from-apple&#x2F;&quot;&gt;jakąś nieoficjalną, relatywnie nieszemraną stronę&lt;&#x2F;a&gt;, na której dostępny był link do pobrania obrazu z serwerów Apple&#x27;a, który na wszelki wypadek uwiecznię również na tym blogu, gdyby znowu coś miało z internetu zniknąć: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;swcdn.apple.com&#x2F;content&#x2F;downloads&#x2F;14&#x2F;38&#x2F;042-45246-A_NLFOFLCJFZ&#x2F;jk992zbv98sdzz3rgc7mrccjl3l22ruk1c&#x2F;InstallAssistant.pkg&quot;&gt;http:&#x2F;&#x2F;swcdn.apple.com&#x2F;content&#x2F;downloads&#x2F;14&#x2F;38&#x2F;042-45246-A_NLFOFLCJFZ&#x2F;jk992zbv98sdzz3rgc7mrccjl3l22ruk1c&#x2F;InstallAssistant.pkg&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Mając plik instalatora, stworzenie bootowalnego USB jest bardzo proste i ogranicza się do odpalenia jednej komendy w Terminalu:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;sudo &amp;quot;&#x2F;Applications&#x2F;Install macOS Big Sur.app&#x2F;Contents&#x2F;Resources&#x2F;createinstallmedia&amp;quot; --volume &#x2F;Volumes&#x2F;USB
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instalacja systemu Big Sur na starym komputerze odbywa się bezproblemowo i voila! Po godzinie możemy w końcu zacząć pracę z OCLP! Tym razem przeglądarka zadziałała, instalacja Homebrew się powiodła, instalacja OCLP komendą w Terminalu &lt;code&gt;brew install opencore-patcher&lt;&#x2F;code&gt; również. Następnie przejście przez instrukcję, przeklikanie się przez aplikację, około sześciu restartów komputera i mamy to - macOS Sequoia na komputerze z 2014 roku!&lt;&#x2F;p&gt;
&lt;p&gt;Połączyłem komputer z siecią Wi-Fi, zainstalowałem Firefoxa, odwiedziłem testowo kilka stron. Okazuje się, że macOS z 2024 roku na MacBooku z 2014 roku to nie jest najlepsze na świecie połączenie. Komputer działał nieużywalnie wolno. Oczywiście wszystko działało poprawnie, ludzie stojący za OCLP zrobili doskonałą robotę, ale pewnych ograniczeń, takich jak absurdalnie wysokie wymagania nowoczesnych systemów, po prostu nie da się przeskoczyć. A może się da?&lt;&#x2F;p&gt;
&lt;p&gt;Bo tak sobie pomyślałem: zaraz, to nie może być tak, że komputer z procesorem Intel Core i5, 16 GB RAM i dyskiem SSD nie może uciągnąć dosłownie gołego systemu operacyjnego z zainstalowaną jedynie przeglądarką.&lt;&#x2F;p&gt;
&lt;p&gt;I w tym momencie skierowałem swoje myśli w stronę Linuxa. A konkretnie, w stronę &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fedoraproject.org&#x2F;workstation&#x2F;&quot;&gt;Fedory Workstation&lt;&#x2F;a&gt;. Fedorę wybrałem po przeczytaniu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;forum.internet-czas-dzialac.pl&#x2F;t&#x2F;desktop-z-jakich-systemow-korzystacie&#x2F;2288&quot;&gt;tych&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;forum.internet-czas-dzialac.pl&#x2F;t&#x2F;dlaczego-ktos-moze-nie-chciec-korzystac-z-ubuntu&#x2F;2328&quot;&gt;dwóch&lt;&#x2F;a&gt; wątków na forum &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.internet-czas-dzialac.pl&#x2F;&quot;&gt;Fundacji &quot;Internet: Czas działać&quot;&lt;&#x2F;a&gt;, w której sobie czasami działam w internecie. Pobranie obrazu z internetu, stworzenie instalacyjnego pendrive&#x27;a za pomocą &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;etcher.balena.io&#x2F;&quot;&gt;Etchera&lt;&#x2F;a&gt;, prosty proces instalacyjny na MacBooku, i system działa.&lt;&#x2F;p&gt;
&lt;p&gt;I to jak działa! Komputer działa płynnie, nie zacina się, uruchamia się poprawnie, obsługuje wszystkie podstawowe peryferia (wszystkich wszystkich nie sprawdzałem), wygląda świetnie. Jedyną czkawką, na jaką się natknąłem, był brak sterowników do adaptera Wi-Fi, a ponieważ w tym komputerze nie ma gniazda Ethernet, musiałem posiłkować się kartą sieciową USB, ale sterowniki były dostępne, a po ich instalacji internet działa bezprzewodowo i bezproblemowo. W tym momencie jest to praktycznie pełnoprawnie i sprawnie działający komputer o nienajgorszych parametrach i wydajności, wysokiej rozdzielczości ekranie (tutaj Apple naprawdę robi dobrą robotę). Teraz ten komputer znowu jest w pełni całkowicie używalny.&lt;&#x2F;p&gt;
&lt;p&gt;I podczas całej tej przygody naszło mnie kilka refleksji.&lt;&#x2F;p&gt;
&lt;p&gt;OCLP to wspaniała inicjatywa. Istnieją na tym świecie ludzie, którzy są w stanie poświęcić niezliczone ilości czasu, żeby przywrócić pełną użyteczność sprzętowi, który producent przestał wspierać. O ile w przypadku mojego komputera dzisiaj to już nie ma sensu, o tyle jeszcze te kilka lat temu z powodzeniem korzystałem z aktualnych wersji macOS po tym, jak Apple powiedziało mi, żebym spadał.&lt;&#x2F;p&gt;
&lt;p&gt;Gdy myślę o tym, dlaczego w pewnym momencie producent przestaje wspierać dany produkt, przychodzi mi do głowy wiele powodów. Sztuczne ograniczanie aktualizacji zwiększa sprzedaż nowych komputerów - czy jest to cyniczne? Jest. Czy jest to niemoralne? Moim zdaniem ciężko to udowodnić. Wymagania nowych systemów są zbyt duże, by stare komputery im podołały. Tutaj też można się obrażać, że po co pchać do systemu tak ciężkie rzeczy, żeby potrzebował petabajtów pamięci, albo nie obrażać, bo chce się mieć interfejs tak piękny jak Windows Vista. Koszty utrzymania starych systemów nie opłacają się biznesowo - sensowny argument dla firmy, której celem jest zarabanie pieniędzy. Starsze urządzenia nie mają odpowiednich zabezpieczeń sprzętowych - połowicznie mogę się zgodzić, enklawy bezpieczeństwa to coś, co moim zdaniem powinien mieć każdy komputer.&lt;&#x2F;p&gt;
&lt;p&gt;Całe szczęście, że na komputery można sobie wgrać dowolny system. A systemów operacyjnych na komputery osobiste jest od groma, można je dobrać pod dowolnym kątem: możliwości sprzętu, preferencji interfejsu, docelowego użytkowania. Tutaj znowu można się zachwycić tymi wszystkimi ludźmi pracującymi nad Fedorą, Waylandem, GNOMEm i milionem innych wynalazków, które dla zwykłego zjadacza chleba są dostępne za darmo, i w wysokiej jakości. Jakimś koszmarnym zrządzeniem losu ta wolność została nam prawie całkowicie odebrana, jeśli chodzi o telefony, które aktualnie są podstawowym urządzeniem cyfrowym dla prawdopodobnie większości ludzi. Więc cieszmy się z tej wolności i korzystajmy tak długo, jak tylko się da.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz mogę ze spokojem odłożyć MacBooka z powrotem na regał.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115571583376994895&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Homelab, tylko że w mieszkaniu i bez zlewki</title>
        <published>2025-11-14T00:15:00+00:00</published>
        <updated>2025-11-14T00:15:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-11-14-homelab-tylko-ze-w-mieszkaniu-i-bez-zlewki/"/>
        <id>https://mtsz.pl/blog/2025-11-14-homelab-tylko-ze-w-mieszkaniu-i-bez-zlewki/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-11-14-homelab-tylko-ze-w-mieszkaniu-i-bez-zlewki/">&lt;p&gt;To jest pierwszy z chaotycznej serii wpisów na temat mojego homelaba. Ten mój homelab to tak naprawdę ledwo istnieje, a jego fundamentalne założenia ciągle się zmieniają, ale nie przeszkadza mi to - to nie jest tak, że ktoś mi za to płaci. Mój pomysł na to, jak zorganizować sobie swoje miejsce w szeroko pojętym internecie, obejmował nie tylko postawienie własnego serwera, ale również ogarnięcie sieci w moim mieszkaniu. Wiem, że to są różne rzeczy, ale w mojej głowie to wszystko ma sens. Zacznijmy więc od tego miejsca, w którym już wszyscy wiemy, co to jest homelab.&lt;&#x2F;p&gt;
&lt;p&gt;Na początku był komputer. Konkretnie to poleasingowy Lenovo ThinkCentre M80q, którego kupiłem za cenę, którą byłem gotów wydać na tę fanaberię. Komputer ten ma procesor przedstawiający się jako &quot;12th Gen Intel(R) Core(TM) i7-12700T&quot; z 20 rdzeniami,  16 gigabajtów pamięci RAM (już wiem, że zdecydowanie za mało), dysk SSD NVMe o pojemności 500 GB, dwa interfejsy sieciowe LAN,  dużo portów USB typów A i C, i coś tam jeszcze, już nieważne. Na początek zabawy w serwowanie brzmi wystarczająco.&lt;&#x2F;p&gt;
&lt;p&gt;Dobra, mam blaszaka, co teraz? Teraz trzeba coś zainstalować. I tu zaczynają się pierwsze schody, bo ja nawet nie wiem do końca, co chcę. Wiem, że chcę mieć serwer mediów, menadżer haseł, agregat RSS-ów - wszystkie te rzeczy mogą istnieć w kontenerze na pojedynczym systemie operacyjnym. Ale okazało się, że niektóre inne rzeczy same w sobie są systemami operacyjnymi: np. HomeAssistantOS, aplikacja do sterowania domem, czy taki OPNsense, który jest de facto routerem (o tym za chwilę). Więc może chcę coś, co pozwoli mi zainstalować i uruchomić różne systemy operacyjne na raz? Czy coś takiego w ogóle istnieje?&lt;&#x2F;p&gt;
&lt;p&gt;Trochę klikania w internecie i okazuje się, że tak! Istnieje coś takiego jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypervisor&quot;&gt;hypervisor&lt;&#x2F;a&gt; - po polsku nazywa się to hipernadzorca, a artykuł w polskiej Wikipedii na ten temat jest tak niezrozumiały, że już łatwiej nauczyć się języka angielskiego. Serio. Co to jest hipernadzorca i co robi? W skrócie, jest to system operacyjny, który pozwala uruchomić na komputerze kolejne systemy operacyjne, przydzielić im zasoby - określoną ilość rdzeni procesora, pamięci RAM czy przestrzeni dyskowej, a także przypisać im różne inne sprzęty - możemy na przykład przypisać poszczególne interfejsy sieciowe czy oddać pełną autonomię nad kartą graficzną. Projektem, który wybrałem do swojego homelaba, jest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.proxmox.com&#x2F;en&#x2F;products&#x2F;proxmox-virtual-environment&#x2F;overview&quot;&gt;Proxmox Virtual Environment&lt;&#x2F;a&gt;. Największy wpływ na tę decyzję miał &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=sZcOlW-DwrU&quot;&gt;ten film od Craft Computing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwszą maszyną wirtualną, którą chciałem stworzyć na moim serwerze, był... router. O co chodzi z tym routerem? Moja idea na tego homelaba była taka, żeby to było jedno pudełko, które sobie podłączam z jednej strony do prądu, z drugiej strony do gniazdka internetowego, i tak oto powstaje cały mój świat internetowy. Zarówno ten zewnętrzny, gdzie hostuję sobie usługi, jak i ten wewnętrzny, gdzie powstają odpowiednie sieci WiFi, do których podłączam wszystkie moje komputery, smartfony i inne odkurzacze i pralki. Z samym WiFi okazało się, że może być lekki problem, bo tak naprawdę potrzebny jest zewnętrzny w stosunku do serwera access point, no ale nadal może to być taki &quot;regałowy pakiecik&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Podczas szukania informacji na temat dostępnych rozwiązań, natknąłem się na wiele dyskusji dotyczących tego, że to nie jest najlepszy pomysł, żeby router instalować na jednym komputerze z innymi usługami, że powinna to być osobna maszyna, żeby w razie wypadku nie stracić łączności ze światem zewnętrznym, no bo wiadomo, że komputery się psują, no a co będzie, jak nie będziesz mógł wbić na fejsika, przecież to nie jest tak, że masz na telefonie możliwość zrobienia hotspota i udostępnienia innym urządzeniom internetu 5G po WiFi. Po rzetelnym rozważeniu tej idei postanowiłem, że i owszem, obawy są uzasadnione, i zamówiłem pięć lodówek i trzy pralki - no bo wiadomo, rzeczy się psują, a gdzie ja wtedy wypiorę moje brudne gacie.&lt;&#x2F;p&gt;
&lt;p&gt;A tak poważnie: istnieje wiele powodów, żeby mieć każdą jedną usługę na osobnej maszynie, albo wszystkie na jednej, albo każda możliwa kombinacja pomiędzy. Kluczem jest zdawanie sobie sprawy z tego, jakie wiążą się z tym konsekwencje. Obawa o utratę dostępu do internetu może być dla niektórych wystarczającym powodem, żeby kupić kolejny komputer dedykowany temu zadaniu. Inni w ogóle nie będą się tym przejmować, i po prostu będą korzystać ze sprzętu dostarczonego od operatora internetu. Ja postanowiłem, że router będzie żył u mnie na serwerze jako maszyna wirtualna numer 1. Do tego poważnego zadania wybrałem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opnsense.org&#x2F;&quot;&gt;OPNsense&lt;&#x2F;a&gt;. Inspiracją do wyboru tego narzędzia był &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.futo.org&#x2F;&quot;&gt;tutorial&lt;&#x2F;a&gt;, jaki mój ulubiony jutuber &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;@rossmanngroup&quot;&gt;Louis Rossmann&lt;&#x2F;a&gt; stworzył na temat tworzenia swojego własnego serwera.&lt;&#x2F;p&gt;
&lt;p&gt;Na dziś wystarczy, jest pierwsza w nocy, dobranoc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115547466244394880&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Ulepszenia do gorsetu</title>
        <published>2025-11-10T14:17:00+00:00</published>
        <updated>2025-11-10T14:17:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-11-10-ulepszenia-do-gorsetu/"/>
        <id>https://mtsz.pl/blog/2025-11-10-ulepszenia-do-gorsetu/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-11-10-ulepszenia-do-gorsetu/">&lt;p&gt;Dzisiaj wpis techniczny.&lt;&#x2F;p&gt;
&lt;p&gt;Z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jozwiak.top&#x2F;blog&#x2F;mikrus-czyli-jak-przenioslem-sie-na-vps&#x2F;&quot;&gt;tego wpisu&lt;&#x2F;a&gt; na blogu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jozwiak.top&quot;&gt;Tymoteusza Jóźwiaka&lt;&#x2F;a&gt; dowiedziałem się, że na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mikr.us&#x2F;&quot;&gt;Mikrusie&lt;&#x2F;a&gt; istnieje coś, co nazywa się Cytrus, czyli osobna od samego Mikrusowego VPSa przestrzeń do hostowania stron internetowych - po szczegóły odsyłam do wpisu Tymoteusza.&lt;&#x2F;p&gt;
&lt;p&gt;Na Cytrusie działa sobie serwer WWW - konkretnie  &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;&quot;&gt;Nginx&lt;&#x2F;a&gt; - dzięki czemu publikacja strony wymaga jedynie umieszczenia w dedykowanym folderze plików strony internetowej oraz podpięcie odpowiedniej domeny. W panelu Cytrusa domenę można podpiąć do takiego folderu, ale można też podpiąć domenę do dowolnej aplikacji odpalonej na samym VPSie. To rozwiązuje praktycznie 99% moich potrzeb w kontekście hostingu, co bardzo mnie cieszy, bo dzięki temu będę mógł zrezygnować z płacenia za hosting w OVH, na którym obecnie trzymam tego bloga oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mapaapostazji.pl&quot;&gt;Mapę Apostazji&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;W związku z tym uroczyście ogłaszam, że GoRSSet ma nowy adres: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rss.mtsz.pl&quot;&gt;https:&#x2F;&#x2F;rss.mtsz.pl&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Z dodatkowych rzeczy, zrezygnowałem ze stylowania XSL do wyświetlania podglądu kanałów, ponieważ strasznym problemem było wyświetlanie pełnej treści artykułu w podglądzie, a na tym mi zależało. Od teraz za podgląd odpowiada skrypt PHP, który również działa na Cytrusie od razu.&lt;&#x2F;p&gt;
&lt;p&gt;Muszę przyznać, że ten cały Mikrus rzeczywiście jest imponujący. Trochę boli mnie brak adresacji IPv4 oraz pchanie całego ruchu przez Cloudflare, ale jak to mówią, jeden problem naraz.&lt;&#x2F;p&gt;
&lt;p&gt;Ten wpis nie jest sponsorowany, ale jeśli ktoś z Was stwierdzi, że Mikrus mógłby się mu przydać, to tutaj jest mój referal, dziękuję za kliknięcie: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mikr.us&#x2F;?r=mtszpl&quot;&gt;https:&#x2F;&#x2F;mikr.us&#x2F;?r=mtszpl&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115525866240087971&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Gorset dla ministra</title>
        <published>2025-10-20T19:17:00+00:00</published>
        <updated>2025-10-20T19:17:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-10-20-gorset-dla-ministra/"/>
        <id>https://mtsz.pl/blog/2025-10-20-gorset-dla-ministra/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-10-20-gorset-dla-ministra/">&lt;p&gt;Od dłuższego czasu nosiłem się z zamiarem napisania - w pewnym sensie przepisania - narzędzia do generowania kanałów RSS&#x2F;Atom dla stron, które tychże nie mają. Jakiś czas temu zrobiłem już podobne narzędzie, ale 1) było okropne, oraz 2) było w PHP, co sprawiało, że było okropne. Do nowej wersji zdecydowałem, że wybiorę &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;&quot;&gt;Go&lt;&#x2F;a&gt; - gdzieś przeczytałem, że bardziej się do tego nada, no i &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;miniflux.app&#x2F;&quot;&gt;Miniflux&lt;&#x2F;a&gt;, którego używam jako czytnika RSS, jest napisany w Go, i działa. Jeszcze nie wiem, czy będę żałował tej decyzji. Zobaczymy.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;projekty&#x2F;gorsset&#x2F;&quot;&gt;GoRSSet&lt;&#x2F;a&gt; (zgadnijcie czemu) działa na prostej zasadzie. Na podstawie dostarczonej do niego &quot;definicji&quot;, pobiera treść strony w HTMLu (lub JSONie, jeśli strona składa się z czterech plików JS), przy użyciu selektorów CSS (albo JSONPath) wyciąga sobie rzeczy takie jak tytuł, data, link, autor, treść, następnie skleja z tego wszystkiego XMLa, którego zapisuje do pliku. Koniec. Od tej pory ten statycznie zapisany plik jest kanałem. Teraz narzędzie wraz z definicjami wrzucasz na VPSa, odpalasz jakiegoś crona, żeby ten regenerował pliki&#x2F;kanały, i gotowe, MOŻNA DAWAĆ SUBA. Dodany jest super prosty caching, który nie jest nigdy czyszczony, bo jeszcze nie zdążyłem tego dopisać.&lt;&#x2F;p&gt;
&lt;p&gt;Przypomniał mi się przy okazji mem, który Oliwier z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kontrabanda.net&#x2F;&quot;&gt;Kontrabanda.net&lt;&#x2F;a&gt; wrzucił na tajną grupę na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;forum.internet-czas-dzialac.pl&#x2F;&quot;&gt;forum Fundacji &quot;Internet! Czas działać!&quot;&lt;&#x2F;a&gt;, i zainspirowany nim, postanowiłem od razu dorzucić do projektu definicję dla &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gov.pl&#x2F;web&#x2F;cyfryzacja&#x2F;wiadomosci&quot;&gt;wiadomości od Ministerstwa Cyfryzacji&lt;&#x2F;a&gt;. Oryginalną piaskownicą dla obecnego projektu, oraz wersji w PHP, była strona &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dlapilota.pl&#x2F;&quot;&gt;dlapilota.pl&lt;&#x2F;a&gt;, której kanał RSS jest jak Trójkąt Bermudzki, gdzie rzeczy losowo pojawiają się i znikają. Ze stronami ministerstw jest o tyle fajnie, że wszystkie z nich korzystają z dokładnie tego samego... yyy... CMSa? Nie wiem, z czego dokładnie - ale parsuje się je dokładnie tak samo. Więc jedną definicją jestem w stanie ogarnąć dużo ministerialnych kanałów naraz.&lt;&#x2F;p&gt;
&lt;p&gt;A jak już miałem te kilkanaście kanałów, to pomyślałem, że dobrze byłoby zrobić jakąś prostą warstwę prezentacji, więc od teraz generator oprócz kanałów generuje również elegancki indeks, a kanały RSS mają style, i przeglądarka potrafi je ładnie wyświetlić, zamiast tego paskudnego XMLa. Jak chcesz zobaczyć źródło, to klikasz prawym w przeglądarce i wybierasz &quot;Pokaż źródło strony&quot;, ty chory...&lt;&#x2F;p&gt;
&lt;p&gt;Wszystko wrzuciłem na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mikr.us&#x2F;&quot;&gt;VPS Mikrus&lt;&#x2F;a&gt;, który kupiłem nie wiem po co, ale teraz naprawdę się przydał. VPS nie ma adresu IPv4, i nie mogę podpiąć tam domeny tak, żeby w adresie nie było portu. &lt;del&gt;Certyfikatu też mi się nie chciało, ale to jest coś, co napisałem dosłownie w dwa dni, więc proszę: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;srv36.mikr.us:20156&#x2F;&quot;&gt;http:&#x2F;&#x2F;srv36.mikr.us:20156&#x2F;&lt;&#x2F;a&gt;.&lt;&#x2F;del&gt; Certyfikat się sam zadział! &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;srv36-20156.wykr.es&#x2F;&quot;&gt;https:&#x2F;&#x2F;srv36-20156.wykr.es&#x2F;&lt;&#x2F;a&gt; (dzięki Tymoteusz za &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;101010.pl&#x2F;@tymoteuszjozwiak&#x2F;115419857685426950&quot;&gt;protip&lt;&#x2F;a&gt;!) To prowizorka, więc istnieje ryzyko, że będzie działać bardzo długo i bez problemów, ale nie daję gwarancji. Kanały odświeżane są co godzinę przy pomocy tego pięknego skryptu:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;while true; do .&#x2F;generate; sleep 3600; done
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Jestę programistę&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-10-20-gorset-dla-ministra&#x2F;mem.jpeg&quot; alt=&quot;Polityk Ministerstwa Cyfryzacji jest siłą zmuszany do oglądania kanału RSS dodoawanego na stronę internetową&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115408077796914944&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Ponadprzeciętnie niekompetentny</title>
        <published>2025-10-16T12:10:00+00:00</published>
        <updated>2025-10-16T12:10:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-10-16-ponadprzecietnie-niekompetentny/"/>
        <id>https://mtsz.pl/blog/2025-10-16-ponadprzecietnie-niekompetentny/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-10-16-ponadprzecietnie-niekompetentny/">&lt;p&gt;Wczoraj dostałem od rekruterki telefon, że firma, do której się rekrutowałem, nie jest zainteresowana współpracą ze mną, z powodów, których nie potrafię zrozumieć. Ten wpis jest moją próbą opisania rzeczywistości zawodowej, w której się znajduję, w poszukiwaniu tego zrozumienia. Bo na ten moment to nie ma sensu.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;praca-jako-pretekst-do-nauki&quot;&gt;Praca jako pretekst do nauki&lt;&#x2F;h1&gt;
&lt;p&gt;Zacznijmy w losowym miejscu. Pewna firma, nazwijmy ją A, postanowiła podziękować mi za współpracę, a to uruchomiło z mojej strony chęć znalezienia nowej. W firmie A pracowałem od kilku lat, przez większość czasu tworząc i rozwijając projekty na iOSa, co jest moją główną kompetencją. Projekty były przeróżne: aplikacja sportowe integrujące się z zegarkiem i mierzące różne dane, aplikacje do śledzenia nawyków i planowania, aplikacje do czytania artykułów i odtwarzania podkastów, nawet aplikacje medyczne. Około rok temu, firmie &quot;skończyły się&quot; projekty iOSowe, i dostałem wtedy propozycję, żebym spróbował swoich możliwości w innych technologiach, których firma aktualnie potrzebuje, czyli Node.js oraz React. Nie będę ukrywał, że na tamten czas byłem mocno uprzedzony do JavaScriptu, ale jeszcze bardziej byłem uprzedzony do niezarabiania pieniędzy, więc wybór był oczywisty. Naturalnie wjechały też różne racjonalizacje pod tytułem &quot;poszerzanie horyzontów, powiększanie kompetencji&quot;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sjp.pwn.pl&#x2F;sjp&#x2F;summa-summarum;2525273.html&quot;&gt;Summa summarum&lt;&#x2F;a&gt; nie była to najgorsza rzecz w moim życiu zawodowym. Po roku pracy z JSem nabrałem wystarczająco doświadczenia, żeby być mniej uprzedzonym do samej technologii, a bardziej do sposobu, w jaki jest wykorzystywana - prawdopodobnie 99% stron w internecie korzystających z Reacta, mogłoby być statycznymi stronami - dokładnie tak jak moja. Ale to osobny temat. Minął rok, firmie &quot;skończyły się&quot; (hehe) projekty dla mnie, no i już nie było mnie gdzie migrować, więc się pożegnaliśmy, miło i sympatycznie mimo wszystko.&lt;&#x2F;p&gt;
&lt;p&gt;Zanim trafiłem do firmy A, pracowałem dla firmy B. W firmie B jednym z podstawowych elementów systemu, który rozwijaliśmy, była komunikacja po Bluetooth. Nigdy wcześniej nie pracowałem z Bluetoothem, ale to nie było problemem, bo jak praktycznie każdy programista, czas nauczenia się nowej technologii skraca się wykładniczo wraz ze wzrostem ogólnego doświadczenia. Przygód z Bluetoothem było &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sjp.pwn.pl&#x2F;sjp&#x2F;co-niemiara;2488982.html&quot;&gt;co niemiara&lt;&#x2F;a&gt;, szczególnie fascynujące było testowanie integracji tych urządzeń z aplikacjami mobilnymi, co doprowadziło do powstania nowych, fascynujących narzędzi. W międzyczasie na tapet wjechał pomysł stworzenia aplikacji we Flutterze - kolejnej technologii - którą również po skończonym czasie opanowałem w stopniu wystarczającym.&lt;&#x2F;p&gt;
&lt;p&gt;Pomiędzy firmą A i B, pracowałem w firmie C. Produktem firmy C znowu było coś kompletnie odmiennego od A i B, ale główną różnicą było to, że pewna część aplikacji była realizowana nie natywnie, a w WebView. Na tę decyzję architektoniczną też byłem wtedy bardziej obrażony niż jestem teraz, ale nie zmienia to faktu, że takie było wymaganie, więc nauczyłem się tego, co było mi potrzebne, i robiłem to, co było konieczne, dzięki czemu rezultat był taki, jaki był oczekiwany. Ta wiedza przydała mi się później w kolejnej firmie, D - znowu, kompletnie inna branża - gdzie mogłem te doświadczenia zaadaptować i ulepszyć. Na ten moment produkt firmy D ma się świetnie i jestem z niego bardzo zadowolony.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;produkt-i-technologia&quot;&gt;Produkt i technologia&lt;&#x2F;h1&gt;
&lt;p&gt;W każdej z tych prac największą satysfakcję dawała mi możliwość używania nowych, lepszych technologii. Nowe narzędzia, nowe biblioteki, szybszy, bardziej zoptymalizowany kod, mniej kodu, prostszy kod, mniej narzędzi, brak narzędzi. Nad samym produktem w żadnej firmie, w której pracowałem, nigdy nie czułem, że mam jakąkolwiek kontrolę, bo zawsze był nade mną jakiś właściciel produktu, który te wszystkie moje (i nie tylko mojej) pomysły najczęściej bagatelizował, a w lepszy dzień - torpedował. Ale technologia to moja kompetencja, i tutaj mogłem się wykazać, i często się wykazywałem, będąc nierzadko siłą napędową różnych małych rewolucji, z których moimi ulubionymi są migracje projektów do &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.swift.org&#x2F;swiftpm&#x2F;documentation&#x2F;packagemanagerdocs&#x2F;&quot;&gt;Swift Package Manger&lt;&#x2F;a&gt;, przejście na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;swiftui&#x2F;&quot;&gt;SwiftUI&lt;&#x2F;a&gt;, czy tworzenie aplikacji w nowej architekturze &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pointfreeco&#x2F;swift-composable-architecture&quot;&gt;The Composable Architecture&lt;&#x2F;a&gt;. To są duże rzeczy, które mają wpływ na wiele aspektów danego projektu.&lt;&#x2F;p&gt;
&lt;p&gt;Ten podział na skupienie na produkcie i technologii odkryłem pierwszy raz we &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;michellelim.dev&#x2F;writing&#x2F;stop-using-frontend-backend&#x2F;&quot;&gt;wpisie na blogu Michelle Lim&lt;&#x2F;a&gt; i bardzo mocno zarezonował we mnie, bo nagle byłem w stanie precyzyjnie określić to, co w każdej pracy tak naprawdę mnie &quot;jara&quot;. W każdej firmie, w której pracowałem, każdy projekt dotyczył zupełnie innego tematu, często nawet kilku, gdy pracowałem w tak zwanym &quot;software house&quot;. I to nie jest tak, że mogę sobie w pewnym momencie powiedzieć, że chcę, żebyśmy zmienili aplikację bankową na aplikację do komunikacji publicznej. Ale żebyśmy zmienili system zależności - już jak najbardziej. Poczucie satysfakcji wynika z poczucia kontroli.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;umiejetnosci-jako-pretekst-do-zabawy&quot;&gt;Umiejętności jako pretekst do zabawy&lt;&#x2F;h1&gt;
&lt;p&gt;W międzyczasie tych wszystkich wojaży zawodowych, zainspirowany doświadczeniami około-webowymi, zacząłem interesować się nowymi tematami.&lt;&#x2F;p&gt;
&lt;p&gt;Na pierwszy ogień wjechał ten oto blog - czy już raczej pełnoprawny internetowy portal osobisty. Najpierw sam próbowałem pisać silnik w PHP, który dynamicznie czyta pliki Markdown i formatuje je do HTMLa, później zacząłem korzystać z bibliotek do parsowania, stylowania , kolorowania składni kodu, a na dzień dzisiejszy korzystam z &lt;a href=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-10-16-ponadprzecietnie-niekompetentny&#x2F;www.getzola.org&quot;&gt;Zoli&lt;&#x2F;a&gt; jako frameworka. Do koszyka umiejętności wjechały technologie takie jak HTML, PHP, SQLite, CSS, SCSS, a nawet szablony Tera.&lt;&#x2F;p&gt;
&lt;p&gt;Druga fascynacja to self-hosting. Albo self-serving? Z jednej strony kupiłem sobie kilka domen, standardowy hosting, jakiegoś małego VPSa, i mały serwer domowy. Zacząłem eksperymentować z Proxmoxem, OPNsense, Dockerem, Minifluxem, HomeAssistantem. Na pewnym etapie stwierdziłem, że fajnie byłoby móc taki serwer postawić jedną komendą, i tak zanurzyłem się w świat DevOps i Terraforma. W głowie mam milion pomysłów dotyczących tego, co chcę jeszcze zrobić. Chciałbym mieć swój własny serwer haseł i sekretów, np. VaultWarden, własny serwer ze zdjęciami, np. Immich albo Ente. Ostatnio zaczęło mi przeszkadzać to, że w OPNsense nie da się łatwo postawić konfiguracji od razu podczas instalacji, i dokopałem się do czegoś, co nazywa się &quot;VyOS&quot; i na YouTube jest więcej wygenerowanych śmieci na jego temat niż rzetelnych materiałów.&lt;&#x2F;p&gt;
&lt;p&gt;Zaznajomienie się z PHP sprawiło, że napisałem sobie kilka bardzo prymitywnych, ale działających RSS-scraperów, np. do strony &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dlapilota.pl&#x2F;&quot;&gt;https:&#x2F;&#x2F;dlapilota.pl&#x2F;&lt;&#x2F;a&gt;, która w tamtym czasie nie miała żadnego kanału RSS, a teraz ma jakiś kulawy - więc, znowu, kolejny pomysł na aplikację, tym razem porządny scraper RSS, napisany w Swifcie, odpalony na VPSie. Jak tyko znajdę czas.&lt;&#x2F;p&gt;
&lt;p&gt;No i oczywiście mój koronny projekt: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mapaapostazji.pl&#x2F;&quot;&gt;Mapa Apostazji&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;badz-doskonaly&quot;&gt;Bądź doskonały&lt;&#x2F;h1&gt;
&lt;p&gt;No więc gdy firma A i ja pożegnaliśmy się, zacząłem rozglądać się za pracą w innej firmie. O dziwo, bardzo niedługo po tym, po długiej suszy na LinkedInie, odezwała się do mnie rekruterka, szukająca pracownika do firmy X. Podczas pierwszej rozmowy powiedziała mi, że proces rekrutacji będzie miał trzy etapy: &quot;programowanie&quot;, &quot;projektowanie systemów&quot; oraz &quot;dopasowanie kulturowe&quot; (to moje frywolne tłumaczenia).&lt;&#x2F;p&gt;
&lt;p&gt;Test z programowania był zabawny. Dostałem jakąś super prostą aplikację, z jakimiś super trywialnymi błędami, super. Problem polegał jedynie na tym, że użyta w nich architektura oraz biblioteki również w pewnym sensie były &quot;super stare&quot;. Tzn. sama aplikacja była napisana w architekturze MVVM, którą ja ostatni raz na oczy widziałem z pięć lat temu. Zarządzanie sygnałami w aplikacji było zrealizowane przy pomocy Combine, które ostatnio raz na oczy widziałem pewnie z 7 lat temu. I ja naprawdę nie rozumiem, co ten test miał sprawdzić. Oczywiście rozumiałem problem leżący u podstawy, więc większość testu spędziłem nad szukaniem odpowiednich funkcji. Ale to nie ma znaczenia, bo finalnie ten etap przeszedłem bardzo dobrze.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejnym etapem było projektowanie systemu. Nigdy wcześniej nie słyszałem o czymś takim, więc trochę to zbagatelizowałem - co było taktycznym błędem, biorąc pod uwagę, że rekruterka w materiałach do stanowiska podesłała mi tytuły dwóch &lt;strong&gt;KSIĄŻEK&lt;&#x2F;strong&gt; na temat &quot;Mobile System Design&quot;. Czajcie to? Żebym przeszedł jeden z etapów rekrutacji, muszę przeczytać dwie &lt;strong&gt;KSIĄŻKI&lt;&#x2F;strong&gt;. I już widzę te protesty, że w tych książkach jest wiedza niezbędna do bycia kompetentnym programistą - i pozwolę sobie nie zgodzić się. Z moich dotychczasowych doświadczeń wynika, że wiedza w tym etapie rekrutacji jest oceniana w 20%, a to co jest najważniejsze, to forma, albo raczej formuła. To dosłownie kojarzy mi się z egzaminem maturalnym, gdzie albo wstrzelisz się w klucz, albo odpadasz. Masz do zrobienia bardzo konkretne rzeczy, w bardzo określonej kolejności, nie możesz o niczym zapomnieć, musisz to wszystko zaplanować w czasie, narysować na diagramie, ogarnąć przypadki brzegowe. Musisz zadawać odpowiednie pytania, podejmować decyzje. Dosłownie musisz się nauczyć, jak przejść ten etap, bo żadna ilość wiedzy, umiejętności i kompetencji nie pomoże, jeśli nie będzie odpowiedniego &quot;formatu&quot;. Aha, no i oczywiście to nie ma nic wspólnego z prawdziwą pracą, bo ten projekt, który musisz podczas rekrutacji odwalić w mniej niż godzinę, w prawdziwym świecie projektujesz tygodniami, jeśli nie miesiącami. No i w prawdziwym życiu możesz się pomylić, a następnie poprawić błąd. Na rozmowie masz być doskonały. Innymi słowy, musisz odwalić balet, żeby potem móc być statystą w superprodukcji.&lt;&#x2F;p&gt;
&lt;p&gt;Ostatni etap w firmie X to było dopasowanie kulturowe. Tutaj też dostałem instrukcję od rekruterki, że firma ma wartości, że będzie pytać o przykłady z mojej kariery, które pokrywają się z wartościami. Straszny bełkot dla mnie, ale tutaj się postarałem, zrobiłem sobie tabelkę, wypisałem wszystko co chciałem powiedzieć. Gdy doszło do rozmowy, po drugiej stronie ekranu siedział rozleniwiony typ, który sennym głosem czytał pytania z kartki, i to w taki sposób, że gdy odpowiedziałem już na jakieś pytanie w poprzedniej odpowiedzi, to i tak to pytanie padało wraz z sakramentalnym &quot;wiem, że już na to pytanie odpowiedziałeś, ale [powrót do leniwego głosu] opowiedz jakim rodzajem pizzy jesteś i w jakiej sytuacji&quot;. Dam sobie zabrać komputer, że gość miał odpaloną transkrypcję, albo jakiś model, który mnie nagrywał, i potem napisał mu raport.&lt;&#x2F;p&gt;
&lt;p&gt;Ostatecznie firma podziękowała mi, bo nie jestem wystarczająco &quot;liderski&quot;. Ja, pchający nowe technologie i rozwiązania do wszystkich projektów, przy których pracuję - zawodowych i prywatnych. OKEEJ.&lt;&#x2F;p&gt;
&lt;p&gt;Druga firma, Y, z którą wiązałem największe nadzieje, miała identyczne etapy - i tutaj przyznaję, każdy z tych, w których uczestniczyłem, był na poziomie. Test programistyczny to był prosty mechanizm do zaimplementowania, i było tam dużo więcej pytań o podstawy, które mają istotne znaczenie podczas pisania kodu. Do projektowania systemów przygotowałem się lepiej, obejrzałem kilka materiałów w internecie, przeczytałem kilka artykułów. I chyba starając się ponad miarę, sam sobie podłożyłem nogę, bo zamiast opisać architekturę, na której znam się doskonale (TCA), zacząłem opisywać tę, której używałem tak dawno, że już jej nie pamiętam (MVVM), bo była ona najczęściej używana w oglądanych przeze mnie materiałach, i stwierdziłem, że programista po drugiej stronie może nie znać tej mojej. Po szkodzie stwierdzam - a co mnie to obchodzi, że on nie wie? To miał być jego problem, a ja zrobiłem go moim. Tym kończą się intensywne próby baletowania ponad miarę.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;nie-to-czego-szukamy&quot;&gt;&quot;Nie to, czego szukamy&quot;&lt;&#x2F;h1&gt;
&lt;p&gt;W trzeciej firmie, Z, od której zaczyna się ten post, zabawa skończyła się bardzo szybko, bo po &quot;dopasowaniu kulturowym&quot;, który był pierwszą rozmową. Sama rozmowa przebiegła moim zdaniem wybitnie. Miałem okazję powiedzieć o moich doświadczeniach, projektach w których pracowałem, dostałem kilka pytań o to, co mnie motywuje, z czego jestem najbardziej dumny w mojej karierze. Powiedziałem o wspomnianym wyżej artykule, o tym jak postrzegam moją pracę, i co mnie w niej najbardziej satysfakcjonuje. Było kilka pytań stricte programistycznych, w których mogłem zabłysnąć wiedzą i historiami o moich rewolucjach. Po rozmowie byłem święcie przekonany, że to była wręcz formalność, i że zaproszenie na kolejny etap dostanę bez żadnego problemu.&lt;&#x2F;p&gt;
&lt;p&gt;Jakież więc było moje zdziwienie, gdy okazało się, że &quot;firma szuka kogoś bardziej zajawionego produktem&quot;, a ja jestem &quot;za bardzo skupiony na technologii&quot;. To mnie złamało. Naprawdę nie kompiluje mi się w głowie to, że z mojego doświadczenia można wyciągnąć taki wniosek. I to nie jest tak, że uważam się za jakiegoś boga programowania, bo osobiście znam ludzi dużo młodszych ode mnie, którzy jednocześnie są dużo lepsi, zarówno pod względem znajomości technologii, jak i zrozumienia potrzeb klienta. Chwała im za to, życzę im jak najlepiej. Ale naprawdę chciałbym zrozumieć, czego w oczach tych wszystkich rekruterów mi brakuje, że pomimo trzynastu lat pracy, przeoraniu siebie przez kilkanaście projektów, języków programowania, technologii, platform, kilku firm o różnym stylu zarządzania, co najmniej kilku osobnych około-programistycznych hobby - nadal nie znajdują we mnie tego, czego szukają.&lt;&#x2F;p&gt;
&lt;p&gt;Tak naprawdę to doskonale wiem, czego mi brakuje. &lt;em&gt;Nie umiem w balet.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Jeśli dotarliście do końca tego smutnego wpisu, to rzućcie okiem na &lt;a href=&quot;&#x2F;projekty&quot;&gt;podstronę z moimi projektami&lt;&#x2F;a&gt;, z których na dzień pisania tego posta żaden nie jest stworzony w mojej &quot;macierzystej&quot; technologii, każdy opera się o zupełnie inny produkt i rozwiązuje zupełnie inny problem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mastodon.com.pl&#x2F;@mtsz&#x2F;115388820878138689&quot;&gt;Chodź, jest debata&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nowa odsłona Mapy Apostazji</title>
        <published>2025-10-12T13:59:00+00:00</published>
        <updated>2025-10-12T13:59:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-10-12-nowa-odslona-mapy-apostazji/"/>
        <id>https://mtsz.pl/blog/2025-10-12-nowa-odslona-mapy-apostazji/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-10-12-nowa-odslona-mapy-apostazji/">&lt;p&gt;Dzisiaj swoją odsłonę ma mój poboczny projekt - &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mapaapostazji.pl&#x2F;&quot;&gt;Mapa Apostazji&lt;&#x2F;a&gt;. W stosunku do starej wersji dużo zmieniło się na powierzchni oraz pod spodem.&lt;&#x2F;p&gt;
&lt;p&gt;Przede wszystkim nowy interfejs. Strona dzieli się teraz na zakładki. Pierwsza zakładka to mapa rozciągnięta na cały rozmiar okna, żeby dobrze działała na telefonie. Po kliknięciu w element, zamiast gigantycznego panelu, otwiera się mały popup z przyciskiem do strony szczegółowej - na razie jest tam minimalna ilość informacji, ale planuję dodać tam jakieś podsumowanie. Szczegóły dla danego kościoła to jest całkowita nowość. Dzięki temu lepiej wyeksponowane są informacje dotyczące konkretnej parafii, i można też przesłać komuś konkretnego linka. Zakładka ze statystykami dostała nowy wykres z ilością zgłoszeń oraz tabelkę popularności. Ostatnia zakładka to statyczne informacje. Do tego przycisk nowego zgłoszenia w nowym nagłówku. Podoba mi się, jak to wszystko wygląda i działa.&lt;&#x2F;p&gt;
&lt;p&gt;Po stronie inżynierskiej zmianie uległo wiele. Strona używa &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;htmx.org&#x2F;&quot;&gt;htmx&lt;&#x2F;a&gt; do ładowania niektórych komponentów. Nie wiem jeszcze czy przy tym zostanę, po prostu bardzo chciałem użyć jedynie HTMLa i JavaScriptu do stworzenia tej strony. Silnik mapy zmieniłem z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;leafletjs.com&#x2F;&quot;&gt;Leaflet&lt;&#x2F;a&gt; na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;maplibre.org&#x2F;&quot;&gt;MapLibre&lt;&#x2F;a&gt;, bo ChatGPT twierdzi, że ten drugi jest lżejszy i szybszy. Nie wiem tego na pewno, ale wrażenie sprawia dobre. Całkowicie przepisałem też parsery danych. To, jak ludzie wpisują dane adresowe, należałoby zbadać jakąś socjologiczną pracą naukową. W przyszłości pewnie trzeba będzie dodać możliwość wybierania miejsca na mapie czy autouzupełnianie adresu. Na razie mi się nie chce. Tak samo nie chce mi się pisać własnego formularza, więc używam tego od Google&#x27;a.&lt;&#x2F;p&gt;
&lt;p&gt;Może też czas założyć jakieś suppi czy inne buycoffee. Kawa z lokalnej kawiarni, którą bardzo lubię, podrożała z 17 do 22 zł, a łatwiej siąść do komputera na 10 godzin i klepać kod na chwałę ateizmu, pijąc smaczną kawusię.&lt;&#x2F;p&gt;
&lt;p&gt;Interesujący wzrost zgłoszeń obserwuję we wrześniu, ciekawe dlaczego. Wpisałem w Google i zobaczyłem to, dodaję dla potomnych:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;istotne.pl&#x2F;boleslawiec&#x2F;wiadomosc&#x2F;bN6&quot;&gt;istotne.pl&lt;&#x2F;a&gt; - Efekt Nawrockiego. Gwałtownie wzrosła liczba apostazji&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rp.pl&#x2F;plus-minus&#x2F;art42562471-mariusz-cieslik-inne-reakcje-na-wynik-wyborow-bledna-przy-efekcie-karola-nawrockiego&quot;&gt;rp.pl&lt;&#x2F;a&gt; - Mariusz Cieślik: Inne reakcje na wynik wyborów bledną przy „efekcie Karola Nawrockiego”&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.tokfm.pl&#x2F;polska&#x2F;dolnoslaskie&#x2F;tokfm-7-189664-32026948-niespodziewany-efekt-wygranej-nawrockiego-postanowila-ze&quot;&gt;tokfm.pl &lt;&#x2F;a&gt; - Niespodziewany efekt wygranej Nawrockiego. &quot;Postanowiła, że wypisze się z Kościoła&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wroclaw.wyborcza.pl&#x2F;wroclaw&#x2F;7,35771,32018382,po-wyborach-wzroslo-zainteresowanie-apostazja-efekt-karola.html&quot;&gt;wroclaw.wyborcza.pl&lt;&#x2F;a&gt; - Rośnie zainteresowanie apostazją po wyborach prezydenckich. &quot;Efekt Karola Nawrockiego&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.wprost.pl&#x2F;kraj&#x2F;12046276&#x2F;wygrana-nawrockiego-problemem-dla-kosciola-rosnie-liczba-wnioskow-o-apostazje.html&quot;&gt;wprost.pl&lt;&#x2F;a&gt; - Wygrana Nawrockiego napędziła apostazję? Te dane mówią same za siebie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;noizz.pl&#x2F;informacyjne&#x2F;rosnie-zainteresowanie-apostazja-to-ma-byc-efekt-nawrockiego&#x2F;gpm8fn2&quot;&gt;noizz.pl&lt;&#x2F;a&gt; - Rośnie zainteresowanie apostazją. To ma być &quot;efekt Nawrockiego&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wpolsce24.tv&#x2F;publicystyka&#x2F;oskarzaja-nawrockiego-ze-przez-niego-sa-apostazje,35958&quot;&gt;wpolsce24.tv&lt;&#x2F;a&gt; - Obrzydliwe. Oskarżają prezydenta-elekta, że przez niego ludzie odchodzą z Kościoła. „Efekt Karola Nawrockiego&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dorzeczy.pl&#x2F;opinie&#x2F;742005&#x2F;efekt-nawrockiego-masowa-apostazja-po-wyborach.html&quot;&gt;dorzeczy.pl&lt;&#x2F;a&gt; - Nawrocki i apostazja. &quot;GW&quot; pisze o osobliwym zjawisku&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Podsumowując: &lt;strong&gt;OBRZYDLIWY EFEKT KAROLA NAWROCKIEGO&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nie tylko blogowanie</title>
        <published>2025-10-05T23:16:00+00:00</published>
        <updated>2025-10-05T23:16:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-10-05-nie-tylko-blogowanie/"/>
        <id>https://mtsz.pl/blog/2025-10-05-nie-tylko-blogowanie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-10-05-nie-tylko-blogowanie/">&lt;p&gt;Szybki wpis, bo jest już późno.&lt;&#x2F;p&gt;
&lt;p&gt;Cały dzisiejszy dzień spędziłem na tworzeniu całkowicie nowej sekcji na mojej stronie: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;arteka&quot;&gt;Arteka&lt;&#x2F;a&gt;. Co to jest Arteka? Nie wiem. Szukałem słowa, które najlepiej odda to, co ma się tam znaleźć: wszystkie twórce dzieła kultury i sztuki, z którymi miałem do czynienia: muzyka, książki, filmy, seriale, gry video, spektakle, wystawy, gry planszowe, koncerty, i tak dalej. Posiadam konta na LubimyCzytać oraz Filmwebie, i jakoś zawsze bolało mnie to, że te wszystkie dane, które tam generuję, nie są do mojej pełnej dyspozycji, i mogą w każdym momencie zniknąć, całkowicie niezależnie ode mnie. Tutaj wszystko zniknie tylko z jednego powodu: bo to skasuję. Albo zepsuję. Dwóch powodów. No i są ładne kolorki.&lt;&#x2F;p&gt;
&lt;p&gt;Inspiracją tego projektu była &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;media.ginatrapani.org&#x2F;&quot;&gt;ta oto strona&lt;&#x2F;a&gt; od Giny Trapani. Jak łatwo się domyśleć, jest to praktycznie ideowa kopia. Moje rozwiązanie jest oczywiście w pełni oparte o szablon w Zoli oraz o pliki Markdown, dzięki czemu mogę dopisywać kolejne pozycje bezpośrednio w Obsidianie. W niedalekiej przyszłości planuję również stworzyć kopię &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;weeks.ginatrapani.org&#x2F;&quot;&gt;tej strony&lt;&#x2F;a&gt;, bo myślę, że fajnie mieć wgląd w to, na czym spędza się swoje życie, tym bardziej, że trochę lat już mam , i kilka rzeczy przeżyłem.&lt;&#x2F;p&gt;
&lt;p&gt;Przy okazji na stronę wjechał inny dział, który roboczo nazywał się &quot;handelek&quot;, ale było za długo, więc teraz nazywa się &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;oddam&#x2F;&quot;&gt;Oddam&lt;&#x2F;a&gt;. Tam mam zamiar wrzucać wszystkie rzeczy, które posiadam, a których już nie używam. Na razie nie zdecydowałem, w jaki sposób, kiedy i komu oddam (albo za ile sprzedam!) te wszystkie &quot;graty&quot; - szczególnie że dosłownie poprzedni post to moje wynurzenia na temat starej elektroniki - ale to jest jakiś krok w kierunku. Przy okazji pracy nad tym działem dorzuciłem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mtsz-pl&#x2F;apollo&#x2F;commits&#x2F;main&#x2F;?author=mtsz-pl&amp;amp;since=2025-10-05&amp;amp;until=2025-10-05&quot;&gt;trochę kodu&lt;&#x2F;a&gt; do motywu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;themes&#x2F;apollo&#x2F;&quot;&gt;Apollo&lt;&#x2F;a&gt;, którego używam na stronie od niedawna. Mi był potrzebny, a może komuś innemu też się przyda.&lt;&#x2F;p&gt;
&lt;p&gt;To tyle na dziś. Dobranoc.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Elektrośmieci w pełni działające</title>
        <published>2025-10-04T19:53:00+00:00</published>
        <updated>2025-10-04T19:53:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-10-04-elektrosmieci-w-pelni-dzialajace/"/>
        <id>https://mtsz.pl/blog/2025-10-04-elektrosmieci-w-pelni-dzialajace/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-10-04-elektrosmieci-w-pelni-dzialajace/">&lt;p&gt;Jedną z moich ulubionych &quot;kategorii przedmiotów&quot; - cokolwiek to znaczy - są elektroniczne gadżety. Gdybym miał posortować te kategorie według liczności egzemplarzy rzeczy, elektronika byłaby prawdopodobnie na trzecim miejscu, po sprzęcie turystycznym oraz... OK, na drugim miejscu. Taka &quot;imponująca&quot; kolekcja ma jednak jeden gigantyczny problem: starzeje się z czasem.&lt;&#x2F;p&gt;
&lt;p&gt;I to nie jest tak, że te wszystkie stare telefony, komputery i inne gadżety przestają działać. Problem jest raczej taki, że przestają mieć sens.&lt;&#x2F;p&gt;
&lt;p&gt;Mam np. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;IPod_Touch_(6th_generation)&quot;&gt;iPoda Touch 6&lt;&#x2F;a&gt;, którego kupiłem bardzo dawno temu, żeby móc uruchamiać tworzoną w tamtym czasie aplikację na fizycznym urządzeniu, zamiast jedynie na symulatorze. Urządzenie małe, lekkie, działające wtedy na aktualnej wersji systemu iOS. W tym momencie jest to praktycznie nieużywalny kawałek elektroniki, nieaktualizowany od pięciu albo i więcej lat, bez wsparcia nowoczesnych protokołów komunikacyjnych, nie obsługujący praktycznie większości aplikacji, które działają akurat od wersji systemu iOS o jeden wyższej.&lt;&#x2F;p&gt;
&lt;p&gt;Inny przykład: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Nokia_6500_slide&quot;&gt;Nokia 6500 Slide&lt;&#x2F;a&gt;. Ekran 2,2 cala, procesor nie wiadomo nawet jaki, RAM 32 MB, tylny aparat 3,2 megapiksela! Ten telefon dosłownie znalazłem na dnie jakiegoś starego podełka po butach. W któryś weekend nudziło mi się wystarczająco, żeby go rozkręcić, wyczyścić i skręcić z powrotem. Udało mi się z niego wyciągnąć nawet jakieś zboże. Telefon elegancko się ładuje, wszystko w nim działa. Ale wspiera jedynie 2G oraz niepełne 3G. Bluetooth 2.0. WiFi brak przeglądarka tylko &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wireless_Application_Protocol&quot;&gt;WAP&lt;&#x2F;a&gt;. Wniosek? Jest kompletnie bezużyteczny.&lt;&#x2F;p&gt;
&lt;p&gt;W pudełku mam też kilka losowych routerów, switchy, nawigacji samochodowych, kalkulatorow, ładowarek, adapterów dysków, powerbanków. dysków twardych, kilka smartfonów, a nawet kilka w pełni działających komputerów. Te, do których miałem najwięcej cierpliwości, zaktualizowane do najwyższych możliwych wersji oprogramowania, często alternatywnego (&lt;del&gt;nieoficjalne&lt;&#x2F;del&gt; to okropne słowo w tym kontekście - skoro nie ma oficjalnego, jak może być nieoficjalne?), jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lineageos.org&#x2F;&quot;&gt;LineageOS&lt;&#x2F;a&gt; na smartfonach czy &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;openwrt.org&#x2F;pl&#x2F;start&quot;&gt;OpenWRT&lt;&#x2F;a&gt; na routerach. I wszystkie leżą sobie u mnie na regale, kupionym tylko po to, żebym miał je gdzie odłożyć, i czekają na to, żeby nic się z nimi nie stało.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Zmiany, zmiany, zmiany</title>
        <published>2025-09-29T21:29:00+00:00</published>
        <updated>2025-09-29T21:29:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-09-29-zmiany-zmiany-zmiany/"/>
        <id>https://mtsz.pl/blog/2025-09-29-zmiany-zmiany-zmiany/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-09-29-zmiany-zmiany-zmiany/">&lt;p&gt;Kilka minimalnych zmian na stronie.&lt;&#x2F;p&gt;
&lt;p&gt;Po pierwsze zmieniłem motyw z kradzionego na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;themes&#x2F;apollo&#x2F;&quot;&gt;Apollo&lt;&#x2F;a&gt; (link do repozytorium: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;not-matthias&#x2F;apollo&quot;&gt;Apollo&lt;&#x2F;a&gt;). Wygląda całkiem podobnie do poprzedniego, podoba mi się wizualnie, za to nie wymaga praktycznie żadnych zmian z mojej strony - jedynie rozszerzeń, no i ma szablon do kart, więc mogę teraz zrobić &quot;szołkejs&quot; moich projektów na jednej, estetycznej stronie.&lt;&#x2F;p&gt;
&lt;p&gt;Przy okazji trochę posprzątałem &quot;kod&quot; wpisów. Przede wszystkim posusuwałem praktycznie wszystkie tagi HTML - fajnie, że Markdown je wspiera, ale im więcej Markdowna w Markdownie, tym lepiej. Został praktycznie tylko &lt;code&gt;audio&lt;&#x2F;code&gt;, którego niczym nie da się zastąpić, oraz &lt;code&gt;shortcodes&lt;&#x2F;code&gt;, których tym bardziej nie da się zastąpić.&lt;&#x2F;p&gt;
&lt;p&gt;Od teraz konsekwentnie używam YAMLa do nadawania wpisom atrybutów - wcześniej miałem miks YAML&#x2F;TOML, ale tylko ten pierwszy działa zarówno w Zoli, jak i w Obsidianie, a to jest mus.&lt;&#x2F;p&gt;
&lt;p&gt;Dodałem linka do Codeberga, bo motyw pozwala wrzucać linki do &quot;portali społeczniościowych&quot;! RSS również jest teraz linkiem społecznościowym.&lt;&#x2F;p&gt;
&lt;p&gt;OK, blog odświeżony. Teraz będzie deploy - zobaczymy, czy nie skaszanią się wszystkie możliwe RSSy. I można wracać do (bardziej) regularnego blogowania.&lt;&#x2F;p&gt;
&lt;p&gt;EDIT: działa.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Stary nowy zegarek</title>
        <published>2025-08-14T09:04:00+00:00</published>
        <updated>2025-08-14T09:04:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-08-14-stary-nowy-zegarek/"/>
        <id>https://mtsz.pl/blog/2025-08-14-stary-nowy-zegarek/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-08-14-stary-nowy-zegarek/">&lt;p&gt;Dawno temu, będąc świeżo &quot;po studiach&quot;, z jakiegoś powodu kupiłem sobie zegarek. Wybrałem wtedy model Timex T2N794, który spodobał mi się, ponieważ był cały czarny. Koperta, znaczniki godzin, wskazówki, pasek - wszystko czarne - oprócz sekundnika. Ten mimimalizm bardzo mi odpowiadał. Cena co prawda na tamte czasy nie była dla mnie zbyt minimalna, ale decyzja zapadła. Kupiłem.&lt;&#x2F;p&gt;
&lt;p&gt;I chodziłem w tym zegarku zawsze i wszędzie, możliwe nawet, że w nim spałem. Do momentu, aż w końcu nie przestałem - nawet nie pamietam, dlaczego. Wtedy zegarek trafił do pudełka o nazwie  &lt;em&gt;pudełko z rzeczami, których już nie używam, ale których nie chcę wyrzucać, bo nadal są dobre, ale też nie sądzę, że ktokolwiek je ode mnie odkupi, a ja nie chcę oddawać ich za darmo, więc je tak trzymam&lt;&#x2F;em&gt;. Aktualnie pudełko zamieniło się w dwa regały z siedmioma półkami po 80 cm szerokości każdy. Ale o tym innym razem.&lt;&#x2F;p&gt;
&lt;p&gt;Ostatnim zegarkiem, który nosiłem, był Apple Watch 8, który dostałem od firmy, dla której robiłem aplikację na ten zegarek, po to, żeby móc testować to, co robię na bieżąco. Oczywiście w czasie, gdy nie pracowałem, zegarka również używałem. Nie jestem jakimś wielkim fanem inteligentnych zegarków, ale Apple Watch był w stanie tę moją obojętność odrobinę przesunąć, bo nie da się mu odmówić użyteczności. Rzeczy takie jak pomiar parametrów podczas treningów (można w nim nawet pływać!), łagodne, bezhałasowe budzenie, monitorowanie parametrów zdrowia, czy dyskretne powiadamianie to wygody, do których łatwo się przyzwyczaić. Jednak projekt się skończył - przynajmniej dla mnie - więc i zegarek trzeba było oddać. W ten sposób powróciłem na bezzegarkowie.&lt;&#x2F;p&gt;
&lt;p&gt;Wtem przypomniałem sobie o moim starym, dobrym Timexie. Przekopałem regał, znalazłem pudełko, w nim znalazłem Timexa, trochę nazgryzionego przez czas, bo niedziałającego, oraz z jakiegoś powodu, bez paska - ale nadal wyglądającego świetnie. Pozostała tylko jedna rzecz do zrobienia: iść do zegarmistrza, wymienić baterię, dokupić pasek, i rozpocząć kolejny rozdział w swoim życiu. Cztery rzeczy do zrobienia.&lt;&#x2F;p&gt;
&lt;p&gt;Pasek chciałem kupić czarny, żeby zachować rzetelność historyczną, oraz &quot;tekstylny&quot; - nie metalowy i nie skórzany. Zegarmistrz pokazał mi wszystkie tekstylne, pasujące do szerokości zegarka paski. Praktycznie wszystkie były czarne (co za zbieg okoliczności), niektóre miały kolorowe akcenty, niektóre miały kolorowe paski po całej długości. I z jakiegoś powodu, jeden z tych pasków był cały czerwony.&lt;&#x2F;p&gt;
&lt;p&gt;Zgadnijcie co.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-08-14-stary-nowy-zegarek&#x2F;timex.png&quot; alt=&quot;timex&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Mam nowy zegarek.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Programowanie for humanity</title>
        <published>2025-08-10T16:32:00+00:00</published>
        <updated>2025-08-10T16:32:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-08-10-programowanie-for-humanity/"/>
        <id>https://mtsz.pl/blog/2025-08-10-programowanie-for-humanity/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-08-10-programowanie-for-humanity/">&lt;p&gt;Dzisiaj wydarzyła się pewna ważna dla mnie rzecz. Stworzyłem pierwszego w życiu poważnego &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.internet-czas-dzialac.pl&#x2F;icd&#x2F;mt940-mbank-ts&#x2F;pulls&#x2F;1&quot;&gt;pull requesta&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Nie jest to nic imponującego w kontekście ani jakości kodu, ani użytych rozwiązań. Narzędzie, do którego dorzuciłem trochę swojego kodu, to prosty konwerter historii transakcji, którą można wyeksportować z mBanku, z formatu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;CSV_(format_pliku)&quot;&gt;CSV&lt;&#x2F;a&gt; do formatu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;MT940&quot;&gt;MT940&lt;&#x2F;a&gt;. Super niszowa sprawa dla księgowych. O ile dobrze zrozumiałem, istnieje szansa, że z tego rozwiązania korzysta dosłownie jedna osoba.&lt;&#x2F;p&gt;
&lt;p&gt;Czemu więc poświęcam czas na napisanie posta relacjonującego tak błahą w sumie rzecz? Ponieważ od dawna obiecuję sobie, że w końcu przysiądę do jakiegoś publicznego projektu programistycznego i zrobię coś pożytecznego dla ludzkości, dla własnej satysfakcji, dla poprawienia czegoś, co mogę poprawić. Potrzebę tę odczuwam bardziej, od kiedy zapoznałem się z historią Jacka, dziadka Louisa Rossmana. Historia jest bardzo ciekawa, polecam odsłuchać - nie będę spoilerować ani spamować (od 4:40 do 12:57).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ksjzI-8Rz2w&quot;&gt;Modern influencer culture has GOT TO GO!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am Jack&#x27;s kid from the street&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Przy okazji poznałem kilka nowych rzeczy, które po prostu wypiszę, żeby w internecie został po tym ślad:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;postanowiłem się postarać i zostosowałem w nazwie commitów coś, co okazało się być konwencją &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.conventionalcommits.org&#x2F;&quot;&gt;Conventional Commits&lt;&#x2F;a&gt;. Wygląda ślicznie.&lt;&#x2F;li&gt;
&lt;li&gt;dodatkowo do stylów CSS wykorzystałem bibliotekę o nazwie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;picocss.com&#x2F;&quot;&gt;PicoCSS&lt;&#x2F;a&gt;, dzięki której można stronę HTML napisać &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.w3schools.com&#x2F;html&#x2F;html5_semantic_elements.asp&quot;&gt;semantycznie&lt;&#x2F;a&gt; i ostyluje się ona &quot;sama&quot; w miarę elegancko.&lt;&#x2F;li&gt;
&lt;li&gt;do uruchamiania środowiska programistycznego skorzystałem z pakietu NPM &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;concurrently&quot;&gt;concurrently&lt;&#x2F;a&gt;, który równocześnie odpala kilka skryptów naraz, łączy ich ouptuty w jeden strumień, i umożliwia robienie kolorków i etykiet. Ładne i przydatne.&lt;&#x2F;li&gt;
&lt;li&gt;w CSS można zrobić coś, co nazywa się &lt;code&gt;mask-image&lt;&#x2F;code&gt;, co w połączeniu z obrazkiem wspierającym przezroczystość można wykorzystać jako trik do ustawienia dowolnego koloru tego obrazka.&lt;&#x2F;li&gt;
&lt;li&gt;oraz że 120 to optymalny limit liczby znaków w edytorze kodu.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To był dobry dzień. A nawet nie ma siedemnastej.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Stary kod zawinięty w złoty papierek</title>
        <published>2025-07-21T20:58:00+00:00</published>
        <updated>2025-07-21T20:58:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-21-stary-kod-zawiniety-w-zloty-papierek/"/>
        <id>https://mtsz.pl/blog/2025-07-21-stary-kod-zawiniety-w-zloty-papierek/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-21-stary-kod-zawiniety-w-zloty-papierek/">&lt;p&gt;To będzie krótka notka. Swift Package Manager to narzędzie do zarządzania zależnościami w projektach pisanych w Swift, z całkiem elegancką integracją z Xcode. Zanim powstał, złotym standardem było inne narzędzie: stworzone przez społeczność &lt;strong&gt;Cocoapods&lt;&#x2F;strong&gt; napisane w języku Ruby. Swoje czasy chwały święcił, gdy do pisania aplikacji na urządzenia Apple&#x27;a używało się języka Objective-C. Czasy się jednak zmieniają, powstają nowe języki, i nowe narzędzia. I wypadałoby z duchem tego czasu iść, ale prawda jest taka, że nadal wiele projektów napisanych w Obj-C i wspartych &quot;podsami&quot; nadal działa i ma się świetnie.&lt;&#x2F;p&gt;
&lt;p&gt;Jest sprytny sposób na pozbycie się przynajmniej jednego z tych reliktów - można z powodzeniem zastąpić Cocoapods SPMem.&lt;&#x2F;p&gt;
&lt;p&gt;W ramach pliku &lt;code&gt;Package.swift&lt;&#x2F;code&gt; można zdefiniować tak zwany &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;documentation&#x2F;PackageDescription&#x2F;Target&#x2F;binaryTarget(name:path:)&quot;&gt;&lt;code&gt;.binaryTarget&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, który zamiast ścieżki do plikow kodu źrodłowego, oczekuje na ścieżkę do zbudowanego wcześniej pliku &lt;code&gt;.xcframework&lt;&#x2F;code&gt;, lub nawet URLa do skompresowanego Zipem XCFrameworka. Niektóre stare biblioteki często mają załączone w artefaktach kolejnych wersji gotowe, skompilowane biblioteki, ale dla tych oferujących sam kod, również jest ratunek - wystarczy własnorecznie zbudować taki Cocoapodsowy projekt, następnie skompresowany wgrać na jakiegoś CDNa, lub nawet wrzucić do osobnego repozytorium, zbudować odpowiedni plik &lt;code&gt;PackageDescription&lt;&#x2F;code&gt; - i możemy spokojnie zrobić jeden mały krok do przodu w drodze do modernizacji naszego projektu.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;pod deintegrate&lt;&#x2F;code&gt; - bardzo przydatna komenda, skoro już jesteśmy w tamcie.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Xcode nie umie w zmienne środowiskowe</title>
        <published>2025-07-21T20:28:00+00:00</published>
        <updated>2025-07-21T20:28:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-21-xcode-nie-umie-w-zmienne-srodowiskowe/"/>
        <id>https://mtsz.pl/blog/2025-07-21-xcode-nie-umie-w-zmienne-srodowiskowe/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-21-xcode-nie-umie-w-zmienne-srodowiskowe/">&lt;p&gt;Tło tej historii jest takie: w jednym z projektów na iOS, nad którym pracuję, wdrożyliśmy system ciągłej integracji od Apple&#x27;a - Xcode Cloud. Do przekazywania sekretów używamy w projekcie zmiennych środowiskowych, a Xcode Cloud udostępnia relatywnie przyjemny interfejs do ich ustawiania. Niestety da się to robić jedynie pojedynczo, a ponieważ aplikacja jest w fazie ciągłego rozwoju, klikanie po interfejsie stało się po jakimś czasie irytujące. Wpadłem więc na pomysł, że zmienne środowiskowe będziemy przechowywać w samym repozytorium, w pliku &lt;code&gt;.env&lt;&#x2F;code&gt;, który następnie zaszyfrujemy przy użyciu OpenSSL, a deszyfracją i integracją tych informacji  zajmie się skrypt uruchamiany automatycznie w czasie komplacji, w ostatnim możliwym momencie. W takim przypadku jedyną zmienną środowiskową, którą trzeba dodać do Xcode Cloud, i która na dodatek będzie się zmieniać raczej rzadko, jest klucz deszyfrujący. Jego złożoność zależy tylko i wyłącznie od nas, algorytmy szyfrujące można sobie dobierać ze wszystkich dostępnych, bezpieczeństwo zachowane, wygoda zwiększona.&lt;&#x2F;p&gt;
&lt;p&gt;Oczywiście rozwiązanie to działało przede wszystkim na Xcode Cloud, ale nic nie stało na przeszkodzie, żeby również lokalnie skorzystać z tego dobrodziejstwa. Plik &lt;code&gt;.env&lt;&#x2F;code&gt; można dorzucić do &lt;code&gt;.gitignore&lt;&#x2F;code&gt;, i następnie bez ryzyka trzymać lokalnie na swoim komputerze. Dodatkowo nasz skrypt zajmuje się również aktualizacją wersji zaszyfrowanej, jeśli coś zmienimy, sprawdza także spójność danych. Wszystko, co zostało do zrobienia, to wrzucenie do swojego lokalnego pliku &lt;code&gt;~&#x2F;.zshrc&lt;&#x2F;code&gt; zmiennej środowiskowej &lt;code&gt;DECRYPTION_KEY=supertajnehaslo123&lt;&#x2F;code&gt;, odpalenie Xcode&#x27;a i problem załatwiony, prawda? &lt;br &#x2F;&gt;
Prawda?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-07-21-xcode-nie-umie-w-zmienne-srodowiskowe&#x2F;nieprawda.png&quot; alt=&quot;nieprawda.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Otusz nieprawda.&lt;&#x2F;p&gt;
&lt;p&gt;Okazuje się, że Xcode nie ma dostępu do lokalnych zmiennych środowiskowych. Teraz tak: ja nie wiem, czy to dobrze, czy jednak nie dobrze. Gdybym miał powiedzieć, co cenię w życiu najbardziej, to powiedziałbym, że nie Xcode&#x27;a. No ale siła przyzwyczajenia, natywna aplikacja, znajomy interfejs. Trzeba rozwiązać kolejny problem - na szczęście ten jest banalnie prosty.&lt;&#x2F;p&gt;
&lt;p&gt;Kto ma dostęp do zmiennych środowiskowych? Każdy, kto jest odpalony z Terminala. Wystarczyło więc napisać skrypt &lt;code&gt;open -a &#x2F;Applications&#x2F;Xcode.app mujprojekt.xcodeproj&lt;&#x2F;code&gt;, i ta, oraz każda inna zmienna we wszechświecie jest dostępna! Oczywiście można to zoptymalizować - wystarczy stworzyć osobny plik i tam wrzucić tę zmienną, a następnie zrobić coś w stylu &lt;code&gt;source tajnyplik &amp;amp;&amp;amp; open ...&lt;&#x2F;code&gt;, albo nawet wrzucać zmienną bezpośrednio w komendzie &lt;code&gt;DECRYPTION_KEY=abc open...&lt;&#x2F;code&gt;, &lt;em&gt;you know the drill&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Została ostatnia sprawa. Odpalanie terminala i uruchamianie skryptu to stanowczo zbyt dużo pracy. Na szczęście od jakiegoś czasu macOS ma aplikację &quot;Skróty&quot;! W tej aplikacji można sobie zrobić &quot;skrót&quot; do praktycznie dowolnej czynności, w tym oczywiście skrót do uruchomienia komendy w Terminalu. W ten oto sposób, co prawda dorobiłem się kolejnej ikonki w moim systemowym Docku, ale za to nie muszę już klikać jak małpa po zmiennych środowiskowych w Xcode Cloud. Ciekawe, czy one kiedykolwiek się zmienią. Byłoby naprawdę szkoda, gdyby moje wspaniałe rozwiązanie nie zaoszczędziło czasu ani pracy nikomu nigdy.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Leniwe ładowanie</title>
        <published>2025-07-21T20:05:00+00:00</published>
        <updated>2025-07-21T20:05:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-21-leniwe-ladowanie/"/>
        <id>https://mtsz.pl/blog/2025-07-21-leniwe-ladowanie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-21-leniwe-ladowanie/">&lt;p&gt;Dzisiaj wpisów będzie kilka (chyba że zmienię zdanie w połowie pisania kolejnego), bo lubię porządeczek i separację.&lt;&#x2F;p&gt;
&lt;p&gt;Wbrew swojej woli zostałem zmuszony do pracy z okropną technologią, jaką są technologie webowe. Naprawdę wolałbym nie wiedzieć, co to jest &lt;code&gt;node&lt;&#x2F;code&gt;, &lt;code&gt;yarn&lt;&#x2F;code&gt;, i te wszystkie rzeczy, no ale potrzebuje pieniądze, bo ludzie nie chcą mi dawać jedzenia za nic innego. Ponieważ projektów, nad którymi pracuję, jest kilka, a każdy z nich używa dokładnie różnej wersji Node&#x27;a od każdej innej, koniecznym stało się użycie kolejnego narzędzia o nazwie &lt;code&gt;nvm&lt;&#x2F;code&gt; - Node Version Manager. Narzędzie bardzo przyjemne w użytku - pisze sobie &lt;code&gt;nvm instal 24&lt;&#x2F;code&gt; i &lt;code&gt;nvm&lt;&#x2F;code&gt; instaluje Node&#x27;a w wersji 24; piszesz &lt;code&gt;nvm use 24&lt;&#x2F;code&gt; - i wiadomo co.&lt;&#x2F;p&gt;
&lt;p&gt;Jednak to narzędzie ma jeden kluczowy problem. Żeby działało, do pliku &lt;code&gt;~&#x2F;.zshrc&lt;&#x2F;code&gt; musiałem dopisać wywołanie skryptu &lt;code&gt;nvm.sh&lt;&#x2F;code&gt;, dostarczonego podczas instalacji. I ten skrypt jest uruchamiany przy każdym otwarciu nowego okna Terminala. I to uruchomienie trwa co najmniej 0,2 sekundy, co po sto pięćdziesiątym razem jest &lt;em&gt;naprawdę&lt;&#x2F;em&gt; irytujące.&lt;&#x2F;p&gt;
&lt;p&gt;Ale od czego są kąkutery? Wiadomo - od hakowania. Oto hakowanie. Taki skrypt wrzucam sobie w sam środek wspomnianego wcześniej pliku &lt;code&gt;.rc&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;zsh&quot;&gt;_lazy_load_nvm() {
  echo -n &amp;quot;Lazy loading NVM... &amp;quot;
  unset -f node npm nvm yarn
  if [ -s &amp;quot;&#x2F;opt&#x2F;homebrew&#x2F;opt&#x2F;nvm&#x2F;nvm.sh&amp;quot; ]; then
    . &amp;quot;&#x2F;opt&#x2F;homebrew&#x2F;opt&#x2F;nvm&#x2F;nvm.sh&amp;quot;
  fi
  if [ -s &amp;quot;&#x2F;opt&#x2F;homebrew&#x2F;opt&#x2F;nvm&#x2F;etc&#x2F;bash_completion.d&#x2F;nvm&amp;quot; ]; then
    . &amp;quot;&#x2F;opt&#x2F;homebrew&#x2F;opt&#x2F;nvm&#x2F;etc&#x2F;bash_completion.d&#x2F;nvm&amp;quot;
  fi
  echo &amp;quot;done!&amp;quot;
  &amp;quot;$@&amp;quot;
}

node() { _lazy_load_nvm node &amp;quot;$@&amp;quot;; }
npm() { _lazy_load_nvm npm &amp;quot;$@&amp;quot;; }
nvm() { _lazy_load_nvm nvm &amp;quot;$@&amp;quot;; }
yarn() { _lazy_load_nvm yarn &amp;quot;$@&amp;quot;; }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Co tu się dzieje? Cztery funkcje na dole &quot;zasłaniają&quot; na chwilę odpowiednie programy, by najpierw wymusić załadowanie &lt;code&gt;nvm&lt;&#x2F;code&gt; w funkcji &lt;code&gt;_lazy_load_nvm&lt;&#x2F;code&gt;. Nasza leniwie ładująca funkcja pierwsze co robi, to &quot;odsłania&quot; na powrót wspomniane programy, następnie robi co do niej należy, i zwraca sterowanie. Kolejne uruchomienie programu już będzie działać normalnie, ponieważ programy są już odsłonięte, wszystko jest załadowane.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;A czas jest zaoszczędzony.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Wstyd i opinie innych</title>
        <published>2025-07-12T12:20:00+00:00</published>
        <updated>2025-07-12T12:20:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-12-wstyd-i-opinie-innych/"/>
        <id>https://mtsz.pl/blog/2025-07-12-wstyd-i-opinie-innych/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-12-wstyd-i-opinie-innych/">&lt;p&gt;Gdy wchodziłem w okres dojrzewania, jedną z rzeczy, które musiałem zacząć robić, było golenie twarzy. Nie był to dla mnie jakiś imponujący rytuał przejścia, raczej higieniczno-estetyczna konieczność. Ponieważ miałem wtedy może 13 lat, nie kupowałem sobie swoich własnych maszynek do golenia, tylko brałem losową maszynkę jednorazową z łazienki rodziców. Za którymś razem wylosowała się różowa, więc taką wziąłem i taką się goliłem. Jakiś czas później fakt używania przeze mnie różowej maszynki do golenia został zauważony przez jednego z moich kuzynów. Nie omieszkał on wyśmiać mnie z tego powodu, w kontekście homofobicznym&#x2F;antymęskim. Pamiętam, że mocno mnie to wtedy zawstydziło, bo jako 13-latek, no wiadomo, nie mogłem sobie pozwolić na to, żeby być niemęski.&lt;&#x2F;p&gt;
&lt;p&gt;Innym razem, za czasów studenckich, byłem na jakimś kuluarowym spotkaniu z członkami organizacji studenckiej, w której wtedy działałem. Poszliśmy do jakiegoś lokalu z alkoholem, i zamówiłem sobie mojito, bo miałem na nie ochotę. Gdy przyniosłem mojego drinka do stolika, jeden z obecnych tam &quot;kolegów&quot; skomentował moje zamówienie, określając je mianem &quot;babskich drinków&quot;. Mi zrobiło się wtedy bardzo niezręcznie - na tyle niezręcznie, że aż jedna koleżanka zaczęła mnie &quot;bronić&quot;, mówiąc, że przecież mogę pić co chcę. SPOILER ALERT: miała 100% racji.&lt;&#x2F;p&gt;
&lt;p&gt;Bardzo niedawno temu miejsce miała jakaś podobna sytuacja - w tym momencie kompletnie jej nie pamiętam. Przypomniałem sobie te przeszłe wydarzenia z mojego życia, i naszła mnie refleksja. To jest jakiś koszmarny błąd socjalizacji, żeby w młodego człowieka wtłoczyć taką ilość wstydu z powodu tak nic nieznaczących rzeczy. Kolor maszynki nie świadczy o Tobie w najmniejszym możliwym stopniu - a już szczególnie nie świadczy o Twojej orientacji seksualnej - którą możesz mieć taką, jaką chcesz. Tak samo to, jakie lubisz drinki.&lt;&#x2F;p&gt;
&lt;p&gt;Ten temat łączy mi się w głowie z szerszą kwestią przejmowania się opiniami innych. Myślę, że warto świadomie filtrować usłyszane opinie przez kilka filtrów - i to jest coś, czego trzeba się nauczyć. Nagle okaże się, że Twój głupi kuzyn czy inny &quot;kolega&quot; z organizacji&#x2F;pracy&#x2F;szkoły&#x2F;studiów, może sobie mówić co chce&#x2F;komentować jakkolwiek, a Ty nie musisz - naprawdę, NIE MUSISZ - się tym &lt;strong&gt;w ogóle&lt;&#x2F;strong&gt; przejmować. Chciałbym, żeby ktoś mi to powiedział te 20 lat temu.&lt;&#x2F;p&gt;
&lt;p&gt;Lista pytań, przez które warto przefiltrować sobie myślę, że każdą zasłyszaną opinię.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;czy osoba, która wyraża swoją opinię, to ktoś, kogo cenisz&lt;&#x2F;li&gt;
&lt;li&gt;czy oceniasz tę opinię jako rzetelną, szczerą, konstruktywną&lt;&#x2F;li&gt;
&lt;li&gt;czy intencja nie jest jedynie taka, żeby kogoś obrazić&lt;&#x2F;li&gt;
&lt;li&gt;czy w ogóle obchodzi Cię to, co ktoś myśli na dany temat&lt;&#x2F;li&gt;
&lt;li&gt;czy Twój rozmówca w pełni akceptuje to, że możesz mieć inną opinię&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Veldt, czyli trawa</title>
        <published>2025-07-11T23:35:00+00:00</published>
        <updated>2025-07-11T23:35:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-11-veldt-czyli-trawa/"/>
        <id>https://mtsz.pl/blog/2025-07-11-veldt-czyli-trawa/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-11-veldt-czyli-trawa/">&lt;p&gt;Dzisiejszy wpis będzie zbieraniną linków, ale zapisuję sobie to, co przyjdzie mi do głowy, bo może będę chciał kiedyś do tego wrócić.&lt;&#x2F;p&gt;
&lt;p&gt;No więc dawno temu trafiłem na losowe nagranie z lajwa muzyka &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Deadmau5&quot;&gt;deadmau5&lt;&#x2F;a&gt;, który podczas transmisji na żywo odsłuchiwał podesłany mu przez fana wokal do jakiejś jego produkcji:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=iqurYVWg7-g&quot;&gt;deadmau5 discovers Chris James on Twitter for The Veldt March 20, 2012&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wtedy jakoś specjalnie nie przywiązałem do tego uwagi, ale dzisiaj obejrzałem z uwagą. No i okazały się rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;Po pierwsze: inspiracją zarówno do stworzenia przez deadmau5 oryginalnego kawałka, jak i do tekstu piosenki ułożonego przez Chrisa Jamesa (to właśnie ten wokalista), było opowiadanie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_Veldt_(short_story)&quot;&gt;The Veldt&#x2F;The World the Children Made&lt;&#x2F;a&gt;, opisujące historię rodziny mieszkającej w zautomatyzowanym domu, spełniającym wszystkie ich potrzeby. W tymże domu, dwoje dzieci spędza bardzo dużo czasu w czymś, co można nazwać &quot;wirtualem&quot; z serialu &quot;Modyfikowany węgiel&quot; (świetny pierwszy sezon swoją drogą), w którym odtworzyły afrykański stepm, który dosłownie nazywa się &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Veldt&quot;&gt;veldt&lt;&#x2F;a&gt;. Nie będę zdradzał całej fabuły (która jest dosłownie opisana na Wikipedii, więc &lt;strong&gt;OSTROŻNIE&lt;&#x2F;strong&gt;), ale historia jest... niepokojąca.&lt;&#x2F;p&gt;
&lt;p&gt;Do samego utworu muzycznego, stworzono również teledysk, który bezpośrednio nawiązuje do opowieści:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=xvtNS6hbVy4&quot;&gt;deadmau5 feat. Chris James - The Veldt (Official Video)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ot, ciekawy splot wydarzeń.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nawadnianie</title>
        <published>2025-07-05T12:39:00+00:00</published>
        <updated>2025-07-05T12:39:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-05-nawadnianie/"/>
        <id>https://mtsz.pl/blog/2025-07-05-nawadnianie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-05-nawadnianie/">&lt;p&gt;To nie jest reklama.&lt;&#x2F;p&gt;
&lt;p&gt;To jest rozwiązanie problemu, który miałem od bardzo dawna. Bo mimo całej świadomości na temat konieczności picia odpowiedniej ilości płynów, woda po prostu mi nie smakuje. A zanim zorientuję się, że powinienem się napić, jest już za późno - w tym sensie, że boli mnie głowa. Wstyd się przyznać, ale do tej pory problem ten rozwiązywałem za pomocą Pepsi bez cukru - ale tankowanie w siebie kofeiny, kwasu węglowego i kwasu fosforowego to jest średni zamiennik dla wody.&lt;&#x2F;p&gt;
&lt;p&gt;Enter: herbata &quot;parzona&quot; na zimno.&lt;&#x2F;p&gt;
&lt;p&gt;Mam litrowy dzbanek, wypełniam go zimną wodą z kranu, wrzucam trzy torebki, wkładam do lodówki. Za pół godziny mam super smaczny napój, idealny na lato, bo nie taki &quot;gęsty&quot; jak sok, bez cukru, bez kwasu węglowego, bez kwasu fosforowego, bez śmieci. Czyste orzeźwienie, i do tego smaczne. Kupiłem siedem pudełek.&lt;&#x2F;p&gt;
&lt;p&gt;W moim sklepie był &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;loydtea.com&#x2F;herbaty-loyd&#x2F;loyd-ice-tea-cytryna-z-limonka&#x2F;&quot;&gt;Loyd - Cytryna Z Limonką&lt;&#x2F;a&gt;, ciekawe czy inni producenci herbaty mają swoje.&lt;&#x2F;p&gt;
&lt;p&gt;Paczcie skład, zero śmiacia:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Biały kwiat hibiskusa, owoc jabłka, liść mięty spearmint (Mentha spicata) 10%, trawa cytrynowa, skórka cytryny 5%, prażony korzeń cykorii, regulator kwasowości - kwas cytrynowy, liść stewii, aromat naturalny cytryny 2%, aromat naturalny limonki 1%.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-07-05-nawadnianie&#x2F;zimna_herbata.jpeg&quot; alt=&quot;zimna_herbata.jpeg&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Pierwszy self-hosting na poważnie</title>
        <published>2025-07-03T17:04:00+00:00</published>
        <updated>2025-07-03T17:04:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-07-03-pierwszy-self-hosting-na-powaznie/"/>
        <id>https://mtsz.pl/blog/2025-07-03-pierwszy-self-hosting-na-powaznie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-07-03-pierwszy-self-hosting-na-powaznie/">&lt;p&gt;Wczoraj był bardzo ważny dzień. Po raz pierwszy poważnie zabrałem się za temat self-hostingu. Zaczęło się od tego, że strasznie czymś zmęczyła mnie aplikacja &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;netnewswire.com&#x2F;&quot;&gt;NetNewsWire&lt;&#x2F;a&gt;, której do tej pory religijnie używałem do RSSów. W wyniku tego zmęczenia zacząłem szukać alternatywy. Pierwsza iteracja padła na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;freshrss.org&#x2F;&quot;&gt;FreshRSS&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;freshrss-dziala-na-web-hostingu&quot;&gt;FreshRSS działa na web hostingu&lt;&#x2F;h1&gt;
&lt;p&gt;Okazuje się, że &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;FreshRSS&#x2F;FreshRSS&quot;&gt;FreshRSS&lt;&#x2F;a&gt; tak właściwie nie potrzebuje &quot;niczego&quot; - tzn. jest on napisany w PHP, jako bazy danych używa SQLite&#x27;a. I to chyba koniec wymagań. Patrzę na te wymagania i sobie myślę: hmm, przecież mój losowy web hosting w OVH ma te rzeczy - to może tam to wrzucę, i zobaczę, co się stanie? No i wrzuciłem. No i zobaczyłem. Zadziałało!&lt;&#x2F;p&gt;
&lt;p&gt;FreshRSS to w sumie fajna aplikacja. Wygląda nienajgorzej, obsługuje różne wtyczki, pozwala na lepszy lub gorszy web-scrapping. Zainstalowałem bodajże dwie wtyczki: jedną do YouTube&#x27;a, żeby móc puszczać filmy bezpośrednio w feedzie, a drugą do robienia klikalnych linków z linków nieklikalnych. No i bęc - te dwie wtyczki się &quot;nie lubią&quot; - jeśli wtyczka jutubowa &quot;zje&quot; daną pozycję, to już na pewno nie będę miał tam poprawionych linków. A ponieważ byłem rozsierdzony czymś, co zrobił NNW (nadal nie pamiętam czym), to i &quot;freszowi&quot; się oberwało.&lt;&#x2F;p&gt;
&lt;p&gt;No to szukam dalej.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;miniflux-dziala-w-kontenerze&quot;&gt;Miniflux działa w kontenerze&lt;&#x2F;h1&gt;
&lt;p&gt;I znalazłem. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;miniflux.app&#x2F;&quot;&gt;Miniflux&lt;&#x2F;a&gt;. Strona rozkosznie minimalistyczna, dosłownie cały interfejs to sam tekst - uwielbiam. Moją uwagę przykuło słowo &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;miniflux.app&#x2F;opinionated.html&quot;&gt;opinionated&lt;&#x2F;a&gt;. Oho, będzie ciekawie. Przeczytałem i w sumie bardzo mi się podoba takie minimalistyczne podejście. Bardzo odmienne od tego, co widzę ostatnio w pracy, gdzie &lt;code&gt;yarn install&lt;&#x2F;code&gt; kończy się informacją, że zainstalowano kilka &lt;strong&gt;tysięcy&lt;&#x2F;strong&gt; pakietów...&lt;&#x2F;p&gt;
&lt;p&gt;Okej, skoro wiem już co chcę postawić, kolejne pytanie brzmi: jak. Tutaj dylematów nie było za wiele. Do głowy przyszedł mi od razu Docker, chwilę rozważałem Podmana, ale z tego co wiem, różnica na moje potrzeby jest marginalna, wybrałem Dockera. Zresztą, one są między sobą kompatybilne, bo oba implementują &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opencontainers.org&#x2F;&quot;&gt;standard OCI&lt;&#x2F;a&gt;. Więc wszystko jedno.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;otwarte-porty-czy-tunelem-przez-reverse-proxy&quot;&gt;Otwarte porty czy tunelem przez reverse proxy&lt;&#x2F;h1&gt;
&lt;p&gt;Moim pierwotnym pomysłem (z którego zrezygnowałem po 12 godzinach ciągłej pracy - ale jaka fascynująca podróż) było postawienie wszystkiego na swoim własnym serwerze, który zresztą już zakupiłem, i sobie leży na szafce od kilku miesięcy razem z kurzem, który na nim osiadł. Z własnym serwerem sprawa jest taka, że trzeba się do niego dostać z zewnątrz. Można to zrobić na wiele sposobów, ale ja ostatecznie wybierałem między dwoma: jakikolwiek sposób na spięcie domeny z moim adresem IP oraz otwarcie portów na routerze, lub postawienie reverse proxy na VPS i tunelowanie ruchu do serwera.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwsza opcja mimo wszystko wydała mi się zbyt ryzykowna. W mojej głowie wpuszczanie jakiegokolwiek ruchu do mojej sieci przez otwarty port - szczególnie z moim minimalnym doświadczeniem - brzmi jak życzenie sobie choroby przenoszonej drogą płciową. VPS + reverse proxy + tunel brzmiały dużo bardziej bezpiecznie, bo ruch między VPSem a moim komputerem odbywa się na ściśle określonych zasadach, na określonych portach, pod warunkiem, że klient na lokalnym serwerze jest odpalony. Wystarczy zabić jeden proces i znikam przed światem. Całe zło otwartych portów miało się dziać na VPSie i nigdy do mnie nie docierać.&lt;&#x2F;p&gt;
&lt;p&gt;Po chwili poszukiwań stanęło na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fatedier&#x2F;frp&quot;&gt;frp&lt;&#x2F;a&gt; oraz &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;caddyserver&#x2F;caddy&quot;&gt;caddy&lt;&#x2F;a&gt;. Żeby to wszystko zadziałało dokładnie tak, jak ja chciałem, musiałem poświęcieć dosłownie 8 godzin. Ale ostatecznie udało się. Architektura wygląda mniej wiecej tak:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;mam sobie fajnego, taniego VPSa, który ma adres IPv6 i który nie działa nigdzie - nawet u mnie xD&lt;&#x2F;li&gt;
&lt;li&gt;dlatego zaopatrzyłem się w darmową domenę, która pokazuje na IPv4 i używa CloudFlare do przetłumaczenia tego na moje IPv6 - wspaniale&lt;&#x2F;li&gt;
&lt;li&gt;na tymże VPSie ruch wlatuje na jakimś losowym porcie, który następnie przekierowuję od razu w &lt;code&gt;frps&lt;&#x2F;code&gt; na jego własny port danych, dosłownie jeden z dwóch, które mam w ramach mojego konta w adresacji IPv4, więc dogadam się z tym z mojego komputera&lt;&#x2F;li&gt;
&lt;li&gt;w moim domu natomiast siedzi sobie komputer z odpalonym &lt;code&gt;frpc&lt;&#x2F;code&gt;, który łyka to, co dostanie od &lt;code&gt;frps&lt;&#x2F;code&gt;, i dalej pcha to do Caddy&lt;&#x2F;li&gt;
&lt;li&gt;a Caddy już ładnie grzecznie rozdziela ruch na kontenery albo mówi &quot;baju baju&quot;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Uff, zmęczyłem się już pisząc to wszystko, więc na dzisiaj wystarczy. Napomknę tylko, że zainstalowałem Minifluxa, Portainera oraz Jellyfina, i wszystko śmiga pięknie.&lt;&#x2F;p&gt;
&lt;p&gt;Właśnie słucham na telefonie z mojego prywatnego serwera:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;sugarcane&#x2F;bloodgroup-cut-out-your-tongue&quot;&gt;BLOODGROUP - CUT OUT YOUR TONGUE&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Telewizor bez reklam</title>
        <published>2025-06-30T22:57:00+00:00</published>
        <updated>2025-06-30T22:57:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-30-telewizor-bez-reklam/"/>
        <id>https://mtsz.pl/blog/2025-06-30-telewizor-bez-reklam/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-30-telewizor-bez-reklam/">&lt;p&gt;Dzisiaj będzie krótko i zwięźle. Z powodów, których nie jestem w stanie sobie przypomnieć, kupiłem dawno temu telewizor LG z systemem webOS. Znam te wszystkie powody, żeby go nie podłączać do internetu, nie logować się w serwisach, i tak dalej, ale na ten moment nie mam zasobów, żeby kupować kolejny serwer, instalować kolejne oprogramowanie, tylko po to, żeby jak człowiek oglądać jutuba bez reklam, od których dosłownie choruję. Jak się okazuje - nie ma takiej potrzeby!&lt;&#x2F;p&gt;
&lt;p&gt;Jest taki projekt, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.webosbrew.org&#x2F;&quot;&gt;webOS Brew&lt;&#x2F;a&gt;, który pozwala na wgrywanie do telewizora zewnętrznych aplikacji. Można oczywiście bawić się w rootowanie telewizora, ale można też skorzystać z łatwego trybu, jakim jest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.webosbrew.org&#x2F;devmode&#x2F;&quot;&gt;Dev Mode&lt;&#x2F;a&gt;. Klika kliknięć, może dwa restarty telewizora, i można cieszyć się takimi cudami jak &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;repo.webosbrew.org&#x2F;apps&#x2F;youtube.leanback.v4&#x2F;&quot;&gt;Youtube bez reklam&lt;&#x2F;a&gt;. Może kiedyś wgram tam coś więcej i opiszę to dokładniej - na razie cieszę się zdrowiem psychicznym podczas słuchania Lofi Girl na telewizorze.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=jfKfPfyJRdk&quot;&gt;lofi hip hop radio 📚 beats to relax&#x2F;study to&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Proper balance of your loudspeakers</title>
        <published>2025-06-26T02:24:00+00:00</published>
        <updated>2025-06-26T02:24:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-26-proper-balance-of-your-loudspeakers/"/>
        <id>https://mtsz.pl/blog/2025-06-26-proper-balance-of-your-loudspeakers/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-26-proper-balance-of-your-loudspeakers/">&lt;p&gt;&lt;audio controls&gt;&lt;source src=&quot;muzyczka.mp3&quot; &#x2F;&gt;&lt;&#x2F;audio&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;ale-ze-o-co-chodzi&quot;&gt;Ale że o co chodzi?&lt;&#x2F;h1&gt;
&lt;p&gt;Ten wpis powstał, żebym mógł przetestować tag HTML &lt;code&gt;audio&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Działa&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Tytuł wpisu zainspirowany &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ZigagQb_hho#t=50s&quot;&gt;doskonałą muzyką Mentona J. Matthewsa III&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
Muzyczka testowa pochodzi z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=I7vOcJcCSso#t=45s&quot;&gt;tego dzieła&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Tryb skupienia i problem z wersjonowaniem</title>
        <published>2025-06-22T23:08:00+00:00</published>
        <updated>2025-06-22T23:08:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-22-tryb-skupienia-i-problem-z-wersjonowaniem/"/>
        <id>https://mtsz.pl/blog/2025-06-22-tryb-skupienia-i-problem-z-wersjonowaniem/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-22-tryb-skupienia-i-problem-z-wersjonowaniem/">&lt;p&gt;Ciągle ulepszam moją skryptozakładkę do Facebooka, mam już jej trzecią wersję, i pomysły na kolejne piętnaście.&lt;&#x2F;p&gt;
&lt;p&gt;To czego nie mam, to koncepcji sensownego jej wersjonowania - i w ogóle całego kodu na stronie. Teoretycznie mogę wrzucać każdą wersję jako osobny plik, bo każdy wpis i tak żyje w swoim własnym folderze, ale jeszcze nie pogodziłem się z tym pomysłem, bo bardzo lubię Gita. Ale stawianie repo kłóci się z moim podejściem upraszczania do granic możliwości. No i czymże jest Git, jeśli po prostu nie kolejnymi kopiami tego samego zaczarowanymi w skomplikowane komendy? Na razie wrzucam jako osobny plik.&lt;&#x2F;p&gt;
&lt;p&gt;Dodałem &quot;tryb skupienia&quot; dla pojedynczego posta. Żeby dobrze działało, to post trzeba otworzyć w osobnej zakładce, bo skrypt dosłownie wyszukuje nagłówka postu, a następnie wychodzi trzynaście &lt;code&gt;div&lt;&#x2F;code&gt;ów do góry i robi czary za pomocą stylu CSS &lt;code&gt;visibility&lt;&#x2F;code&gt;. Oraz przyciski do rozwijania komentarzy są od teraz klikane dopiero wtedy, gdy pojawią się na ekranie. I są zaznaczane na czerwono, żeby było widoczne, co się klika.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;javascript: (function () {
  const PANEL_ID = &amp;quot;control-panel&amp;quot;;
  const FOCUS_LEVEL = 13;
  const FOCUS_MODE_STYLES = `
    &amp;lt;style id=&amp;quot;focus-mode-styles&amp;quot;&amp;gt;
      .focus-hidden { visibility: hidden !important; }
      .focus-visible { visibility: visible !important; }
    &amp;lt;&#x2F;style&amp;gt;
  `;
  const COMMENT_BUTTON_PATTERNS = [
    &#x2F;Wyświetl wszystkie.*odpowiedzi&#x2F;,
    &#x2F;Wyświetl więcej&#x2F;,
    &#x2F;Pokaż więcej odpowiedzi&#x2F;,
    &#x2F;Wyświetl 1 odpowiedź&#x2F;,
    &#x2F;odpowiedzia(ł|ła|\(a\))&#x2F;,
  ];

  &#x2F;* if panel already exists, do nothing *&#x2F;
  if (document.getElementById(PANEL_ID)) return;

  let domWatcher = null;
  let visibilityObserver = null;
  let dragOffset = null;
  let clickedButtonsCount = 0;
  let focusEnabled = false;

  &#x2F;* add focus mode CSS styles *&#x2F;
  document.head.insertAdjacentHTML(&amp;quot;beforeend&amp;quot;, FOCUS_MODE_STYLES);

  &#x2F;* build and display control panel *&#x2F;
  const panel = createPanel();
  const title = panel.querySelector(&amp;quot;#panel-title&amp;quot;);
  const commentButton = panel.querySelector(&amp;quot;#comment-button&amp;quot;);
  const counterDisplay = panel.querySelector(&amp;quot;#counter-display&amp;quot;);
  const focusModeButton = panel.querySelector(&amp;quot;#focus-mode-button&amp;quot;);
  const closeButton = panel.querySelector(&amp;quot;#close-button&amp;quot;);
  document.body.appendChild(panel);

  &#x2F;* event handlers *&#x2F;
  title.onmousedown = (e) =&amp;gt; startDragging(e);
  document.onmousemove = (e) =&amp;gt; dragPanel(e);
  document.onmouseup = () =&amp;gt; stopDragging();
  commentButton.onclick = () =&amp;gt; (visibilityObserver ? stopWatching() : startWatching());
  focusModeButton.onclick = () =&amp;gt; (focusEnabled ? deactivateFocusMode() : activateFocusMode());
  closeButton.onclick = closePanel;

  &#x2F;* === MAIN FUNCTIONS === *&#x2F;

  function startWatching() {
    updateButton(commentButton, &amp;quot;Wyłącz rozwijanie komentarzy&amp;quot;, &amp;quot;crimson&amp;quot;);
    visibilityObserver = new IntersectionObserver((entries) =&amp;gt; clickIntersectingEntries(entries));
    observeNode(document.body, visibilityObserver);
    domWatcher = new MutationObserver((m) =&amp;gt; observeMutations(m, visibilityObserver));
    domWatcher.observe(document.body, { childList: true, subtree: true });
  }

  function stopWatching() {
    updateButton(commentButton, &amp;quot;Włącz rozwijanie komentarzy&amp;quot;);
    if (visibilityObserver) {
      visibilityObserver.disconnect();
      visibilityObserver = null;
    }
    if (domWatcher) {
      domWatcher.disconnect();
      domWatcher = null;
    }
  }

  function activateFocusMode() {
    const postContainer = findPostContainer();
    if (!postContainer) {
      alert(&amp;quot;Nie udało się znaleźć kontenera posta&amp;quot;);
      return;
    }
    updateButton(focusModeButton, &amp;quot;Wyłącz tryb skupienia&amp;quot;, &amp;quot;darkorange&amp;quot;);
    focusEnabled = true;
    document.body.classList.add(&amp;quot;focus-hidden&amp;quot;);
    panel.classList.add(&amp;quot;focus-visible&amp;quot;);
    postContainer.classList.add(&amp;quot;focus-visible&amp;quot;);
  }

  function deactivateFocusMode() {
    updateButton(focusModeButton, &amp;quot;Włącz tryb skupienia&amp;quot;);
    focusEnabled = false;
    const focusElements = document.querySelectorAll(&amp;quot;.focus-hidden, .focus-visible&amp;quot;);
    focusElements.forEach((e) =&amp;gt; e.classList.remove(&amp;quot;focus-hidden&amp;quot;, &amp;quot;focus-visible&amp;quot;));
  }

  function clickButton(button) {
    const textElements = [button, ...button.querySelectorAll(&amp;quot;*&amp;quot;)];
    setElementColors(textElements, &amp;quot;red&amp;quot;);
    setTimeout(() =&amp;gt; {
      button.click();
      clickedButtonsCount++;
      updateCounterDisplay();
    }, 500);
  }

  &#x2F;* === OBSERVER FUNCTIONS === *&#x2F;

  function observeMutations(mutations, visibilityObserver) {
    mutations.forEach((m) =&amp;gt; {
      m.addedNodes.forEach((n) =&amp;gt; observeNode(n, visibilityObserver));
      m.removedNodes.forEach((n) =&amp;gt; unobserveNode(n, visibilityObserver));
    });
  }

  function clickIntersectingEntries(entries) {
    entries.filter((e) =&amp;gt; e.isIntersecting).forEach((e) =&amp;gt; clickButton(e.target));
  }

  function observeNode(node, visibilityObserver) {
    const buttons = findMatchingButtons(node);
    buttons.forEach((b) =&amp;gt; visibilityObserver.observe(b));
  }

  function unobserveNode(node, visibilityObserver) {
    const buttons = findMatchingButtons(node);
    buttons.forEach((b) =&amp;gt; visibilityObserver.unobserve(b));
  }

  &#x2F;* === UTILITIES === *&#x2F;

  function findPostContainer() {
    const headers = document.querySelectorAll(&amp;quot;h2 span&amp;quot;);
    const header = Array.from(headers).find((header) =&amp;gt; &#x2F;^Post &#x2F;.test(header.textContent));
    if (!header) return;

    let container = header;
    for (let i = 0; i &amp;lt; FOCUS_LEVEL; i++) {
      container = container.parentElement;
      if (!container) return;
    }
    return container;
  }

  function isMatchingButton(element) {
    return (
      element.nodeType === Node.ELEMENT_NODE &amp;amp;&amp;amp;
      element.getAttribute?.(&amp;quot;role&amp;quot;) === &amp;quot;button&amp;quot; &amp;amp;&amp;amp;
      COMMENT_BUTTON_PATTERNS.some((pattern) =&amp;gt; pattern.test(element.textContent))
    );
  }

  function findMatchingButtons(node) {
    if (node.nodeType !== Node.ELEMENT_NODE) return [];
    const matchingButtons = [];
    if (isMatchingButton(node)) matchingButtons.push(node);
    const descendantButtons = Array.from(node.querySelectorAll(&amp;#39;div[role=&amp;quot;button&amp;quot;]&amp;#39;)).filter(
      isMatchingButton
    );
    matchingButtons.push(...descendantButtons);
    return matchingButtons;
  }

  &#x2F;* === PANEL CONTROL FUNCTIONS === *&#x2F;

  function closePanel() {
    stopWatching();
    document.onmousemove = document.onmouseup = null;
    panel.remove();
  }

  function startDragging(event) {
    if (event.button !== 0) return; &#x2F;* left click only *&#x2F;
    dragOffset = {
      x: event.clientX - panel.offsetLeft,
      y: event.clientY - panel.offsetTop,
    };
  }

  function dragPanel(event) {
    if (!dragOffset) return;
    panel.style.left = `${event.clientX - dragOffset.x}px`;
    panel.style.top = `${event.clientY - dragOffset.y}px`;
  }

  function stopDragging() {
    dragOffset = null;
  }

  &#x2F;* === UI FUNCTIONS === *&#x2F;

  function createPanel() {
    const panelHTML = `
      &amp;lt;div id=&amp;quot;${PANEL_ID}&amp;quot; style=&amp;quot;
        position: fixed;
        top: 100px;
        left: 100px;
        background: #fff;
        border: 1px solid #000;
        padding: 8px;
        z-index: 999999;
        display: grid;
        gap: 5px;
      &amp;quot;&amp;gt;
        &amp;lt;h1 id=&amp;quot;panel-title&amp;quot; style=&amp;quot;cursor: move; text-align: center;&amp;quot;&amp;gt;Asystent FB&amp;lt;&#x2F;h1&amp;gt;
        &amp;lt;button id=&amp;quot;comment-button&amp;quot; style=&amp;quot;cursor: pointer;&amp;quot;&amp;gt;Włącz rozwijanie komentarzy&amp;lt;&#x2F;button&amp;gt;
        &amp;lt;span id=&amp;quot;counter-display&amp;quot;&amp;gt;Kliknięte przyciski: 0&amp;lt;&#x2F;span&amp;gt;
        &amp;lt;button id=&amp;quot;focus-mode-button&amp;quot; style=&amp;quot;cursor: pointer;&amp;quot;&amp;gt;Włącz tryb skupienia&amp;lt;&#x2F;button&amp;gt;
        &amp;lt;button id=&amp;quot;close-button&amp;quot; style=&amp;quot;cursor: pointer;&amp;quot;&amp;gt;Zamknij&amp;lt;&#x2F;button&amp;gt;
      &amp;lt;&#x2F;div&amp;gt;
    `;

    const tempDiv = document.createElement(&amp;quot;div&amp;quot;);
    tempDiv.innerHTML = panelHTML;
    return tempDiv.firstElementChild;
  }

  function updateButton(button, text, color) {
    button.textContent = text;
    button.style.backgroundColor = color ?? &amp;quot;black&amp;quot;;
  }

  function updateCounterDisplay() {
    counterDisplay.textContent = `Kliknięte przyciski: ${clickedButtonsCount}`;
  }

  function setElementColors(elements, color) {
    elements.forEach((e) =&amp;gt; e.style.setProperty(&amp;quot;color&amp;quot;, color, &amp;quot;important&amp;quot;));
  }
})();
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;PS: odkrycie dnia - kod skryptozakładki można pobierać dynamicznie z lokalne serwera, a samą ją odpalać taki prostym snippetem! Moje życie po raz kolejny stało się prostsze.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;javascript: (function () {
  var s = document.createElement(&amp;quot;script&amp;quot;);
  s.src = &amp;quot;http:&#x2F;&#x2F;localhost:1111&#x2F;script.js&amp;quot;;
  document.body.appendChild(s);
})();
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Poczytaj mi ejaju</title>
        <published>2025-06-19T21:55:00+00:00</published>
        <updated>2025-06-19T21:55:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-19-poczytaj-mi-ejaju/"/>
        <id>https://mtsz.pl/blog/2025-06-19-poczytaj-mi-ejaju/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-19-poczytaj-mi-ejaju/">&lt;p&gt;Dzisiaj jest jakieś święto, i jest dzień wolny od pracy, więc więc zamiast programować dla prywaciarza za psie pieniądze, programuję dla zabawy za darmo. A jest z czego się cieszyć! Pierwsze dzieło to&lt;&#x2F;p&gt;
&lt;h1 id=&quot;skrypt-do-wgrywania-tej-wlasnie-strony&quot;&gt;Skrypt do wgrywania tej właśnie strony&lt;&#x2F;h1&gt;
&lt;p&gt;Od teraz zamiast:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;pisać w Terminalu komendę do budowania strony &lt;code&gt;zola build&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;odpalać graficznego klienta FTP (Cyberduck)&lt;&#x2F;li&gt;
&lt;li&gt;otwierać folder, do którego zbudowała się strona&lt;&#x2F;li&gt;
&lt;li&gt;zaznaczać i przeciągać pliki strony do klienta FTP&lt;&#x2F;li&gt;
&lt;li&gt;potwierdzać że tak, chcę nadpisać wszystko&lt;&#x2F;li&gt;
&lt;li&gt;czekać, aż pasek postępu się wypełni, po to, żeby zamknąć klienta FTP&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;wystarczy w Terminalu wpisać ✨✨✨ &lt;code&gt;.&#x2F;deplojuj.sh&lt;&#x2F;code&gt; ✨✨✨ i się deplojuje.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;#!&#x2F;bin&#x2F;bash

REMOTE_USER=&amp;quot;user&amp;quot;
REMOTE_HOST=&amp;quot;ftp.domain.com&amp;quot;
REMOTE_PATH=&amp;quot;blog&amp;quot;
LOCAL_BUILD_DIR=&amp;quot;public&amp;quot;

# Check if .netrc exists
if [ ! -f ~&#x2F;.netrc ]; then
    echo &amp;quot;Error: ~&#x2F;.netrc file not found!&amp;quot;
    echo &amp;quot;Please create ~&#x2F;.netrc with the following format:&amp;quot;
    echo &amp;quot;machine $REMOTE_HOST login $REMOTE_USER password YOUR_PASSWORD&amp;quot;
    echo &amp;quot;Make sure to set proper permissions: chmod 600 ~&#x2F;.netrc&amp;quot;
    exit 1
fi

# Build the site
echo &amp;quot;Building the site...&amp;quot;
zola build --output-dir $LOCAL_BUILD_DIR

# Check if local build directory exists
if [ ! -d &amp;quot;$LOCAL_BUILD_DIR&amp;quot; ]; then
    echo &amp;quot;Error: Local build directory &amp;#39;$LOCAL_BUILD_DIR&amp;#39; not found!&amp;quot;
    exit 1
fi

echo &amp;quot;Deploying from &amp;#39;$LOCAL_BUILD_DIR&amp;#39; to &amp;#39;$REMOTE_HOST:$REMOTE_PATH&amp;#39;...&amp;quot;

# Use lftp to sync files
lftp &amp;lt;&amp;lt; EOF
open sftp:&#x2F;&#x2F;$REMOTE_USER@$REMOTE_HOST
mirror -R --delete $LOCAL_BUILD_DIR $REMOTE_PATH
quit
EOF

if [ $? -eq 0 ]; then
    echo &amp;quot;Deployment completed successfully!&amp;quot;
else
    echo &amp;quot;Deployment failed!&amp;quot;
    exit 1
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oczywiście nie jest to nic wielkiego, ale dawno temu usłyszałem gdzieś (chyba od CGP Grey&#x27;a), że takie najmniejsze optymalizacje mają największy wpływ na samopoczucie. To szło jakoś tak, że człowiek nie rejestruje ich na świadomym poziomie, ale podskórnie nadal to &quot;irytuje&quot; układ nerwowy, i zredukowanie tego &quot;swędzenia&quot;, chociaż tak samo niekoniecznie rejestrowalne na poziomie świadomości, poprawia samopoczucie, sprawia, że ptaki piękniej śpiewają, chmury są mniej szare, a ludzie mniej irytujący. I nawet jeśli sobie to wszystko wymyśliłem i wmówiłem, to i tak stwierdzam, że ptaki faktycznie piękniej śpiewają odkąd napisałem ten skrypt.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;zola-dogaduje-sie-z-obsidianem&quot;&gt;Zola dogaduje się z Obsidianem&lt;&#x2F;h1&gt;
&lt;p&gt;Udało mi się też ogarnąć kwestię wyświetlania obrazków i generalnie assetów zarówno w Zoli, jak i w Obsidianie. Do tej pory wszystko obrazki czy fragmenty kodu umieszczałem w osobnym folderze o nazwie &lt;code&gt;assets&lt;&#x2F;code&gt;, i żeby obrazki poprawnie wyświetlały się na stronie, ich ścieżka musiała być dosłownie kosmiczna, coś w stylu &lt;code&gt;..&#x2F;..&#x2F;assets&#x2F;images&#x2F;kotek.png&lt;&#x2F;code&gt;. Tego koszmaru oczywiście nie mógł znieść Obsidian, więc wyświetlał błąd zamiast obrazka. A ponieważ te posty piszę często w Obsidianie, to musiałem to naprawić. No i się udało. Zola wspiera coś, co nazywa się &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;content&#x2F;overview&#x2F;#asset-colocation&quot;&gt;asset colocation&lt;&#x2F;a&gt;, czyli że można sobie wszystkie pliki towarzyszące stronie wrzucić do tego samego fodleru, i podawać po prostu lokalnie ścieżki typu &lt;code&gt;![tu ma być kotek](kotek.png)&lt;&#x2F;code&gt;. No działa ślicznie.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;moglem-przeczytac-w-15-minut-ale-napisalem-program-w-8-godzin&quot;&gt;Mogłem przeczytać w 15 minut, ale napisałem program w 8 godzin&lt;&#x2F;h1&gt;
&lt;p&gt;Większość dzisiejszego dnia spędziłem na tworzeniu skryptu w Pythonie, który dowolny plik Markdown (to są jakieś inne?)... syntezuje? W sensie robi syntezę mowy. Zaczęło się od tego, że był jakiś strasznie długi artykuł, którego nie chciało mi się czytać. Przypomniałem sobie, że jest coś takiego jak Whisper, który robi tekst z nagrań, ale może w drugą stronę też działa? Trochę grzebania po internecie, i znalazłem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;reddit.com&#x2F;r&#x2F;LocalLLaMA&#x2F;comments&#x2F;1f0awd6&#x2F;best_local_open_source_texttospeech_and&#x2F;&quot;&gt;najpierw ten wątek na Reddicie&lt;&#x2F;a&gt;,  potem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;TextToSpeech&#x2F;comments&#x2F;1ijmbbs&#x2F;kokoro82m_is_very_impressive_and_is_super_fast_on&#x2F;&quot;&gt;inny wątek na Reddicie&lt;&#x2F;a&gt;, potem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jashdubal&#x2F;offline-transcription&quot;&gt;to repozytorium na GitHubie&lt;&#x2F;a&gt; i zainspirowany tym wszystkim, napisałem swoją wariację na temat przetwarzania tekstu na mowę.&lt;&#x2F;p&gt;
&lt;p&gt;Kilka ciekawostek dla znawców Pythona (którym sam raczej nie jestem). Pierwsza sprawa to to, ze jakieś 20% czasu spędziłem na walce z typami, bo jako programista statycznie typowanego Swifta, moja dusza cierpiała od samego patrzenia na kod bez adnotacji typów. Ostatecznie poległem. To była uczciwa walka i zostałem pokonany. Druga sprawa to to, że skrypt do działania wymaga instalacji zależności, a jak zależności, to wiadomo, że &lt;code&gt;venv&lt;&#x2F;code&gt;. No i pierwsza edycja tego mojego pisania składała się ze skryptu &lt;code&gt;bash&lt;&#x2F;code&gt;, który tego &lt;code&gt;venv&lt;&#x2F;code&gt;a zestawiał, instalował zależności i odpalał co trzeba. Ale okazuje się, że Python - czy może precyzyjniej skrypt w Pythonie - może sobie swoje środowisko sam stworzyć, zainstalować zależności, a potem się w nim uruchomić! Ja wiem, że to jest komputer, i on robi to, co programista nakazał, ale muszę się przespać z tą rewelacją.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, moje dzieło można podziwiać poniżej.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;python&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3.12
import argparse
import os
import re
import subprocess
import sys
import venv
import warnings
from datetime import datetime
from pathlib import Path

AUDIO_EXT = &amp;#39;.wav&amp;#39;
DEFAULT_VOICE = &amp;#39;af_heart&amp;#39;
VENV_DIR = Path(__file__).parent &#x2F; &amp;quot;.kokoro-venv&amp;quot;
PACKAGES = [&amp;quot;kokoro&amp;gt;=0.9.4&amp;quot;, &amp;quot;soundfile&amp;quot;]

&amp;quot;&amp;quot;&amp;quot;
CLI tool for offline text-to-speech synthesis using Kokoro-82M.
Usage: python3.12 tts.py -f example.md -v af_nicole
&amp;quot;&amp;quot;&amp;quot;

pipeline = None


def ensure_venv():
    if sys.prefix != sys.base_prefix:
        return

    if not VENV_DIR.exists():
        print(&amp;quot;📦 Setting up virtual environment...&amp;quot;)
        venv.create(VENV_DIR, with_pip=True)
        bin_dir = &amp;quot;Scripts&amp;quot; if os.name == &amp;quot;nt&amp;quot; else &amp;quot;bin&amp;quot;
        pip_exe = VENV_DIR &#x2F; bin_dir &#x2F; &amp;quot;pip&amp;quot;
        subprocess.check_call([str(pip_exe), &amp;quot;install&amp;quot;, *PACKAGES])

    print(&amp;quot;🔄 Switching to virtual environment...&amp;quot;)
    python_exe = VENV_DIR &#x2F; (&amp;quot;Scripts&amp;quot; if os.name == &amp;quot;nt&amp;quot; else &amp;quot;bin&amp;quot;) &#x2F; &amp;quot;python&amp;quot;
    result = subprocess.run([str(python_exe)] + sys.argv)
    sys.exit(result.returncode)


def get_pipeline():
    global pipeline
    if pipeline is not None:
        return pipeline

    ensure_venv()
    print(&amp;quot;🤖 Initializing TTS pipeline...&amp;quot;)
    with warnings.catch_warnings():
        warnings.simplefilter(&amp;quot;ignore&amp;quot;)
        from kokoro import KPipeline # type: ignore
        pipeline = KPipeline(lang_code=&amp;#39;a&amp;#39;, repo_id=&amp;#39;hexgrad&#x2F;Kokoro-82M&amp;#39;)
    return pipeline


def text_to_audio(text, voice, speed, output_path=None):
    print(&amp;quot;🎯 Converting text to audio...&amp;quot;)

    # Generate audio segments
    segments = [s.strip() for s in re.split(r&amp;#39;\n+&amp;#39;, text.strip()) if s.strip()]
    generator = get_pipeline()(text, voice=voice, speed=speed, split_pattern=r&amp;#39;\n+&amp;#39;)

    audio_data = []
    total_segments = len(segments)
    for i, (_, _, audio) in enumerate(generator):
        current = i + 1
        percent = int(current &#x2F; total_segments * 100)
        print(f&amp;quot;\r⏳ Processing: {percent}% ({current}&#x2F;{total_segments})&amp;quot;, end=&amp;#39;&amp;#39;, flush=True)
        audio_data.extend(audio)
    print()

    # Save audio
    if output_path is None:
        output_path = datetime.now().strftime(&amp;#39;%y-%m-%d-%H-%M-%S&amp;#39; + AUDIO_EXT)
    elif not output_path.endswith(AUDIO_EXT):
        output_path += AUDIO_EXT

    print(&amp;quot;💾 Writing audio file...&amp;quot;)
    import soundfile # type: ignore
    soundfile.write(output_path, audio_data, 24000)
    return output_path


def process_file(filepath, voice, speed, output_path=None):
    print(f&amp;quot;📄 Processing: {filepath}&amp;quot;)
    with open(filepath, &amp;#39;r&amp;#39;) as f:
        text = f.read()

    if output_path is None:
        output_path = f&amp;quot;{Path(filepath).stem}{AUDIO_EXT}&amp;quot;

    return text_to_audio(text, voice, speed, output_path)


def process_batch(voice, speed):
    print(&amp;quot;📚 Batch processing...&amp;quot;)
    for md_file in Path(&amp;#39;.&amp;#39;).glob(&amp;#39;*.md&amp;#39;):
        wav_file = md_file.with_suffix(AUDIO_EXT)
        if wav_file.exists():
            print(f&amp;quot;⏭️  Skipping {md_file} (already exists)&amp;quot;)
            continue
        process_file(str(md_file), voice, speed)


def main():
    parser = argparse.ArgumentParser(description=&amp;quot;CLI tool for offline text-to-speech synthesis.&amp;quot;)
    parser.add_argument(&amp;#39;text&amp;#39;, nargs=&amp;#39;?&amp;#39;, help=&amp;quot;Text to synthesize&amp;quot;)
    parser.add_argument(&amp;#39;-f&amp;#39;, &amp;#39;--file&amp;#39;, help=&amp;quot;File to process&amp;quot;)
    parser.add_argument(&amp;#39;-v&amp;#39;, &amp;#39;--voice&amp;#39;, default=DEFAULT_VOICE, help=f&amp;quot;Voice (default: {DEFAULT_VOICE})&amp;quot;)
    parser.add_argument(&amp;#39;-s&amp;#39;, &amp;#39;--speed&amp;#39;, type=float, default=1.0, help=&amp;quot;Speech speed&amp;quot;)
    parser.add_argument(&amp;#39;-o&amp;#39;, &amp;#39;--output&amp;#39;, help=&amp;quot;Output filename&amp;quot;)
    parser.add_argument(&amp;#39;--batch&amp;#39;, action=&amp;#39;store_true&amp;#39;, help=&amp;quot;Process all .md files&amp;quot;)

    args = parser.parse_args()

    if not (args.text or args.file or args.batch):
        parser.print_help()
        sys.exit(1)

    print(&amp;quot;🚀 Starting TTS...&amp;quot;)

    if args.batch:
        process_batch(args.voice, args.speed)
    elif args.file:
        process_file(args.file, args.voice, args.speed, args.output)
    elif args.text:
        text_to_audio(args.text, args.voice, args.speed, args.output)

    print(&amp;quot;🎉 Done!&amp;quot;)


if __name__ == &amp;quot;__main__&amp;quot;:
    main()
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Klasycznie, do programowania został użyty Cursor, model Claude 4 Sonnet, oraz następująca piosenka&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=dHW1y-2YBlE&quot;&gt;YOUNG GALAXY - Cover Your Tracks&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Skryptozakładki a as podstawowe prawo człowieka</title>
        <published>2025-06-18T10:17:00+00:00</published>
        <updated>2025-06-18T10:17:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-18-skryptozakladki-a-as-podstawowe-prawo-czlowieka/"/>
        <id>https://mtsz.pl/blog/2025-06-18-skryptozakladki-a-as-podstawowe-prawo-czlowieka/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-18-skryptozakladki-a-as-podstawowe-prawo-czlowieka/">&lt;p&gt;Odkąd napisałem skryptozakładki do Facebooka oraz ING, nie mogę przestać o nich myśleć. To, że ułatwiają mi życie, to jedno - ale teraz okazuje się, że one dają dużo większe możliwości, niż mi się na początku wydawało.&lt;&#x2F;p&gt;
&lt;p&gt;Mam taki pomysł, żeby napisać sobie szkielet skryptozakładki, która dodaje do treści strony swobodnie latające okienko. Takie okienko będzie można przesuwać w dowolne miejsce na stronie. Będzie też przycisk &quot;Zamknij&quot;, który usunie okienko całkowicie. Pozostała część okienka będzie do dyspozycji właściwej funkcji. Dzięki temu będzie można rozszerzyć dosłownie każdą jedną stronę internetową o dosłownie każdy mechanizm, jaki się tylko zamarzy, i to jednym kliknięciem zakładki.&lt;&#x2F;p&gt;
&lt;p&gt;Do pracy nad pomysłem użyję kodu skryptozakładki Facebookowej z poprzedniego wpisu, bo wiem jak działa, a dzięki temu mechanizmowi może uda mi się poprawić jej użyteczność.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;jak-to-dziala&quot;&gt;Jak to działa&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;poniższy kod wklejasz na stronę &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.minifier.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.minifier.org&#x2F;&lt;&#x2F;a&gt; i minimalizujesz&lt;&#x2F;li&gt;
&lt;li&gt;w przeglądarce tworzysz nową zakładkę, nazywasz ją jak chcesz, a w pole &quot;adres&quot; wklejasz zminimalizowany kod&lt;&#x2F;li&gt;
&lt;li&gt;wchodzisz na fejsa na dowolny post z miliardem komentarzy, i potem odpalasz zakładkę&lt;&#x2F;li&gt;
&lt;li&gt;profit&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;javascript: (function () {
  const PANEL_ID = &amp;quot;fb-control-panel&amp;quot;;
  const BUTTON_TEXT_PATTERNS = [
    &#x2F;Wyświetl wszystkie.*odpowiedzi&#x2F;,
    &#x2F;Wyświetl więcej&#x2F;,
    &#x2F;Pokaż więcej odpowiedzi&#x2F;,
    &#x2F;Wyświetl 1 odpowiedź&#x2F;,
  ];

  &#x2F;&#x2F; Check if panel already exists - if so, do nothing
  if (document.getElementById(PANEL_ID)) return;

  &#x2F;&#x2F; Create and setup UI
  const panel = createPanel();
  const title = createTitle();
  const toggleButton = createToggleButton();
  const closeButton = createCloseButton();
  panel.append(title, toggleButton, closeButton);
  document.body.appendChild(panel);

  &#x2F;&#x2F; State
  let buttonWatcher = null;
  let offsetX = 0;
  let offsetY = 0;
  let isDragging = false;

  &#x2F;&#x2F; Event listeners
  toggleButton.addEventListener(&amp;quot;click&amp;quot;, handleToggleClick);
  closeButton.addEventListener(&amp;quot;click&amp;quot;, handleCloseClick);
  title.addEventListener(&amp;quot;mousedown&amp;quot;, handleMouseDown);
  document.addEventListener(&amp;quot;mousemove&amp;quot;, handleMouseMove);
  document.addEventListener(&amp;quot;mouseup&amp;quot;, handleMouseUp);

  &#x2F;&#x2F; === EVENT HANDLERS ===
  function handleToggleClick() {
    buttonWatcher ? stopAutoClicker() : startAutoClicker();
  }

  function handleCloseClick() {
    stopAutoClicker();
    document.removeEventListener(&amp;quot;mousemove&amp;quot;, handleMouseMove);
    document.removeEventListener(&amp;quot;mouseup&amp;quot;, handleMouseUp);
    panel.remove();
  }

  function handleMouseDown(event) {
    isDragging = true;
    offsetX = event.clientX - panel.offsetLeft;
    offsetY = event.clientY - panel.offsetTop;
  }

  function handleMouseMove(event) {
    if (isDragging) {
      panel.style.left = `${event.clientX - offsetX}px`;
      panel.style.top = `${event.clientY - offsetY}px`;
    }
  }

  function handleMouseUp() {
    isDragging = false;
  }

  &#x2F;&#x2F; === AUTO-CLICKER FUNCTIONS ===
  function startAutoClicker() {
    updateButton(&amp;quot;Stop Auto-Clicker&amp;quot;, &amp;quot;crimson&amp;quot;);

    &#x2F;&#x2F; Click existing buttons
    clickButtonsInNode(document.body);

    &#x2F;&#x2F; Watch for new buttons
    buttonWatcher = new MutationObserver((mutations) =&amp;gt; {
      if (buttonWatcher) {
        mutations.forEach((mutation) =&amp;gt;
          mutation.addedNodes.forEach(clickButtonsInNode)
        );
      }
    });
    buttonWatcher.observe(document.body, { childList: true, subtree: true });
  }

  function clickButtonsInNode(node) {
    Array.from(node.querySelectorAll(&amp;#39;div[role=&amp;quot;button&amp;quot;]&amp;#39;))
      .filter((button) =&amp;gt;
        BUTTON_TEXT_PATTERNS.some((pattern) =&amp;gt; pattern.test(button.textContent))
      )
      .forEach((button, index) =&amp;gt; {
        safeClickWithDelay(button, index * 200);
      });
  }

  function stopAutoClicker() {
    updateButton(&amp;quot;Start Auto-Clicker&amp;quot;, &amp;quot;forestgreen&amp;quot;);
    if (buttonWatcher) {
      buttonWatcher.disconnect();
      buttonWatcher = null;
    }
  }

  function updateButton(text, color) {
    toggleButton.textContent = text;
    toggleButton.style.backgroundColor = color;
  }

  function safeClickWithDelay(button, delay) {
    setTimeout(() =&amp;gt; {
      try {
        button.click();
      } catch (error) {
        console.error(&amp;quot;Failed to click button:&amp;quot;, error);
      }
    }, delay);
  }

  &#x2F;&#x2F; === UI CREATION ===
  function createPanel() {
    const panel = document.createElement(&amp;quot;div&amp;quot;);
    Object.assign(panel.style, {
      position: &amp;quot;fixed&amp;quot;,
      top: &amp;quot;100px&amp;quot;,
      left: &amp;quot;100px&amp;quot;,
      background: &amp;quot;#fff&amp;quot;,
      border: &amp;quot;2px solid #000&amp;quot;,
      padding: &amp;quot;15px&amp;quot;,
      zIndex: &amp;quot;999999&amp;quot;,
      display: &amp;quot;grid&amp;quot;,
      gap: &amp;quot;10px&amp;quot;,
    });
    panel.id = PANEL_ID;
    return panel;
  }

  function createTitle() {
    const title = document.createElement(&amp;quot;h1&amp;quot;);
    title.textContent = &amp;quot;Facebook Auto-Clicker&amp;quot;;
    Object.assign(title.style, {
      cursor: &amp;quot;move&amp;quot;,
      userSelect: &amp;quot;none&amp;quot;,
      margin: &amp;quot;0&amp;quot;,
    });
    return title;
  }

  function createToggleButton() {
    const button = document.createElement(&amp;quot;button&amp;quot;);
    button.textContent = &amp;quot;Start Auto-Clicker&amp;quot;;
    button.style.cursor = &amp;quot;pointer&amp;quot;;
    button.id = &amp;quot;fb-toggle-btn&amp;quot;;
    return button;
  }

  function createCloseButton() {
    const button = document.createElement(&amp;quot;button&amp;quot;);
    button.textContent = &amp;quot;Close&amp;quot;;
    button.style.cursor = &amp;quot;pointer&amp;quot;;
    button.id = &amp;quot;fb-close-btn&amp;quot;;
    return button;
  }
})();
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;muzyczka-do-programowania&quot;&gt;Muzyczka do programowania&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=iMFrODwRyZo&quot;&gt;Gusgus - Breaking Down (Official Video)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nieskończone komentarze</title>
        <published>2025-06-09T20:04:00+00:00</published>
        <updated>2025-06-09T20:04:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-06-09-nieskonczone-komentarze/"/>
        <id>https://mtsz.pl/blog/2025-06-09-nieskonczone-komentarze/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-06-09-nieskonczone-komentarze/">&lt;h1 id=&quot;motywacja&quot;&gt;Motywacja&lt;&#x2F;h1&gt;
&lt;p&gt;Oglądam właśnie WWDC 2025 - konferencję Apple&#x27;a na temat ich nowego oprogramowania. Całkiem niezłe rzeczy dodali, np. dostęp do lokalnego modelu językowego. Zmienili też radykalnie interfejs wszystkiego na Liquid Glass, który wygląda jak Windows Vista (to synonim do &quot;wygląda okropnie&quot;). Ale nie o tym dzisiaj.&lt;&#x2F;p&gt;
&lt;p&gt;Dzisiaj miejsce miała też &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;schmorgpl&#x2F;videos&#x2F;2867935586726166&quot;&gt;premiera&lt;&#x2F;a&gt; raportu stworzonego przez &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;schm.org.pl&#x2F;&quot;&gt;Stowarzyszenie na rzecz Chłopców i Mężczyzn&lt;&#x2F;a&gt;, w którego tworzeniu miałem swój drobny udział. Raport dotyczy problemu małej ilości mężczyzn na studiach medycznych, próbuje go diagnozować, proponuje rozwiązania, analogiczne np. do programu &quot;Dziewczyny na politechniki&quot;, który ma duże sukcesy.&lt;&#x2F;p&gt;
&lt;p&gt;W związku z tym raportem, powstało kilka artykułów w internetowych gazetach. Jeden z nich, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rp.pl&#x2F;spoleczenstwo&#x2F;art42484811-coraz-mniej-mezczyzn-na-studiach-medycznych-problem-z-rownoscia-plci&quot;&gt;opublikowany na RP.pl&lt;&#x2F;a&gt;, wywołał &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;dziennikrzeczpospolita&#x2F;posts&#x2F;pfbid02K8Ptq91mmk1gUznoLXeJy1Fux6V3UwHHbjVsNPpzB8pMTjH4JkDrSvS3758TYC9jl&quot;&gt;burzliwą dyskusję na Facebooku&lt;&#x2F;a&gt;. Chciałem poczytać tę dyskusję. Ale po tym, jak musiałem po raz sto pięćdziesiąty kliknąć przycisk &quot;Pokaż więcej odpowiedzi&quot;, trochę się zirytowałem.&lt;&#x2F;p&gt;
&lt;p&gt;Przypomniałem sobie jednak, że używałem kiedyś wspaniałej skryptozakładki, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;com.hemiola.com&#x2F;bookmarklet&#x2F;&quot;&gt;Expand Facebook Comments&lt;&#x2F;a&gt;, która robiła właśnie to - ekspandowała fejsbukowe komenty, automatycznie klikając te guziczki. Niestety, jej twórca zirytował się bardziej ode mnie, bo przestał ją rozwijać. Jak tłumaczy w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;com.hemiola.com&#x2F;2015&#x2F;08&#x2F;29&#x2F;expand-all&#x2F;&quot;&gt;tym wpisie&lt;&#x2F;a&gt;, nie rozwija jej:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;(...) due to Facebook changes that, as a human, make no sense to me and have finally caused me to ignore Facebook (going on six months now).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Całkowicie go rozumiem, i też chciałbym nie używać Facebooka, ale na ten moment nadal jest tam zbyt dużo osób i organizacji, które cenię, a które publikują jedynie tam. Na szczęście, mam wszystko czego potrzebuję, żeby spróbować samemu taką skryptozakładkę stworzyć.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;zalozenia&quot;&gt;Założenia&lt;&#x2F;h1&gt;
&lt;p&gt;Nie wgłębiałem się kod źródłowy istniejącej skryptozakładki, ale zakładam, że całe cierpienie jej autora spowodowane było tym, że do identyfikacji przycisków próbował używać selektorów CSS&#x2F;XPath oraz atrybutów &lt;code&gt;id&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;class&lt;&#x2F;code&gt;. Ponieważ Facebook to jest jeden wielki skrypt JS, pradopodobnie te identyfikatory zmieniają się nawet z dnia na dzień. Dlatego zdecydowałem się na inne podejście, i moja skryptozakładka będzie udawała mnie.&lt;&#x2F;p&gt;
&lt;p&gt;Ja, żeby rozwinąć odpowiedzi, szukam przycisku &quot;Wyświetl wszystkie X wiadomości&quot;, no i go klikam. I dokładnie tak napisałem mój kod. Teraz, gdy zobaczyłem przycisk &quot;Wyświetl wszystkie X wiadomości&quot;, zamiast klikać jego, klikałem moją skryptozakładkę, a ona klikała ten przycisk - a także każdy inny przycisk o takim samym tytule. Działało ślicznie.&lt;&#x2F;p&gt;
&lt;p&gt;Kolejnym krokiem było rozbudowanie skrytu o rozpoznawanie kolejnych przycisków: &quot;Wyświetl więcej&quot;, &quot;Pokaż więcej odpowiedzi&quot;, oraz mój ulubiony specjalny przypadek, &quot;Wyświetl 1 odpowiedź&quot;. Teraz po każdym kliknięciu rozwijało się praktycznie wszystko, co było zwinięte.&lt;&#x2F;p&gt;
&lt;p&gt;Ale po chwili zaczęło mnie irytować to, że muszę klikać skryptozakładkę xD. Dlatego do zrobienia została ostatnia rzecz: sprawić, żeby skryptozakładka &lt;em&gt;klikała się sama&lt;&#x2F;em&gt;. Oczywiście to nie jest możliwe, JS nigdy nie będzie klikał po interfejsie przeglądarki. Ale może nasłuchiwać zmian na stronie, i jeśli w nowej treści pojawi się jeden z przycisków, to niech skrypt go kliknie, i gotowe. Ze względu na to, jak działa obserwowanie zmian (&lt;code&gt;MutationObserver&lt;&#x2F;code&gt;), skrypt może się wywoływać rekurencyjnie, co jest fajnym udogodnieniem, bo wtedy cały wątek rozwinie się &quot;sam&quot;: &lt;code&gt;Observer&lt;&#x2F;code&gt; wykrywa zmianę, skanuje stronę, klika przyciski, w wyniku czego pojawia się nowa zmiana, i lecimy od nowa - aż skończą się przyciski do klikania.&lt;&#x2F;p&gt;
&lt;p&gt;Teraz skryptozakładka jedyne co robi, to instaluje się na stronie, i po prostu działa. I to bez żadnych dodatkowych wtyczek, bez wstrzykiwania skryptów przez ViolentMonkey, i istnieje jedynie do kolejnego odświeżenia strony! Proste i piękne!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;kod-zrodlowy&quot;&gt;Kod źródłowy&lt;&#x2F;h1&gt;
&lt;p&gt;Dla formalności: żeby to działało w skryptozakładce, trzeba &lt;em&gt;zinlajnować&lt;&#x2F;em&gt; ten cały kod, oraz dodać na początku &lt;code&gt;javascript:&lt;&#x2F;code&gt;. Z moich obserwacji wynika, że - przynajmniej w Firefoxie - zakładki bardzo nie lubią mieć w sobie znaków nowej linii.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;&#x2F;&#x2F; Auto-clicking bookmarklet with MutationObserver
&#x2F;&#x2F; This will automatically click &amp;quot;show more&amp;quot; buttons as they appear on the page
&#x2F;&#x2F; Click again to stop the observer

(function () {
  &#x2F;&#x2F; Check if observer is already running (toggle off)
  if (window.fbAutoClicker) {
    closeAutoClickerBar();
    return;
  }

  &#x2F;&#x2F; Click existing buttons first
  const existingButtons = Array.from(
    document.querySelectorAll(&amp;#39;div[role=&amp;quot;button&amp;quot;]&amp;#39;)
  ).filter((button) =&amp;gt; isTargetButton(button.textContent));

  console.log(&amp;quot;Clicking&amp;quot;, existingButtons.length, &amp;quot;existing buttons&amp;quot;);
  existingButtons.forEach((button, index) =&amp;gt; {
    setTimeout(() =&amp;gt; clickButton(button), index * 200);
  });

  &#x2F;&#x2F; Set up observer for new buttons
  const observer = new MutationObserver((mutations) =&amp;gt; {
    mutations.forEach((mutation) =&amp;gt; {
      mutation.addedNodes.forEach((node) =&amp;gt; {
        checkForButtons(node);
      });
    });
  });

  &#x2F;&#x2F; Start observing
  observer.observe(document.body, {
    childList: true,
    subtree: true,
  });

  &#x2F;&#x2F; Store observer globally so we can stop it
  window.fbAutoClicker = observer;

  &#x2F;&#x2F; Add a persistent red bar at the top
  createRedBar();

  console.log(&amp;quot;Auto-clicker started - monitoring for new buttons&amp;quot;);
  alert(&amp;quot;Auto-clicker started! Click bookmarklet again to stop.&amp;quot;);

  &#x2F;&#x2F; === FUNCTION DEFINITIONS ===

  function isTargetButton(text) {
    return (
      (text.includes(&amp;quot;Wyświetl wszystkie&amp;quot;) &amp;amp;&amp;amp; text.includes(&amp;quot;odpowiedzi&amp;quot;)) ||
      text.includes(&amp;quot;Wyświetl więcej&amp;quot;) ||
      text.includes(&amp;quot;Pokaż więcej odpowiedzi&amp;quot;) ||
      text.includes(&amp;quot;Wyświetl 1 odpowiedź&amp;quot;)
    );
  }

  function clickButton(button) {
    const text = button.textContent.trim();
    console.log(&amp;quot;Auto-clicking:&amp;quot;, text);
    button.click();
  }

  function checkForButtons(node) {
    if (node.nodeType !== Node.ELEMENT_NODE) return;

    &#x2F;&#x2F; Check if the node itself is a button we want to click
    if (node.matches &amp;amp;&amp;amp; node.matches(&amp;#39;div[role=&amp;quot;button&amp;quot;]&amp;#39;)) {
      const text = node.textContent;
      if (isTargetButton(text)) {
        setTimeout(() =&amp;gt; clickButton(node), 100);
      }
    }

    &#x2F;&#x2F; Check child buttons
    const buttons = node.querySelectorAll(&amp;#39;div[role=&amp;quot;button&amp;quot;]&amp;#39;);
    buttons.forEach((button) =&amp;gt; {
      const text = button.textContent;
      if (isTargetButton(text)) {
        setTimeout(() =&amp;gt; clickButton(button), 100);
      }
    });
  }

  function createRedBar() {
    if (!document.getElementById(&amp;quot;fb-auto-clicker-bar&amp;quot;)) {
      const bar = document.createElement(&amp;quot;a&amp;quot;);
      bar.id = &amp;quot;fb-auto-clicker-bar&amp;quot;;
      bar.href = &amp;quot;#&amp;quot;;
      bar.textContent = &amp;quot;autoclicker enabled ✕&amp;quot;;
      bar.style.position = &amp;quot;fixed&amp;quot;;
      bar.style.top = &amp;quot;0&amp;quot;;
      bar.style.background = &amp;quot;red&amp;quot;;
      bar.style.color = &amp;quot;white&amp;quot;;
      bar.style.padding = &amp;quot;0.5em&amp;quot;;
      bar.style.fontSize = &amp;quot;1.5em&amp;quot;;
      bar.onclick = function (e) {
        e.preventDefault();
        closeAutoClickerBar();
      };
      document.body.appendChild(bar);
    }
  }

  function closeAutoClickerBar() {
    if (window.fbAutoClicker) {
      window.fbAutoClicker.disconnect();
      delete window.fbAutoClicker;
    }
    const redBar = document.getElementById(&amp;quot;fb-auto-clicker-bar&amp;quot;);
    if (redBar) {
      redBar.remove();
    }
    console.log(&amp;quot;Auto-clicker stopped&amp;quot;);
    alert(&amp;quot;Auto-clicker stopped&amp;quot;);
  }
})();
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;muzyczka&quot;&gt;Muzyczka&lt;&#x2F;h1&gt;
&lt;p&gt;Pisaniu tego posta towarzyszyła mi poniższa muzyczka - usłyszana przeze mnie pierwszy raz w życiu dzisiaj, użyta w intro do WWDC. Fajna.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=3AFhaKGsgRc&quot;&gt;POLO &amp;amp; PAN — The Mirror (Lyrics Video)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>ING Bank mnie nienawidzi</title>
        <published>2025-05-30T22:05:00+00:00</published>
        <updated>2025-05-30T22:05:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-30-ing-bank-mnie-nienawidzi/"/>
        <id>https://mtsz.pl/blog/2025-05-30-ing-bank-mnie-nienawidzi/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-30-ing-bank-mnie-nienawidzi/">&lt;p&gt;Ci, który mnie znają, wiedzą, że jeśli miałbym jedyną rzecz, na którą mógłbym narzekać, i na żadną inną - to wybrałbym kiepskie aplikacje. Konkretnie ich interfejsy oraz szeroko rozumiane &quot;doświadczenie użytkownika&quot;. Ponieważ zarówno zawodowo, jak i prywatnie jestem wielkim fanem programowania, komputerów, aplikacji, urządzeń cyfrowych i internetu, zwracam bardzo dużą uwagę na użyteczność i intuicyjność tego typu rozwiązań. W ogóle generalnie uważam, że współczesna technologia jest praktycznie jak magia, ale nie w kwestii tego, jak działa, tylko jak bardzo pozwala na rozwiązywanie najmniejszych oraz największych problemów na świecie. Oczywiście tworzy też nowe, ale moim zdaniem wartość netto jest dodatnia. Do rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;Jednym z banków, któremu powierzyłem swoje finanse jest ING Bank. Jest tak samo dobry i tak samo zły jak każdy inny bank na świecie. Ale jedną rzecz robią tak &lt;strong&gt;idiotycznie&lt;&#x2F;strong&gt;, że zasłużyli na laurkę na moim wspaniałym blogu.&lt;&#x2F;p&gt;
&lt;p&gt;ING Bank dostęp do konta zabezpiecza przy użyciu tzw. hasła maskowanego. Hasło maskowane to nic innego, jak formularz akceptujący losowe litery hasła, zamiast całego ciągu. Zdjęcie poglądowe poniżej.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-05-30-ing-bank-mnie-nienawidzi&#x2F;ing-mask.png&quot; alt=&quot;hasło maskowane ING&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Samo hasło maskowane to jeszcze nie koniec świata. Co prawda, wpisywanie hasła w ten sposób jest upierdliwe, bo większość ludzi nawet z hasłami &lt;code&gt;alamakota123&lt;&#x2F;code&gt; będzie potrzebować kilku chwil, żeby doliczyć, jaka litera jest na siódmej pozycji (dalej, powiedz jaka, bez liczenia). Problem ten rozwiązują niektóre menadżery haseł - ja wiem, że robi to na pewno wtyczka BitWardena. Więc w czym problem?&lt;&#x2F;p&gt;
&lt;p&gt;Ano w tym, że ING, oprócz tego wspaniałego pomysłu, miało jeszcze jeden - i to lepszy! Otóż praktycznie każdy jeden element interfejsu strony logowania ING jest wsadzony w tak zwany &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Web_Components#Shadow_DOM&quot;&gt;Shadow DOM&lt;&#x2F;a&gt; - co to jest, nie ma większego znaczenia. Znaczenie ma to, że to prawie całkowicie wywala dzialanie jakiegokolwiek menadżera haseł. Serio, szukałem i nie znalazłem jednego działającego rozwiązania. Nie będę się nawet zastanawiał z czego wynika taka gigantyczna kulminacja idiotyzmów na stronie ING, bo już wiem, że to z powodu bezpieczeństwa, myślenia o dzieciach, zapobiegania kradzieży tożsamości, i to dla mojej wygody!&lt;&#x2F;p&gt;
&lt;p&gt;No i zajebiście, tylko że moje hasło do ING ma maksymalną ilość wszystkich możliwych losowych znaków, jakie tylko wygenerował mi menadżer haseł. I ja naprawdę tracę cierpliwość za KAŻDYM. JEDNYM. RAZEM. jak muszę zalogować się do banku. Serio, raz tak odkładałem zapłcenie podatków, że dostałem maila od ZUSu, że oni bardzo przepraszają, ale mają wiecie gdzie to, że nie chce mi się wpisywać hasła, i że mam zapłacić odsetki w ciągu 5 dni.&lt;&#x2F;p&gt;
&lt;p&gt;Ale nie od tego mam kąkuter, żeby się przejmować takimi problemami. Enter &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Skryptozak%C5%82adka&quot;&gt;skryptozakładka&lt;&#x2F;a&gt;. Skryptozakładka to, jak sama nazwa wskazuje, skrypt zaklęty w zakładkę. Ponieważ nie chce mi się już pisać samemu kodu, poprosiłem oczywiście czatbota o napisanie mi skryptozakładki, która po uruchomieniu, tak zmodyfikuje ekran logowania ING, że pojawi się na nim:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;pojedyncze pole tekstowe, do którego będę mógł jak normalny człowiek autouzupełnić hasło,&lt;&#x2F;li&gt;
&lt;li&gt;przycisk &quot;Wstaw hasło&quot;, który po kliknięciu sobie poszczególne literki powkłada w te różne otwory ING Banku.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Finalnie wygląda to tak:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-05-30-ing-bank-mnie-nienawidzi&#x2F;ing-form.png&quot; alt=&quot;hasło ludzkie ING&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Co robi ten skrypt?&lt;&#x2F;p&gt;
&lt;p&gt;Ocala życie.&lt;br &#x2F;&gt;
Leczy zszargane nerwy.&lt;br &#x2F;&gt;
&lt;em&gt;Ratuje ludzkość&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;javascript: (function () {
  function findElementByIdInShadowDom(id, root = document) {
    if (root.getElementById?.(id)) return root.getElementById(id);
    for (const el of root.querySelectorAll(&amp;quot;*&amp;quot;)) {
      if (el.shadowRoot) {
        const found = findElementByIdInShadowDom(id, el.shadowRoot);
        if (found) return found;
      }
    }
    return null;
  }

  function findElementByTagInShadowDom(tagName, root = document) {
    const elements =
      root.getElementsByTagName?.(tagName) ||
      root.querySelectorAll?.(tagName) ||
      [];
    if (elements.length &amp;gt; 0) return elements[0];
    for (const el of root.querySelectorAll(&amp;quot;*&amp;quot;)) {
      if (el.shadowRoot) {
        const found = findElementByTagInShadowDom(tagName, el.shadowRoot);
        if (found) return found;
      }
    }
    return null;
  }

  function createPasswordFieldAndButton() {
    console.log(&amp;quot;Looking for ing-card element...&amp;quot;);
    const ingCard = findElementByTagInShadowDom(&amp;quot;ing-card&amp;quot;);
    if (!ingCard) {
      console.log(&amp;quot;Nie znaleziono &amp;lt;ing-card&amp;gt;, skrypt nie może kontynuować&amp;quot;);
      return;
    }
    console.log(&amp;quot;Found ing-card, checking for shadow root&amp;quot;);
    if (!ingCard.shadowRoot) {
      console.log(&amp;quot;ing-card doesn&amp;#39;t have a shadow root, inserting directly&amp;quot;);
      insertPasswordTools(ingCard);
      return;
    }
    console.log(&amp;quot;ing-card has a shadow root, inserting inside it&amp;quot;);
    let targetElement = ingCard.shadowRoot;
    if (targetElement.firstElementChild) {
      insertPasswordTools(targetElement);
    } else {
      console.log(&amp;quot;Shadow root is empty, inserting directly&amp;quot;);
      insertPasswordTools(targetElement);
    }
  }

  function insertPasswordTools(container) {
    const passwordField = document.createElement(&amp;quot;input&amp;quot;);
    passwordField.type = &amp;quot;password&amp;quot;;
    passwordField.id = &amp;quot;manual-password-field&amp;quot;;
    passwordField.name = &amp;quot;password&amp;quot;;
    passwordField.className = &amp;quot;password-field&amp;quot;;
    passwordField.autocomplete = &amp;quot;current-password&amp;quot;;
    passwordField.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Password&amp;quot;);
    passwordField.placeholder = &amp;quot;Wpisz swoje hasło&amp;quot;;
    passwordField.style.marginBottom = &amp;quot;10px&amp;quot;;
    passwordField.style.padding = &amp;quot;8px&amp;quot;;
    passwordField.style.width = &amp;quot;100%&amp;quot;;
    passwordField.style.boxSizing = &amp;quot;border-box&amp;quot;;

    const button = document.createElement(&amp;quot;button&amp;quot;);
    button.textContent = &amp;quot;Wstaw hasło&amp;quot;;
    button.style.marginBottom = &amp;quot;10px&amp;quot;;
    button.style.padding = &amp;quot;8px 16px&amp;quot;;
    button.style.width = &amp;quot;100%&amp;quot;;
    button.style.boxSizing = &amp;quot;border-box&amp;quot;;
    button.type = &amp;quot;button&amp;quot;;

    const toolContainer = document.createElement(&amp;quot;div&amp;quot;);
    toolContainer.style.padding = &amp;quot;10px&amp;quot;;
    toolContainer.style.border = &amp;quot;2px solid #ff6200&amp;quot;;
    toolContainer.style.borderRadius = &amp;quot;5px&amp;quot;;
    toolContainer.style.background = &amp;quot;#fff&amp;quot;;
    toolContainer.style.marginBottom = &amp;quot;10px&amp;quot;;
    toolContainer.style.zIndex = &amp;quot;9999&amp;quot;;
    toolContainer.style.position = &amp;quot;relative&amp;quot;;

    const fieldContainer = document.createElement(&amp;quot;div&amp;quot;);
    fieldContainer.id = &amp;quot;password-form&amp;quot;;
    fieldContainer.setAttribute(&amp;quot;role&amp;quot;, &amp;quot;form&amp;quot;);
    fieldContainer.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Login Form&amp;quot;);
    fieldContainer.appendChild(passwordField);
    fieldContainer.appendChild(button);
    toolContainer.appendChild(fieldContainer);

    const heading = document.createElement(&amp;quot;div&amp;quot;);
    heading.textContent = &amp;quot;ING Password Tool&amp;quot;;
    heading.style.fontWeight = &amp;quot;bold&amp;quot;;
    heading.style.marginBottom = &amp;quot;10px&amp;quot;;

    toolContainer.insertBefore(heading, toolContainer.firstChild);

    if (container.firstElementChild) {
      container.insertBefore(toolContainer, container.firstElementChild);
    } else {
      container.appendChild(toolContainer);
    }

    console.log(&amp;quot;Password field and button added&amp;quot;);

    function isFieldDisabled(field) {
      return (
        field.disabled ||
        field.hasAttribute(&amp;quot;disabled&amp;quot;) ||
        field.getAttribute(&amp;quot;aria-disabled&amp;quot;) === &amp;quot;true&amp;quot;
      );
    }

    button.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {
      const password = passwordField.value;
      if (!password) {
        console.log(&amp;quot;Wpisz hasło w pole tekstowe&amp;quot;);
        return;
      }
      console.log(`Attempting to fill password of length ${password.length}`);
      let filledCount = 0;
      let disabledCount = 0;
      for (let i = 0; i &amp;lt; password.length; i++) {
        const currentPasswordInput = findElementByIdInShadowDom(
          `current-password-${i}`
        );
        if (currentPasswordInput) {
          if (isFieldDisabled(currentPasswordInput)) {
            console.log(`Field current-password-${i} is disabled, skipping`);
            disabledCount++;
          } else {
            currentPasswordInput.value = password[i];
            currentPasswordInput.dispatchEvent(
              new Event(&amp;quot;input&amp;quot;, { bubbles: true })
            );
            console.log(
              `Filled character &amp;quot;${password[i]}&amp;quot; into field current-password-${i}`
            );
            filledCount++;
          }
        } else {
          console.log(`Could not find field current-password-${i}`);
        }
      }
      console.log(
        `Filled ${filledCount} password fields (skipped ${disabledCount} disabled fields)`
      );
    });
  }
  createPasswordFieldAndButton();
})();
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Bru</title>
        <published>2025-05-28T19:51:00+00:00</published>
        <updated>2025-06-11T13:33:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-28-bru/"/>
        <id>https://mtsz.pl/blog/2025-05-28-bru/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-28-bru/">&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt; to wspaniały menadżer pakietów, z którego korzystam na macOS. Ponieważ staram się często aktualizować zainstalowane programy, to już nawykowo wpisuję do Terminala szereg komend w kolejności, czekając na jedną po drugiej. Bez sensu, marnowanie czasu, wzrost frustracji - od czego mam programowanie™?&lt;&#x2F;p&gt;
&lt;p&gt;Poniżej funkcja, którą wrzuciłem do pliku &lt;code&gt;.bru.sh&lt;&#x2F;code&gt;, a następnie podpiąłem w pliku &lt;code&gt;.zshrc&lt;&#x2F;code&gt;, o tak:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;[[ -f ~&#x2F;.bru.sh ]] &amp;amp;&amp;amp; source ~&#x2F;.bru.sh
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Teraz wystarczy wpisać w Terminalu &lt;code&gt;bru {-af}&lt;&#x2F;code&gt; i litania robi się sama.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;# ~&#x2F;.bru.sh

function _verbose {
  local magenta=$&amp;#39;\e[35m&amp;#39;
  local clear=$&amp;#39;\e[0m&amp;#39;
  local command=${*}
  echo ${magenta}${command}${clear}
  bash -c &amp;quot;${command}&amp;quot;
}

function _ask {
  local message=${1}
  local yellow=$&amp;#39;\e[33m&amp;#39;
  local red=$&amp;#39;\e[31m&amp;#39;
  local clear=$&amp;#39;\e[0m&amp;#39;

  read -k1 &amp;quot;input?&amp;quot;${yellow}${message}${clear} &amp;amp;&amp;amp; echo
  if [[ ${input} != [yY] ]]; then
    echo ${red}&amp;quot;Step skipped, continuing...&amp;quot;${clear}
    return 1
  fi
}

function _notify {
  local message=${1}
  local green=$&amp;#39;\e[32m&amp;#39;
  local clear=$&amp;#39;\e[0m&amp;#39;
  echo ${green}${message}${clear}
}

function _warn {
  local message=${1}
  local red=$&amp;#39;\e[31m&amp;#39;
  local clear=$&amp;#39;\e[0m&amp;#39;
  echo ${red}${message}${clear}
}

function bru {
  # Set default values
  local auto=false
  local full=false
  local ignored=&amp;quot;firefox&amp;quot; # | separated

  # Parse options
  while getopts &amp;quot;af&amp;quot; opt; do
    case $opt in
    a) auto=true ;;
    f) full=true ;;
    \?) return 1 ;;
    esac
  done

  # Print warnings and notifications
  $auto &amp;amp;&amp;amp; _warn &amp;quot;Automatic mode - won&amp;#39;t ask for confirmation&amp;quot; ||
    _notify &amp;quot;Interactive mode - will ask for confirmation&amp;quot;
  $full &amp;amp;&amp;amp; _warn &amp;quot;Full upgrade - includes ignored packages&amp;quot; ||
    _notify &amp;quot;Default upgrade - ignores specified packages&amp;quot;

  # Update and list outdated packages
  _verbose brew update

  _notify &amp;quot;Regular upgrade:&amp;quot;

  $full &amp;amp;&amp;amp; _verbose brew outdated --formula ||
    _verbose &amp;quot;brew outdated --formula | grep -vE &amp;#39;($ignored)&amp;#39;&amp;quot;
  $full &amp;amp;&amp;amp; _verbose brew outdated --cask ||
    _verbose &amp;quot;brew outdated --cask | grep -vE &amp;#39;($ignored)&amp;#39;&amp;quot;

  # Upgrade packages
  $auto || _ask &amp;quot;Regular upgrade? (y&#x2F;n): &amp;quot; &amp;amp;&amp;amp; {
    $full &amp;amp;&amp;amp; _verbose &amp;quot;brew upgrade&amp;quot; ||
      _verbose &amp;quot;brew outdated | grep -vE &amp;#39;($ignored)&amp;#39; | xargs brew upgrade&amp;quot;
  }

  _notify &amp;quot;Greedy upgrade:&amp;quot;

  # List outdated greedy casks
  $full &amp;amp;&amp;amp; _verbose brew outdated --cask --greedy ||
    _verbose &amp;quot;brew outdated --cask --greedy | grep -vE &amp;#39;($ignored)&amp;#39;&amp;quot;

  # Upgrade packages greedy
  $auto || _ask &amp;quot;Greedy upgrade? (y&#x2F;n): &amp;quot; &amp;amp;&amp;amp; {
    $full &amp;amp;&amp;amp; _verbose &amp;quot;brew upgrade --greedy&amp;quot; ||
      _verbose &amp;quot;brew outdated --greedy | grep -vE &amp;#39;($ignored)&amp;#39; | xargs brew upgrade&amp;quot;
  }

  # Autoremove and cleanup
  _verbose brew autoremove
  _verbose brew cleanup
  _verbose brew doctor
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Muzyczka podczas programowania: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=UjpbQ1OWMPE&quot;&gt;M83 - Oblivion (feat Susanne Sundfør) - audio &lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Muzyka z Czyli Zet</title>
        <published>2025-05-26T15:33:00+00:00</published>
        <updated>2025-05-26T15:33:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-26-muzyka-z-czyli-zet/"/>
        <id>https://mtsz.pl/blog/2025-05-26-muzyka-z-czyli-zet/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-26-muzyka-z-czyli-zet/">&lt;p&gt;Podczas pandemii jedną z form spędzania czasu było jeżdżenie samochodem po mieście. Wszystko było zamykane, straż miejska robiła łapanki ludzi spacerujących w odległości mniejszej niż 5 metrów - samochód był enklawą wolności w perspektywie domowego więzienia. W tym też czasie zdarzało mi się słuchać dużo radia ChilliZet, które raz na czas serwowało muzykę, która naprawdę mi się podobała. Dużo takich inspiracji wylądowało finalnie w mojej bibliotece, np. Kinnship:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=J3SHcBqC_sY&quot;&gt;Kinnship - Backwards [Official Lyric Video]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ale do rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;W radiu było na tyle dużo fajnych piosenek, że pomyślałem, że może bym sobie skombinował ich całą playlistę, i słuchał na własnych warunkach? Bo tam czasami leciała też średnia muzyka, a w swojej biblitece miałbym pełną kontrolę nad &lt;em&gt;moderacją&lt;&#x2F;em&gt;. Wbiłem do internetu, i okazuje się, że na stronie &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;player.chillizet.pl&#x2F;Sprawdz-co-gralismy&quot;&gt;Sprawdź co graliśmy&lt;&#x2F;a&gt; jest dokładna playlista. Pierwsze zwycięstwo.&lt;&#x2F;p&gt;
&lt;p&gt;Strona podaje piosenki w godzinowych iteracjach, żeby zmieniać godziny, wystarczy zmienić cyfrę w adresie, np. dla godziny 14:00 jest to&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;https:&#x2F;&#x2F;player.chillizet.pl&#x2F;Sprawdz-co-gralismy&#x2F;(godzina)&#x2F;14
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Co prawda przez to mam dostęp do muzyki tylko z ostatniej doby, ale zawsze coś, można puścić jakieś cykliczne zadanie, i niech się akumulują dane. &quot;Napisałem&quot; (bo tak naprawdę to Cursor napisał) super prosty skrypt w Pythonie, który pobiera wszystkie strony, parsuje HTML, i wyciąga dane. Odpalam... i klops. Dane są ładowane dynamicznie, za pomocą JavaScriptu.&lt;&#x2F;p&gt;
&lt;p&gt;Dobra, to dajcie mi ten skrypt Javy. Inspekcja strony, i cyk:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;https:&#x2F;&#x2F;gfx-player.chillizet.pl&#x2F;design&#x2F;player&#x2F;javascript&#x2F;played-history.js
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Otwieram plik, no i wiadomo: obfuskacja, minimalizacja, masturbacja. Przekopiowałem kod do Cursora, i sformatowałem go. Nadal koszmar. No to wklepałem do promptera: &quot;convert this to Python script&quot;. Dwie minuty później, mam gigantyczny projekt z chyba 15 plikami, dokumentacją, testami, plikiem README mówiącym mi, jak mam żyć. Ugh, do kosza. Jeszcze raz: &quot;analyze this JS code, understand it, and create minimal Python script to fetch data about played songs&quot;. Kolejne dwie minuty... i tym razem się udało. Nadal dużo bigosu, ale już tylko jeden plik, no i nawet elegancki interfejs:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;% python3 minimal_radio.py -h
usage: minimal_radio.py [-h] [--station STATION] [--date DATE] [--time TIME] [--csv CSV]
                        [--print] [--count COUNT]

Fetch radio station history

options:
  -h, --help            show this help message and exit
  --station, -s STATION
                        Radio station (default: radiozet)
  --date, -d DATE       Date in YYYY-MM-DD format (default: current date)
  --time, -t TIME       Time in HH:MM format (default: current time)
  --csv, -c CSV         Save tracks to CSV file (default: tracks.csv)
  --print, -p           Print tracks to console
  --count, -n COUNT     Maximum number of tracks to fetch (default: unlimited)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No i tak się bawię tym, testuję sobie, ale coś mi nie gra. Wbijam konkretną stację, datę, godzinę, &lt;code&gt;count&lt;&#x2F;code&gt;, i dostaję wyniki z wybranej godziny, ale też późniejsze. Hmm. A co się stanie, jak wpiszę do &lt;code&gt;count&lt;&#x2F;code&gt; np. 1000? No proszę. Dostanę 1000 kolejnych wpisów, zaczynając od wpisanej daty i godziny. A jak wpiszę 999999? To dostanę &lt;strong&gt;wszystkie&lt;&#x2F;strong&gt;. Doskonale - bo teraz już nie będę musiał robić ani żadnych &lt;code&gt;cron&lt;&#x2F;code&gt;ów, &lt;code&gt;fetch&lt;&#x2F;code&gt;ów, &lt;code&gt;scrape&lt;&#x2F;code&gt;ów, tylko sobie ugotuję dosłownie jeden skrypt w Bashu, i dostanę wszystkie dane, jakie tylko są mi potrzebne.&lt;&#x2F;p&gt;
&lt;p&gt;Po chwili testów okazało się, że pierwszy wpis w bazie jest z dnia 5 maja 2022, z godziny 4:00. Nie należy też przesadzać z liczbą pobieranych ścieżek. Liczba, która u mnie działała to 110000, to mniej więcej liczba ścieżek odgrywanych w ciągu jednego roku, więc skrypt wystarczy ustawić na 1 stycznia na godzinę 00:00, i uruchomić dosłownie 4 razy (dla lat 2022-25), żeby mieć całą historię piosenek (i nie tylko) z Chilli Zet. Oczywiście przetworzenie tych danych to osobna bajka, ale już nie na ten wpis.&lt;&#x2F;p&gt;
&lt;p&gt;Oto finalny skrypt dla potomnych:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env zsh

DATE=2022-05-04
TIME=10:00:00

TIMESTAMP=$(date -j -f &amp;#39;%Y-%m-%dT%H:%M:%SZ&amp;#39; &amp;quot;${DATE}T${TIME}Z&amp;quot; +%s)
EMITTER=chilli
TRACK_COUNT=20

URL=&amp;quot;https:&#x2F;&#x2F;rds.eurozet.pl&#x2F;reader&#x2F;history.php?true=jsonData&amp;quot;

[[ -n &amp;quot;$TIMESTAMP&amp;quot; ]] &amp;amp;&amp;amp; URL=&amp;quot;$URL&amp;amp;startDate=$TIMESTAMP&amp;quot;
[[ -n &amp;quot;$EMITTER&amp;quot; ]] &amp;amp;&amp;amp; URL=&amp;quot;$URL&amp;amp;emitter=$EMITTER&amp;quot;
[[ -n &amp;quot;$TRACK_COUNT&amp;quot; ]] &amp;amp;&amp;amp; URL=&amp;quot;$URL&amp;amp;trackCount=$TRACK_COUNT&amp;quot;

curl -s &amp;quot;$URL&amp;quot; | sed &amp;#39;s&#x2F;^jsonData(&#x2F;&#x2F;;s&#x2F;)$&#x2F;&#x2F;&amp;#39; | jq . &amp;gt;output.json
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dobra, jeszcze na szybkości skrypt w Pythonie (wygenerowany przez Cursora oczywiście), do wyeksportowania unikalnych piosenek do pliku CSV:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;python&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3

import json
import csv
import glob

# Read all JSON files and aggregate data
all_songs = []
seen_ids = set()

for file in glob.glob(&amp;quot;*.json&amp;quot;):
  with open(file) as f:
    data = json.load(f)
    for song in data[&amp;quot;messages&amp;quot;][0]:
      if (
        song[&amp;quot;rds_song_id&amp;quot;] not in seen_ids
        and song.get(&amp;quot;rds_title&amp;quot;)
        and song.get(&amp;quot;rds_artist&amp;quot;)
      ):
        all_songs.append(song)
        seen_ids.add(song[&amp;quot;rds_song_id&amp;quot;])

# Export to CSV
with open(&amp;quot;aggregated_songs.csv&amp;quot;, &amp;quot;w&amp;quot;, newline=&amp;quot;&amp;quot;) as f:
  if all_songs:
    writer = csv.DictWriter(f, fieldnames=all_songs[0].keys())
    writer.writeheader()
    writer.writerows(all_songs)

print(f&amp;quot;Exported {len(all_songs)} unique songs to aggregated_songs.csv&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Powrót do feudalizmu</title>
        <published>2025-05-23T23:08:00+00:00</published>
        <updated>2025-05-23T23:08:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-23-powrot-do-feudalizmu/"/>
        <id>https://mtsz.pl/blog/2025-05-23-powrot-do-feudalizmu/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-23-powrot-do-feudalizmu/">&lt;p&gt;Skopiowany z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;migasbartosz&#x2F;posts&#x2F;pfbid0QE8PN1fQkuzF7h9ocEGMQjFKBAMR7WmgEEBJ8hViCo9HA4AxSJ1Vd54TVvzFDugfl&quot;&gt;tego posta na Facebooku&lt;&#x2F;a&gt; wpis na temat powodów wysokiego poparcia szurskich opcji politycznych tuż przed wyborami prezydenckimi. Archiwizuję, ponieważ przedstawia bardzo interesującą perspektywę, z którą się zgadzam.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;To co się dzieje w polityce jest w gruncie rzeczy dość proste do wyjaśnienia i przewidzenia.&lt;&#x2F;p&gt;
&lt;p&gt;Struktura społeczna od zarania dziejów wyglądała bardzo podobnie - większość majątku i władza religijna&#x2F;polityczna skupiona w wąskim gronie elit i masy ludzi walczących codziennie o przetrwanie i wykarmienie rodziny przy pługu, młocie, warsztacie, czy z bronią w ręku. Tak wyglądały z grubsza miasta starożytnego Sumeru, tak wyglądała Judea czasów Jezusa, na takich fundamentach stało Cesarstwo Rzymskie, taką strukturę prezentowały średniowieczne państwa, chińskie i japońskie cesarstwa, imperia Inków i Azteków, wiktoriańska Anglia, Imperium Osmańskie i z grubsza tak wygląda dziś Brazylia, Indie czy RPA.&lt;&#x2F;p&gt;
&lt;p&gt;Tzw. Zachód zrobił wyłom od tej zasady w okresie XX wieku, kiedy w pierwszej połowie zaczęły pojawiać się pierwsze jaskółki redystrybucji bogactwa od bogatej elity do mas społecznych, które rozwiną się na dobre po II WŚ w postaci państw dobrobytu, z wysokim opodatkowaniem zamożnych, licznymi programami socjalnymi i rozwojem usług publicznych. Był to właściwie jedyny moment w historii, kiedy uczciwie pracujący ludzie trudniący się codzienną mozolną pracą mogli odczuwać względne bezpieczeństwo, że będą mieć dach nad głową, opiekę zdrowotną, dostęp do publicznej edukacji dla ich dzieci i zabezpieczenie na starość. Ale wraz z nadejściem neoliberałów ten eksperyment się skończył, a to co obserwujemy od pół wieku to powrót do ustawień fabrycznych ludzkości.&lt;&#x2F;p&gt;
&lt;p&gt;Bogatym odpuszczono podatki i poluzowano regulacje rynków globalizując je, co szybko przyniosło efekty. Bogate elity miały coraz mniej obowiązków wobec państwa i społeczeństwa, a coraz więcej możliwości do bogacenia się. I jak to zawsze w historii bywało bogaci niczym czarne dziury zaczęli wysysać frukta z ekonomii. Widać to na wielu przykładach np. mieszkania komunalne wyprzedano klasie robotniczej i średniej, która jednak zaczęła następnie wyprzedawać nieruchomości w ręce bogatszych - widać to choćby na przykładzie UK czy Polski, gdzie w kilka dekad nieruchomości na masową skalę przepłynęły od pojedyńczych właścicieli w ręce różnej maści landlordów czy funduszy inwestycyjnych zwięszkając dodatkowo pasywny przychód ich właścicielom, pozwalając im na kupowanie coraz to nowych nieruchomości i wysysać z rynku także te dopiero co wybudowane pod najem. Podobny mechanizm możemy jednak zaobserwować też w przypadku publicznego majątku wspierającego usługi publiczne - publiczne przedsiębiorstwa masowo poszły pod młotek trafiając w ręce bogaczy, którzy kroili je na kawałki, przenosili produkcję do trzeciego świata, lub też odwrotnie, budowali monopole - w każdym razie to co kiedyś służyło całości społeczeństwa obsługując podstawowe potrzeby (poczta, opieka zdrowotna, edukacja, transport, telekomunikacja, energetyka) przekształciło się w biznesy, które generowały dochody już tylko dla bogatych właścicieli nowopowstałych spółek prywatnych żywiących się publicznym niegdyś majątkiem.&lt;&#x2F;p&gt;
&lt;p&gt;Dziś kiedy przeciętny Kowalski wydaje na cokolwiek, część monet zasila fortunę bogatego właściciela - płacisz za wynajem mieszkania - brzdęk, płacisz ratę kredytu hipotecznego - brzdęk, płacisz za prywatne przedszkole - brzdęk, płacisz za internet, telefon, ubezpieczenie na życie - brzdęk. Ale bogacze nie wysysają pieniędzy tylko ze społeczeństwa, ale też z rządów. Pozbawione wpływów podatkowych rządy, które wyprzedały dużą część majątku są zależne od wyborców, muszą więc dostarczać usługi publiczne, tylko że coraz trudniej jest to robić bo 1) nie ma wpływów podatkowych od bogaczy, którzy płacą niskie podatki lub unikają ich wogóle 2) nie mają insfrastruktury bo została wyprzedana (szpitale, elektrownie, koleje). Co więcej robią rządy? 1) Obciążają coraz bardziej podatkami zwyklych ludzi (procentowo największe podatki płacą osoby zatrudnione na umowę o pracę) 2) utrzymują wysoki VAT (obciążając konsumpcję, która jest największa u zwykłych ludzi, bo bogacze większość pieniędzy inwestują lub zachowują) 3) obniżają jakość usług publicznych z uwagi na brak środków na ich sfinansowanie 4) jeśli już oferują usługi publiczne to albo płacą za nie bogaczom (np. kontrakty NFZ z prywatnymi NZOZami) lub zadłużają się u bogaczy emitując obligacje itp.
Receptą na ten stan rzeczy miał być stały wzrost - im więcej wyprodukujemy tym więcej będzie do podziału i nawet jeśli ten podział jest nie do końca uczciwy, to nadal wszyscy będą odczuwać polepszenie warunków życia. Tylko, że bogacze są niczym czarne dziury, które im większą mają masę tym szybciej i więcej wysysają materię dookoła. Twoja pensja wzrosła kilka razy w ciągu ostatniej dekady, w której wybudowano tysiące nowych mieszkań? To fajnie, ale ceny nieruchomości również wzrosły, ceny kredytów też, a większość z tych mieszkań trafiła do wąskiego grona ludzi, którzy czerpią z nich dochody. Masz więcej pieniędzy na konsumpcję? To fajnie, ale ceny wszystkiego poszły w górę - energia, czynsze, jedzenie, ubezpiezpieczenia. Zarabiasz więcej, masz więcej rzeczy dookoła siebie, ale na fundamentalnym poziomie nadal nie masz zabezpieczenia podstawowych potrzeb, na które musisz cały czas tyrać. Kto nie ma mieszkania nadal na nie nie zarobi, kto ma wiele mieszkań temu zostaną dodane nowe.&lt;&#x2F;p&gt;
&lt;p&gt;Co to ma wspólnego z wyborami? Wszystko. Klasa pracująca już od dawna jest pod silną presją i wizja poprawy bytu oddala się coraz bardziej - praca jest automatyzowana, warunki pracy uśmieciowiane, usługi publiczne obcinane, obciążenia podatkowe (PIT i VAT) relatywnie wysokie, koszty życia (czynsz, energia, jedzenia) uniemożliwają odkladanie na przyszłość, zabezpieczenie emerytalne jest coraz bardziej iluzoryczne. Jeśli startujesz jako człowiek niezamożny to prawdopodobnie takim zostaniesz do końca życia, przykro mi, ale system oferuje coraz mniej i coraz trudniejsze drogi do wskoczenia na wyższy poziom. A tutaj też jest presja - AI właśnie zbiera się do wycięcia z rynku podstawowych prac biurowych i inteligenckich (np. tłumacze, juniorskie stanowiska w korpie), w tym samym czasie upadające usługi publiczne pauperyzują masę urzędników i pracowników publicznych (np. nauczyciele, pocztowcy, kolejarze, pracownicy instytucji kultury). Drobne biznesy wycinają z rynku monopole (Żabki, sieci piekarni, markety) masowa produkcja taniego i guwnianego sprzętu odbiera chleb rzemieślnikom (znikają szewcy, krawce, serwisanci sprzętów RTV i AGD). Klasa średnia rozrywana jest na strzępy na naszych oczach - większość z nich już wkrótce zasili niezamożne masy społeczne, a tylko nieliczna grupa doszusuje bliżej w pobliże bogatych (wykwalifikowani specjaliści, kadra managerska, przedsiębiorcy, posiadacze mniejszych majątków generujących pasywny dochód).&lt;&#x2F;p&gt;
&lt;p&gt;I teraz nadchodzą wybory i masy ludzi codziennie bytujących pod presją, czujący na plecach oddech landlorda, wierzycieli lub AI, tacy którzy obawiają się restrukturyzacji ich firm, zamrożenia podwyżek, podwyżek cen kredytów, energii czy żywności, ludzie stojący w coraz dłuższych kolejkach do lekarzy, walczący o miejsce w publicznym złobku, tacy ludzie dostają do ręki kraty wyborcze.&lt;&#x2F;p&gt;
&lt;p&gt;Łatwo jest skierować gniew ludzi stojących w kolejce do lekarza czy walczących o miejsce w publicznym żłobku na imigrantów i Ukraińców z którymi konkurują o kurczące się usługi publiczne.
Łatwo jest skierować gniew ludzi ledwo wiążących koniec z końcem na Żydów sterujących gospodarką czy brukselskich urzędników nakładajacych bzdurne prawa podnoszące ceny prądu czy jedzenia.&lt;&#x2F;p&gt;
&lt;p&gt;Łatwo jest przekonać ludzi płacących wysoki podatek dochodowy i VAT od swoich marnych pensji, że państwo ich okrada i karze podatkami za pracę.&lt;&#x2F;p&gt;
&lt;p&gt;Łatwo jest wywołać nienawiść do kobiet wśród młodych mężczyzn, którzy z uwagi na swój status finansowy mają problemy z założeniem rodziny, kiedy kobiety mają większe możliwości wżenienia się w majątek, więc naturalnie poszukują lepiej usytuowanych partnerów (tak, środowisko redpillowe i wykopowi incele nie biorą się znikąd).&lt;&#x2F;p&gt;
&lt;p&gt;Nie dziwcie się więc wynikom wyborów kiedy liberałowie w rządzie obcałowują rączki Brzoskom tego krajo pierdolącym kocopoły o upadku etosu pracy, kiedy zakochani w pojedyńczych historiach sukcesu liberalni pismacy opowiadają farmazony o tym jak ciężką pracą ludzie się bogacą i chcieć to móc, kiedy dyżurni etycy zainstalowani na profesorskich stołkach grzmią o upadku moralnym pospólstwa ze swoich katedr niczym bóg starotestamentowy.&lt;&#x2F;p&gt;
&lt;p&gt;Nie dziwcie się, albowiem będzie tego tylko więcej i mocnej, im szybciej będą bogacić się giełdy, a zadłużać gospodarstwa domowe i rządy, im szybciej będą rosnąć dochody najbogatszych a dłużej stać w miejscu wynagrodzenia w relacji do całości PKB, im więcej będzie rosnąć efektywność, a kurczyć się zasób dóbr, które można nabyć za przeciętne wynagrodzenia, im szybciej będzie rosnąć majątek wąskich elit, a im bardziej będzie oddalać się perspektywa na dach nad głową, rodzinę i porządną edukację dla przeciętnych zjadaczy chleba.&lt;&#x2F;p&gt;
&lt;p&gt;Tak, to jest tak proste.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Gigantyczne stopnie</title>
        <published>2025-05-21T22:26:00+00:00</published>
        <updated>2026-03-03T12:27:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-21-gigantyczne-stopnie/"/>
        <id>https://mtsz.pl/blog/2025-05-21-gigantyczne-stopnie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-21-gigantyczne-stopnie/">&lt;p&gt;A. wysłała mi jakiś czas temu to i myślę, że to jest wspaniałe: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=oiZCNAqq7Ug&quot;&gt;CLOCKS but it&#x27;s GIANT STEPS&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Naszło mnie, żeby sobie poszukać podobnych, i znalazłem te. Są wspaniałe:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=uBncldiuVn0&quot;&gt;SEPTEMBER (But It&#x27;s Giant Steps)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=VaD7rRPxcjQ&quot;&gt;BAD GUY but it&#x27;s GIANT STEPS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=og4kwL2JpsY&quot;&gt;Sandstorm but it&#x27;s Giant Steps&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;...tak, będę edytował ten wpis&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=_i5YvMkzAtY&quot;&gt;A Thousand Giant Steps by Vanessa Coltrane&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Piękny komentarz pod ostatnim filmem:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&#x27;s just all sit for a moment and reflect on the fact that this was released 1 week into the pandemic&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>RSS jest dla mnie bardzo ważny</title>
        <published>2025-05-19T19:20:00+00:00</published>
        <updated>2025-06-09T21:32:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-19-rss-jest-dla-mnie-bardzo-wazny/"/>
        <id>https://mtsz.pl/blog/2025-05-19-rss-jest-dla-mnie-bardzo-wazny/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-19-rss-jest-dla-mnie-bardzo-wazny/">&lt;p&gt;No, to tyle. Dziękuję za uwagę.&lt;&#x2F;p&gt;
&lt;p&gt;Dobra, nie musisz wiedzieć, co to jest RSS, jak działa i dlaczego właściwie miałby być ważny dla ciebie. Podejrzewam, że osób, które to wiedzą, jest naprawdę mało. Dlatego zacznijmy od początku.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;RSS – Really Simple Syndication albo RDF Site Summary, czyli Resource Description Framework Site Summary&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h1 id=&quot;wyglada-jak-rss-dziala-jak-rss&quot;&gt;Wygląda jak RSS, działa jak RSS...&lt;&#x2F;h1&gt;
&lt;p&gt;Przeczytałem wiele różnych artykułów na temat RSS-a. Ich autorzy, próbując wyjaśnić, czym jest RSS, najczęściej albo silą się na techniczny bełkot, albo porównują go do jakichś wydumanych usług, takich jak zamawianie jedzenia przez Uber Eats czy poczta elektroniczna. Te porównania są, moim zdaniem, strasznie karkołomne. Uważam, że wystarczy dosłownie jedno–dwa słowa do opisania, czym tak naprawdę jest ta technologia, tak, żeby każdy od razu intuicyjnie zrozumiał, o co w tym wszystkim chodzi. RSS to po prostu internetowa...&lt;&#x2F;p&gt;
&lt;h1 id=&quot;cherry-blossom-prenumerata-subskrypcja-blossom&quot;&gt;🌸 PRENUMERATA &#x2F; SUBSKRYPCJA 🌼&lt;&#x2F;h1&gt;
&lt;p&gt;Moim zdaniem RSS powinno rozwijać się do Really Simple Subscriptions&lt;&#x2F;p&gt;
&lt;p&gt;Dobra — zapytasz — no i co w tym takiego rewolucyjnego albo ważnego?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sciek-informacyjny&quot;&gt;Ściek informacyjny&lt;&#x2F;h1&gt;
&lt;p&gt;Nie będzie nowością stwierdzenie, że większość ludzi informacje i wiadomości czerpie głównie z mediów społecznościowych, gdzie dosłownie każdy może publikować, komentować, lajkować, szerować, spamować, dezinformować — ile tylko zapragnie. Portale takie jak Facebook, Twitter, Instagram i cała reszta mają ogromny problem z moderowaniem tych treści — a to tylko jedna strona medalu. Bo przecież są tam też algorytmy, które zamykają użytkownika w bańce informacyjnej, podsuwając informacje, na które jest najbardziej podatny, które najdłużej utrzymają jego uwagę, najbardziej zbulwersują czy zdezorientują.&lt;&#x2F;p&gt;
&lt;p&gt;A przecież nadal istnieją w internecie rzetelne źródła informacji i nadal są osoby zainteresowane ich zdobywaniem. W jaki sposób to zrobić? Do tego potrzeba dwóch narzędzi.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rzetelne-zrodla&quot;&gt;Rzetelne źródła&lt;&#x2F;h1&gt;
&lt;p&gt;Pierwsze narzędzie to umiejętność wyszukiwania rzetelnych źródeł. To nie jest temat tego wpisu, ale doskonałym źródłem wiedzy na ten temat jest film Skajfana. Polecam obejrzeć później, a my lecimy dalej.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=T1vW8YDDCSc&quot;&gt;Krótki film o prawdzie i fałszu&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;przystepna-forma&quot;&gt;Przystępna forma&lt;&#x2F;h1&gt;
&lt;p&gt;Drugie narzędzie to sposób pozyskiwania informacji z tych źródeł — taki, który nie jest sterowany żadnymi algorytmami, nie wciska spamu, reklam i całego tego śmietnika, do którego — obawiam się — większość internautów już dawno się przyzwyczaiła przez zbyt długą ekspozycję.&lt;&#x2F;p&gt;
&lt;p&gt;O mediach społecznościowych jako źródle informacji już wspomniałem. Ale są też inne: papierowe gazety, czasopisma i magazyny, telewizja, radio, portale informacyjne, eksperckie strony internetowe, podcasty, reportaże, wywiady. Gigantycznym źródłem informacji — zarówno rzetelnych, jak i wręcz przeciwnie — jest też na przykład YouTube oraz TikTok.&lt;&#x2F;p&gt;
&lt;p&gt;Problem, który być może intuicyjnie już widzisz, to mnogość tych źródeł. Nawet jeśli wybierzesz sobie kilka gazet, kilka portali informacyjnych, kilka blogów eksperckich, podcastów i kanałów wideo, to i tak robi się z tego kilkanaście, kilkadziesiąt, a czasami nawet kilkaset miejsc, które trzeba by było przeglądać codziennie, żeby być na bieżąco.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;na-ratunek-rss&quot;&gt;Na ratunek RSS&lt;&#x2F;h1&gt;
&lt;p&gt;RSS to takie rozwiązanie technologiczne, które te wszystkie źródła - a przynajmniej te internetowe (chociaż te papierowe&#x2F;radiowe&#x2F;telewizyjne tak naprawdę w większości też już zmigrowały do internetów) - pozwala śledzić w jednym miejscu. Każdy nowy artykuł, podcast, film na YouTubie, wpis na blogu, informacja na portalu — (prawie) wszystko możesz mieć dostarczone w jedno miejsce, używając jednego prostego triku.&lt;&#x2F;p&gt;
&lt;p&gt;RSS rozwiązuje wszystkie wymienione wcześniej problemy w sposób banalnie prosty. Przede wszystkim masz pełną kontrolę nad tym, co subskrybujesz. To ty decydujesz, które źródła chcesz śledzić, co wyświetli się na twojej &quot;tablicy informacyjnej&quot; - żaden algorytm zasilony milionem anonimowych lajków tego nie determinuje, nie zobaczysz żadnej reklamy pomiędzy interesującymi cię artykułami. Wszystko ułożone jest w porządku chronologicznym, bez mieszania kolejnością, powtarzania tych samych artykułów czy znikania tych, które cię zainteresowały. Możesz czytać, co chcesz, kiedy chcesz, jak chcesz.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rss-i-jego-czytnik&quot;&gt;RSS i jego czytnik&lt;&#x2F;h1&gt;
&lt;p&gt;Czytnik RSS to taki program, w którym możesz subskrybować te wszysktie treści z dowolnych stron i portali internetowych. Aby było to możliwe, jedyne, co dana strona musi posiadać, to tzw. kanał RSS.&lt;&#x2F;p&gt;
&lt;p&gt;Jest z tym oczywiście problem — wiele stron takiego kanału nie posiada, albo mają go gdzieś głęboko zakopanego, albo jest on uszkodzony, albo niepełny, albo wręcz celowo został przez stronę usunięty po tym, jak dana strona przyciągnęła odpowiednią ilość użytkowników, żeby zamknąć ich w swoim zamurowanym ogrodzie — ale to temat na kolejny wpis.&lt;&#x2F;p&gt;
&lt;p&gt;Czytników RSS — na wszystkie systemy operacyjne, jako aplikacje&#x2F;strony internetowe, wtyczki do przeglądarek — jest co najmniej milion. Osobiście korzystam z &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;netnewswire.com&#x2F;&quot;&gt;NetNewsWire&lt;&#x2F;a&gt;, bo jest otwartoźródłowy (co jest dla mnie bardzo ważne) i działa na wszystkich urządzeniach od Apple&#x27;a, których używam na co dzień (iPhone, iPad, MacBook). Wcześniej na iPhonie używałem też aplikacji &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;reederapp.com&#x2F;&quot;&gt;Reeder&lt;&#x2F;a&gt;. Dawno temu używałem aplikacji internetowej &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.theoldreader.com&#x2F;&quot;&gt;TheOldReader&lt;&#x2F;a&gt; - to klon bardzo popularnego niegdyś Google Reader&#x27;a, powstały po uśmierceniu tego drugiego przez Google&#x27;a ich bardzo popularnego niegdyś projektu - która była bardzo w porządku (przestałem z niej korzystać tylko dlatego, że chcę zredukować liczbę używanych usług poza moją kontrolą na rzecz aplikacji na moim komputerze). Innych aplikacji nie chcę polecać, ponieważ żadnej innej nie używałem, ale w internecie pełno jest poradników i rankingów. Zachęcam Cię do testowania różnych opcji i znalezienia tej, która najbardziej ci odpowiada.&lt;&#x2F;p&gt;
&lt;p&gt;Poniżej przykładowe zdjęcie z takiego programu. Co na nim widać? Po lewej stronie — lista wszystkich stron, które subskrybujesz. W środkowej kolumnie — lista wszystkich artykułów ze wszystkich tych stron, w jednym miejscu! Niektóre oznaczone jako nieprzeczytane, inne jako przeczytane. Po prawej stronie — pełna (najczęściej) treść artykułu. Wszystko przejrzyście, jednolitą czcionką, bez reklam, bez losowej kolejności, z jasno oznaczoną informacją, co zostało przeczytane, a co nie. Podane źródło, autor, a po kliknięciu w nagłówek artykułu — można otworzyć źródłową stronę internetową.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-05-19-rss-jest-dla-mnie-bardzo-wazny&#x2F;nnw.png&quot; alt=&quot;zrzut ekranu z NetNewsWire&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;W ramach zadania domowego proponuję to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;poszukaj i zainstaluj pierwszy lepszy czytnik RSS, jaki znajdziesz na swój telefon lub komputer&lt;&#x2F;li&gt;
&lt;li&gt;dodaj do niego kilka stron lub portali, które mniej lub bardziej obserwujesz&lt;&#x2F;li&gt;
&lt;li&gt;poużywaj przez tydzień i zobacz czy to jest coś dla Ciebie.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Na rozgrzewkę podam kilka źródeł, które sam subskrybuję:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;ar.al&#x2F;index.xml&lt;&#x2F;code&gt; - programowanie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;brd24.pl&#x2F;feed&#x2F;&lt;&#x2F;code&gt; - bezpieczeństwo ruchu drogowego&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;www.internet-czas-dzialac.pl&#x2F;rss&#x2F;&lt;&#x2F;code&gt; - internetowanie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;kontrabanda.net&#x2F;feed&lt;&#x2F;code&gt; - okołointernetowe dziennikarstwo obywatelskie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;feeds.macrumors.com&#x2F;MacRumors-All&lt;&#x2F;code&gt; - ploteczki ze świata Apple&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;blog.oliwierjaszczyszyn.com&#x2F;feed&#x2F;&lt;&#x2F;code&gt; - internetowanie obywatelskie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;siecobywatelska.pl&#x2F;feed&#x2F;&lt;&#x2F;code&gt; - sprawdzanie jak jest&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;https:&#x2F;&#x2F;schm.org.pl&#x2F;feed&#x2F;&lt;&#x2F;code&gt; - przywracanie mężczyznom podmiotowości&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;W tym wpisie poruszyłem kilka zagadnień, które zasługują na swoje osobne rozwinięcie. Być może poruszę je w kolejnych wpisach. Albo nie. Czas pokaże.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;aspekty techniczne protokołu RSS i jego nowszego odpowiednika, Atom&lt;&#x2F;li&gt;
&lt;li&gt;szkodliwe mechanizmy mediów społecznościwych i problemy z moderacją&lt;&#x2F;li&gt;
&lt;li&gt;absurdalne ilości reklam w przestrzeni internetowej&lt;&#x2F;li&gt;
&lt;li&gt;brakujące lub uszkodzone kanały RSS&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;em&gt;No, to tyle. Dziękuję za uwagę.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Początek po raz ostatni</title>
        <published>2025-05-13T20:59:00+00:00</published>
        <updated>2025-05-13T20:59:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-13-poczatek-po-raz-ostatni/"/>
        <id>https://mtsz.pl/blog/2025-05-13-poczatek-po-raz-ostatni/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-13-poczatek-po-raz-ostatni/">&lt;p&gt;Test, raz, dwa, trzy. To jest pierwszy dokument &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pl.wikipedia.org&#x2F;wiki&#x2F;Markdown&quot;&gt;Markdown&lt;&#x2F;a&gt;, który będzie moim blogiem.&lt;&#x2F;p&gt;
&lt;p&gt;Tak naprawdę to nie pierwszy. Miałem już około milion prób. Ale ta jest ostatnia, ponieważ jestem &quot;u siebie&quot;. To znaczy, ten plik powstaje wewnątrz mojego skarbca w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obsidian.md&#x2F;&quot;&gt;Obsidianie&lt;&#x2F;a&gt;. O tym jak to działa, dlaczego tak, a nie inaczej, co to jest Markdown i Obsidian, planuję napisać w przyszłości.&lt;&#x2F;p&gt;
&lt;p&gt;Styl strony ukradłem (dosłownie, skopiowałem CSSa) od &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ar.al&#x2F;&quot;&gt;Arala Balkana&lt;&#x2F;a&gt;, bo mi się spodobał, i zakładam, że mu to nie przeszkadza.&lt;&#x2F;p&gt;
&lt;p&gt;Strona działa w oparciu o &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zolę&lt;&#x2F;a&gt;, to takie fajne narzędzie do generowania tzw. statycznych stron.&lt;&#x2F;p&gt;
&lt;p&gt;Dobra, muszę sprawdzić teraz kilka standardowych rzeczy, zacznijmy od formatowania kodu, bo jakżeby inaczej?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;kod-zrodlowy&quot;&gt;Kod źródłowy&lt;&#x2F;h1&gt;
&lt;pre&gt;&lt;code data-lang=&quot;python&quot;&gt;def check_directory(directory, ignore_files):
  for root, _, files in os.walk(directory):
    for file in files:
      if file.endswith(&amp;#39;.md&amp;#39;):
        check_file(os.path.join(root, file), ignore_files)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tło jest za jasne, ale kolorowanie składni dziala, więc na razie tak to zostawię. Aktualizacja 20 maja: naprawione!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;obrazki&quot;&gt;Obrazki&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-05-13-poczatek-po-raz-ostatni&#x2F;piesek.jpg&quot; alt=&quot;tu ma być piesek&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Obrazki działają doskonale.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;cytaty&quot;&gt;Cytaty&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;We do this not because
it is easy,
but because
we thought it would be easy&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Cytaty też OK.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;youtube&quot;&gt;YouTube&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=S3mwdn0rYjA&quot;&gt;GusGus - Love is Alone (Official Music Video)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Głosuję na Zandberga</title>
        <published>2025-05-10T12:14:00+00:00</published>
        <updated>2025-05-10T12:14:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-10-glosuje-na-zandberga/"/>
        <id>https://mtsz.pl/blog/2025-05-10-glosuje-na-zandberga/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-10-glosuje-na-zandberga/">&lt;p&gt;Ten wpis opublikowałem na Facebooku, ale archiwizuję go tutaj, bo Facebook to ściek, z którego prędzej czy później zrezygnuję.&lt;&#x2F;p&gt;
&lt;p&gt;Ci z Was, którzy znają mnie wystarczająco długo, mogą pamiętać, jakie poglądy i sympatie polityczne miałem za swoich młodzieńczych lat. Pewnie niewiele i niewielu z Was wie, że nawet startowałem do sejmu na posła RP z ramienia partii pewnego starszego pana. W tamtym okresie generalnie bardzo otwarcie mówiłem na temat moich poglądów politycznych.&lt;&#x2F;p&gt;
&lt;p&gt;Potem przyszła dorosłość, praca, mieszkanie, jednym słowem: życie, i na jałowe dyskusje zabrakło czasu, bo trzeba było się zająć prawdziwymi obowiązkami. W przeciągu tego całego czasu problemy, które obserwowałem za młodu, nie uległy jednak znaczącej poprawie, niektóre nawet się pogorszyły.&lt;&#x2F;p&gt;
&lt;p&gt;Postanowiłem więc na chwilę wrócić do mojej otwartości, i powiedzieć Wam wszystkim, że zamierzam w najbliższych wyborach głosować na Zandberga. Przeczytałem jego propozycje, posłuchałem kilka wywiadów, i doszedłem do wniosku, że ja naprawdę chciałbym żyć w takim kraju, jakim on go maluje.&lt;&#x2F;p&gt;
&lt;p&gt;To co chcę Wam przekazać to: poczytajcie propozycje kandydatów, posłuchajcie wywiadów, i wybierzcie tak, żeby nam wszystkim w tymkraju™ było lepiej, niż jest dzisiaj. Według Waszego najlepszego uznania.&lt;&#x2F;p&gt;
&lt;p&gt;Robię ten manifest również dlatego, że krew w żyłach mrozi mi myśl, że ktoś może nadal przypisać mi poglądy i sympatie 19-letniego Matiego, a już szczególnie przez pryzmat aktualnych poglądów tamtej strony sceny politycznej.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Friendship ended with JKM Now POTĘŻNY DUŃCZYK is my best friend&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Do postu był dodany link do &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.facebook.com&#x2F;partiarazem&#x2F;videos&#x2F;539844279087378&#x2F;&quot;&gt;filmu na Facebooku z Zandbergiem&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;mtsz.pl&#x2F;blog&#x2F;2025-05-10-glosuje-na-zandberga&#x2F;zandberg-post.png&quot; alt=&quot;post Zandberga&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Weval - Billboard Mixtape</title>
        <published>2025-05-07T23:46:00+00:00</published>
        <updated>2025-05-07T23:46:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2025-05-07-weval-billboard-mixtape/"/>
        <id>https://mtsz.pl/blog/2025-05-07-weval-billboard-mixtape/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2025-05-07-weval-billboard-mixtape/">&lt;p&gt;Gdzieś na SoundCloudzie wpadła mi ta składanka, spodobała mi się, więc postanowiłem zbudować z niej tracklistę i wrzucić tutaj.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;weval&#x2F;weval-billboard-mixtape&quot;&gt;Weval - Billboard Mixtape&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;tracklista&quot;&gt;Tracklista&lt;&#x2F;h1&gt;
&lt;ol&gt;
&lt;li&gt;0:00 - ???&lt;&#x2F;li&gt;
&lt;li&gt;1:56 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=svXZCOQobhc&quot;&gt;Red Axes ft. Abrão - Papa Sooma&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;6:20 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=IeKSV8NrLGg&quot;&gt;The Beach Boys - All I Wanna Do&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;9:53 - ???&lt;&#x2F;li&gt;
&lt;li&gt;12:04 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=nZDPCjEoIMI&quot;&gt;Charlie - Spacer Woman&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;14:31 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Zpl7fFQLG-U&quot;&gt;Weval - Square People&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;19:24 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=oAGReheIB3o&quot;&gt;Joanna Newsom – Yarn and Glue&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;25:04 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=8c4CbWJuFIM&quot;&gt;Simeon Ten Holt - Canto Ostinato&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;29:57 - ???&lt;&#x2F;li&gt;
&lt;li&gt;33:02 - ???&lt;&#x2F;li&gt;
&lt;li&gt;36:42 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=5lDwLtm3-5k&quot;&gt;Spectral Display - There&#x27;s A Virus Going Round&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;42:10 - ???&lt;&#x2F;li&gt;
&lt;li&gt;45:22 - ???&lt;&#x2F;li&gt;
&lt;li&gt;48:04 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=s6V_44ibou8&quot;&gt;Gotye - Don&#x27;t Worry, We&#x27;ll Be Watching You&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;50:07 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KHvYw4cn3TI&quot;&gt;David August - Ouvert&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;55:12 - ...
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KwhBreZic8I&quot;&gt;Outkast - SpottieOttieDopaliscious&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Jak brać ode mnie pieniądze</title>
        <published>2022-03-20T17:46:00+00:00</published>
        <updated>2022-03-20T17:46:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2022-03-20-jak-brac-ode-mnie-pieniadze/"/>
        <id>https://mtsz.pl/blog/2022-03-20-jak-brac-ode-mnie-pieniadze/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2022-03-20-jak-brac-ode-mnie-pieniadze/">&lt;p&gt;Szukałem właśnie informacji o otwartoźródłowej alternatywie dla Kindle Paperwhite. Znalazłem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=23584885&quot;&gt;link do HackerNews&lt;&#x2F;a&gt;, gdzie ktoś napisał:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why would you care about violating a law nobody on earth has any chance of catching you and punishing you. If you want to give money to the author you could consider seeing if they have a way to take donation&#x2F;patronage or buying a physical copy. If you don&#x27;t actually need the physical copy or have room for it gift it to someone and request that they gift it when they are done with it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Przypomniałem sobie wtedy, że dokładnie takie przemyślenie dotyczące opłacania autorów książek miałem dawno temu, gdy rozważałem, w jaki sposób osoby produkujące treści intelektualne (niefizyczne) mogą zapewnić sobie zarobkowanie w momencie, gdy wytwór ich pracy można skopiować i udostępnić zerowym kosztem. Temat oczywiście można rozszerzyć na muzykę, poezję, gry, książki, podręczniki, podkasty, audycje. Nawet całe radia.&lt;&#x2F;p&gt;
&lt;p&gt;Od kilku lat popularne stały się platformy pozwalające wspierać twórców. Co więcej, sam ostatnio zacząłem niektórych różnych twórców finansować w ten sposób.&lt;&#x2F;p&gt;
&lt;p&gt;Na bazie tych wszystkich rzeczy wyróżniłem kilka modeli finansowania, które moim zdaniem mają szansę przetrwania, a może nawet upowszechnienia się na tyle, że wyprą te &quot;stare&quot; modele.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;1-subskrypcje-platformowe&quot;&gt;1. Subskrypcje platformowe&lt;&#x2F;h1&gt;
&lt;p&gt;Aktualnie płacę za Netflixa oraz Apple Music. Za relatywnie niską cenę mam dostęp do bardzo dużego zbioru utworów. Niskość tej ceny jest usprawiedliwiona o tyle, że co prawda zasoby są gigantyczne, ale moje &quot;możliwości&quot; konsumpcyjne są bardzo organiczone, więc spokojnie powinno wystarczyć na opłacenie każdego twórcy, z którego treści korzystam. Potencjalnym problemem jest to, że rzeczy, których chcę obejrzeć albo posłuchać, nie ma na danej platformie. Musiałbym opłacać więcej niż jedną platformę, a wtedy płaciłbym kilkukrotnie za to samo, bo prawdopodobnie 90% zbiorów między platformami pokrywa się.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;2-wsparcie-cykliczne&quot;&gt;2. Wsparcie cykliczne&lt;&#x2F;h1&gt;
&lt;p&gt;Tutaj sprawa jest prosta. Produkt jest dostępny za darmo dla każdego, natomiast twórcy swoim &quot;patronom&quot; dają dostęp do dodatkowych możliwości lub nagród - newsletter, grupa na fejsie, pocztówka z wyjazdu. Dzięki czemu istnieje mechanizm finansowania w pewnym sensie niezależny od samej twórczości, osoby niezainteresowane lub nie mające możliwości wspierania, mogą to nadal robić, natomiast reszta może płacić tyle ile chce, tak długo jak chce. Ten model biznesowy radzi sobie zadziwiająco dobrze, pozwala zapłacić za coś po zapoznaniu się z jakością i tematyką, a co więcej, najczęściej nie ma reklam (oprócz autopromocji). Bardzo lubię ten model, jak już się do niego przekonałem, to w ciągu jednego miesiąca zacząłem wspierać 11 różnych twórców.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;3-subskrypcja-zamknieta&quot;&gt;3. Subskrypcja zamknięta&lt;&#x2F;h1&gt;
&lt;p&gt;Ten model kojarzy mi się najbardziej z aplikacjami mobilnymi. Za określoną kwotę dostajemy dostęp do określonej aplikacji, np. do medytacji albo listy zadań. Mam problem z tym modelem, bo o ile rozumiem potrzebę twórców do ciągłego utrzymywania serwerów, łatania błędów itp., kwota bardzo często jest nieadekwatna do wartości. Nie widzę powodu do płacenia 500 zł rocznie za aplikację do zadań, którą można zastąpić notesem albo plikiem tekstowym. Taka wygoda nie jest warta takich pieniędzy. Co więcej, uważam że model subskrypcji otwartej (patrz punkt 2) mógłby być lepszym modelem. Już nie zliczę, ile razy do pobrania aplikacji zniechęcił mnie tekst &quot;zakupy w aplikacji&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Próbując stworzyć syntezę tych informacji, idealny model finansowania to taki, który daje konsumentowi pełną dowolność co do wysokości kwoty i częstotliwości wpłat, umożliwiając jednocześnie twórcy godne zarobki. Jak pokazuje rzeczywistość, takie modele mają prawo istnieć i przynosić sensowne przychody.&lt;&#x2F;p&gt;
&lt;p&gt;Do obczajenia:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opencollective.com&#x2F;&quot;&gt;OpenCollective&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;patronite.pl&#x2F;&quot;&gt;Patronite&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Strach przed nie-lataniem</title>
        <published>2022-03-08T12:34:56+00:00</published>
        <updated>2022-03-08T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2022-03-08-strach-przed-nie-lataniem/"/>
        <id>https://mtsz.pl/blog/2022-03-08-strach-przed-nie-lataniem/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2022-03-08-strach-przed-nie-lataniem/">&lt;p&gt;Wracałem wczoraj samochodem z Austrii - byłem na nartach w Sölden. Na fragmentach dziesięciogodzinnej trasy nie było ograniczeń prędkości, więc jechałem (jako pasażer) z prędkościami z przedziału 140-200 km&#x2F;h. I miałem objawienie: strach przed lataniem jest absurdalny - szczególnie w odniesieniu do jazdy samochodem.&lt;&#x2F;p&gt;
&lt;p&gt;Jadąc samochodem po ziemi, absolutnie wszystko jest przeszkodą lub powodem wypadku. Każda jedna bariera, słup, budynek, drzewo, płot, maszyna, inny samochód. Każda nierówność na jezdni, każda dziura, poźlizg, trochę rozsypanego żwiru, mokra nawierzchnia. Spotkanie z jakimkolwiek zaburzeniem trasy z prędkością z ww. przedziału to gwarancja śmierci. A takie spotkanie jest w pewnym sensie nieuniknione. Nie możesz nie jechać po asfalcie. Nie możesz nie mijać budynków.&lt;&#x2F;p&gt;
&lt;p&gt;A w samolocie? Liczba przeszkód jest bliska zeru. Powody wypadków to niesprawny sprzęt, zła pogoda, błąd pilota. Koniec listy. Możesz lecieć 800 km&#x2F;h. W linii prostej. Bez żadnych przeszkód immanentnych transportowi kołowemu.&lt;&#x2F;p&gt;
&lt;p&gt;Zresztą statystyki mówią swoje. Nawet najbardziej &quot;niekorzystnie&quot; skorygowane statystyki potwierdzają, że latanie jest dużo bezpieczniejsze. Teraz, oprócz danych analitycznych mam swój argument anegdotyczny. q.e.d.&lt;&#x2F;p&gt;
&lt;p&gt;Wniosek: bardziej boję się jechać samochodem, niż latać samolotem.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Podróżne obawy</title>
        <published>2022-01-05T12:34:56+00:00</published>
        <updated>2022-01-05T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2022-01-05-podrozne-obawy/"/>
        <id>https://mtsz.pl/blog/2022-01-05-podrozne-obawy/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2022-01-05-podrozne-obawy/">&lt;p&gt;Wczoraj wróciłem z Islandii. Odpocząłem. Postanowiłem, że wrócę od podróżowania. Stresowałem się tą całą organizacją, a prawda jest taka, że podróż - jak każde inne zagadnienie - da się sprowadzić do zbioru trywialnych problemów. Transport na miejsce, transport na miejscu, mieszkanie, jedzenie, spędzanie czasu. Planowanie usuwa niepewność do wartości pomijalnych. Poza tym wyjazd do Niemiec będzie kolejną okazją. Zresztą bilety na samolot kupione, nocleg ogarnięty. Nie ma więcej rzeczy do ogarniania.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Fajna wtyczka do psucia YouTube&#x27;a</title>
        <published>2022-01-05T00:59:00+00:00</published>
        <updated>2022-01-05T00:59:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2022-01-05-fajna-wtyczka-do-psucia-youtube-a/"/>
        <id>https://mtsz.pl/blog/2022-01-05-fajna-wtyczka-do-psucia-youtube-a/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2022-01-05-fajna-wtyczka-do-psucia-youtube-a/">&lt;p&gt;Fajną wtyczkę do przeglądarki znalazłem. Nazywa się &quot;Remove YouTube Suggestions&quot; - chociaż powinna się raczej nazywać &quot;Remove YouTube Dopamine Injecting, Addiction Inflicting Brain Triggers&quot;. Co robi wtyczka? Jak sama nazwa wskazuje, oraz więcej: pozwala ukryć propozycje filmów na stronie głównej, sekcję propozycji po prawej stronie filmu, propozycje po wyświetleniu filmu. Bonusowo można ukryć sekcję komentarzy oraz live chat. Ukryłem wszystko.&lt;&#x2F;p&gt;
&lt;p&gt;I od razu zauważyłem ciekawą rzecz. Po obejrzeniu filmu - a nawet podczas jego oglądania - automatycznie zjechałem do miejsca, gdzie powinna być sekcja komentarzy. Dosłownie odruch Pawłowa. Oczywiście wiem, po co tam zjechałem. Biorąc pod uwagę, że mam ponad 200 zasubskrybowanych kanałów, tego, czego tam szukałem, miałem aż zanadto. Nie będę tęsknił.&lt;&#x2F;p&gt;
&lt;p&gt;Wtyczka jest otwartoźródłowa, to dobrze. W środku są linki do Firefoxa oraz Chrome&#x27;a: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lawrencehook&#x2F;remove-youtube-suggestions&quot;&gt;github:lawrencehook&#x2F;remove-youtube-suggestions&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;PostMeritum: podgląd strony Githuba na Facebooku wygląda brzydko, więc wrzucam piosenkę, którą YouTube podrzucił mi jako reklamę xD. Piosenka bardzo dobra, i do tego polska! &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ZTYSAl9Npqw&quot;&gt;Męskie Granie Orkiestra 2021 (Daria Zawiałow, Dawid Podsiadło, Vito Bambino) - I Ciebie też, bardzo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Facebooka fikołki</title>
        <published>2021-11-08T12:34:56+00:00</published>
        <updated>2021-11-08T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-11-08-facebooka-fikolki/"/>
        <id>https://mtsz.pl/blog/2021-11-08-facebooka-fikolki/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-11-08-facebooka-fikolki/">&lt;p&gt;Facebook robi srogie fikołki, żeby nie dało się ukryć sponsorowanych wpisów - vide &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;wolfiechristl&#x2F;status&#x2F;1071473931784212480&quot;&gt;ten tłit&lt;&#x2F;a&gt; (który pewnie i tak zniknie kiedyś z internetu, więc go przekleję):&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Facebook adds 5 divs, 9 spans and 30 css classes to every single post in the timeline to make it more difficult to identify and block &#x27;Sponsored&#x27; posts, oh my.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Facebook w ogóle robi mnóstwo obrzydliwych rzeczy, zarówno jawnie - za co nie odpowiadają przed nikim, jak i niejawnie - za co na pewno nidy nie odpowiedzą przed nikim. Ale wystarczy prosta wtyczka wstrzykująca style do strony oraz kilka linijek kodu CSS, żeby przeglądanie tego śmiesznego portalu było odrobinę bardziej spokojne. Albo raczej odrobinę mniej szargające nerwy, bo wszyscy wiemy, co Facebook robi z naszą uwagą.&lt;&#x2F;p&gt;
&lt;p&gt;Dla takiego Firefoxa prosta wtyczka to może być na przykład &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;addons.mozilla.org&#x2F;pl&#x2F;firefox&#x2F;addon&#x2F;styl-us&#x2F;&quot;&gt;Stylus&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Na dzisiejszy dzień, żeby posprzątać Facebooka ze śmieci, wystarczy ten krótki snippet:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;css&quot;&gt;.p8dawk7l.nc684nl6 { display: none; } &#x2F;* comment likes *&#x2F;
.stjgntxs.buofh1pr.bp9cbjyn { display: none; } &#x2F;* post likes *&#x2F;
.hlyrhctz { display: none; } &#x2F;* right pane *&#x2F;
.bx45vsiw.be9z9djy { display: none; }  &#x2F;* left pane *&#x2F;
.jbae33se, .ocebsr1h { display: none; }  &#x2F;* stories *&#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ukrywa on lajki pod komentarzami, lajki pod postami, ten prawy panel ze śmieciami, ten lewy panel ze śmieciami oraz ten górny panel ze śmieciami. Brak lajków - a szczególnie brak śmieszków i wkurwinek (to te &quot;zdenerwowane&quot; minki) - wyłącza tę natychmiastową reakcję oceniającą, która popycha do napisania komentarza. W przeważającej większości przypadków konieczność przeczytania komentarza, żeby wystawić mu ocenę jest kosztem zbyt dużym dla leniwego, małpiego rozumu. To lenistwo należy wykorzystać. W sumie dokładnie to samo lenistwo wykorzystuje Facebook z pomocą emotikonek.&lt;&#x2F;p&gt;
&lt;p&gt;Aha, ten kod pewnie przestanie działać za kilka miesięcy, bo Facebook nie może sobie pozwolić nad to, żeby ludzie panowali nad swoimi emocjami. Także miejcie się na baczności, moi drodzy nieistniejący czytelnicy.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Nie lubię poezji</title>
        <published>2021-09-06T12:34:56+00:00</published>
        <updated>2021-09-06T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-09-06-nie-lubie-poezji/"/>
        <id>https://mtsz.pl/blog/2021-09-06-nie-lubie-poezji/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-09-06-nie-lubie-poezji/">&lt;p&gt;Polski system edukacji włożył bardzo dużo wysiłku w to, żebym nie rozumiał ani nie lubił poezji. Pamiętam nawet, że na teście gimnazjalnym, z analizy i interpretacji wierszy miałem 0 punktów na 2 możliwe. Powody takiego wyniku mogą być różne, ale liczy się rezultat - 10 lat traumy sprawiło, że jestem zrażony do tej formy.&lt;&#x2F;p&gt;
&lt;p&gt;A nie powinienem. Bo okazuje się, że poezja ma bardzo wiele do zaoferowania. I jest trochę jak muzyka - może być dobra i może być zła. Ja dobrą poezję odkryłem dzięki dobrej muzyce. Mam nadzieję, że z traumy wyjdę szybciej, niż w nią wszedłem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=dB6T9Qrkz6A&quot;&gt;Błażej Król- Głos wewnętrzny (z albumu &quot;Herbert 3.0&quot;)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Zupa w kubku</title>
        <published>2021-08-15T00:13:00+00:00</published>
        <updated>2021-08-15T00:13:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-08-15-zupa-w-kubku/"/>
        <id>https://mtsz.pl/blog/2021-08-15-zupa-w-kubku/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-08-15-zupa-w-kubku/">&lt;p&gt;Wyobraź sobie, że jesteś na mieście, wychodzisz właśnie z uczelni, albo wychodzisz z tramwaju i kierujesz się w stronę uczelni albo pracy. Jesteś ciągle na nogach, bo dojazd zajmuje Ci dużo czasu. A może właśnie skończyłeś trzygodzinny wykład z fizyki. Masz tylko chwilę czasu, bo zaraz masz kolejną rzecz do zrobienia. Jesteś w biegu. Jesteś też głodny. Ale nie masz czasu na pójście do lokalu. Nie chcesz kupować jakiejś suchej drożdżówki - tylko się upaprasz, a poza tym nie jest ona ani trchę sycąca. Co teraz?&lt;&#x2F;p&gt;
&lt;p&gt;Teraz możesz kupić zupę w kubku! Coś jak kawa, tylko że zupa. Rosół jest idealny na chłodniejszy dzień, albo poranek po cięższej nocy. Masz ochotę na coś ostrzejszego? Może barszcz? Albo żurek? W kubku znajdziesz nie tylko zupę, ale także inne składniki zupy. Makaron, uszka, co tylko chcesz. Możesz spokojnie zjeść łyżką podczas lub po wypiciu zupy. Ale możesz też bez, jeśli nie chcesz.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nazwa: Zupa w Kubeł&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sprzedaż takiej zupy mogłaby się odbywać z podobnego ustrojstwa, co sprzedają kawę z roweru. Kilka garnków z podgrzewem, przygotowane wkładki, kubki, sztućce, terminal i viola. Idealną miejscówką na start wydaje się Rondo Mogilskie w Krakowie, przemiał ludzi jest tam gigantyczny.&lt;&#x2F;p&gt;
&lt;p&gt;Cena zupy powinna być bardzo niska, bo ani to skomplikowane, ani jakoś wielkoskalowe. Piątak za rosół w kubku brzmi super.&lt;&#x2F;p&gt;
&lt;p&gt;Przy okazji wpisałem w Google &lt;em&gt;zupa w kubku&lt;&#x2F;em&gt; i wyskoczyła mi firma &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.soupculture.pl&#x2F;&quot;&gt;Soup Culture&lt;&#x2F;a&gt;, która sprzedaje zupę w jadalnych kubkach. Pomysł świetny, chociaż narzut produkcyjny duży. Z drugiej strony nie trzeba by robić fikołków z jedzeniem wkładek.&lt;&#x2F;p&gt;
&lt;p&gt;Przy okazji: w Krakowie jest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;swiatoze.pl&#x2F;zupa-w-jadalnych-kubkach-dostepna-w-krakowie-soup-culture-otwiera-nowa-placowke&#x2F;&quot;&gt;mnóstwo knajp&lt;&#x2F;a&gt; sprzedających jedzenie wege. Można obczaić. Dodam do backloga.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Adiemus</title>
        <published>2021-08-01T12:34:56+00:00</published>
        <updated>2021-08-01T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-08-01-adiemus/"/>
        <id>https://mtsz.pl/blog/2021-08-01-adiemus/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-08-01-adiemus/">&lt;p&gt;Pamiętam z dzieciństwa taki jeden teledysk z delfinami. Siedziałem sobie wtedy po turecku na podłodze w salonie, w mieszkaniu z wielkiej płyty w Nowym Sączu przy ulicy Armii Krajowej. Musiałem zadzierać głowę, bo telewizor stał wysoko w meblościance, ale byłem przyzwyczajony. Same delfiny nie robiły na mnie jakiegoś specjalnego wrażenia, ale już ich przedstawienie na tle sprawiającego wrażenie nieskończonego, monumentalnego, pustego miasta, połączenie z chóralnym, epickiem śpiewem - już tak.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=uo9f-Co9APg&quot;&gt;Adiemus - Adiemus&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Piosenka, która wtedy leciała to Adiemus z płyty Adiemus: Songs of Sanctuary, nagranej w ramach projektu Adiemus przez Karla Jenkinsa, walijskiego kompozytora. Projekt jest utrzymany w stylu New Age. Sam teledysk już nie robi takiego wrażenia, trochę się zestarzał, ale nadal jest dobry. Natomiast muzyka jest nawet lepsza. Naturalnie przesłuchałem wszystkie utwory z całego projektu, które choć czasami powtarzalne, nadal brzmią dobrze i spójnie.&lt;&#x2F;p&gt;
&lt;p&gt;Niedawno trafiłem na coś bardzo podobnego muzycznie. W jednym z odcinków Raportu o Stanie Świata (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;raportostanieswiata.pl&#x2F;odcinki&#x2F;raport-o-stanie-swiata-17-lipca-2021&#x2F;&quot;&gt;o, tym&lt;&#x2F;a&gt;) wrzucony został utwór Pora Sotunda, nagrany w ramach projektu The Mystery of Bulgarian Voices przez Marcela Celliera, we współpracy z Bulgarian State Television Female Vocal Choir. Ten projekt próbuje pogodzić starodawny folk bułgarski z nowoczesną muzyką World, i wychodzi mu całkiem nieźle. Dostrzegam dużo podobieństw z Adiemusem.&lt;&#x2F;p&gt;
&lt;p&gt;Fajnie jest czasami odnaleźć stare wspomnienia w nowej formie. Tak w ogóle, to ten wpis jest jedynie pretekstem, żeby wrzucić piosenkę.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Rc8QRI6lXb8&quot;&gt;The Mystery of the Bulgarian Voices ft. Lisa Gerrard - Pora Sotunda&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Morderstwo na rowerze</title>
        <published>2021-07-28T12:34:56+00:00</published>
        <updated>2021-07-28T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-07-28-morderstwo-na-rowerze/"/>
        <id>https://mtsz.pl/blog/2021-07-28-morderstwo-na-rowerze/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-07-28-morderstwo-na-rowerze/">&lt;p&gt;Kupiłem sobie rower. I znowu musiałem zrewidować swój pogląd na temat ogólnego poziomu inteligencji ludzi. Albo poziomu uważności. A był on bardzo pobłażliwy, ten pogląd.&lt;&#x2F;p&gt;
&lt;p&gt;Może mam lekką paranoję, ale odkąd jeżdżę motocyklem, to staram się myśleć za każdego jednego uczestnika ruchu w promieniu 10 km. Wychodzę z założenia, że każdy jeden uczestnik ruchu ma tylko jeden cel - zabić mnie. Dzięki temu udało mi się uniknąć praktycznie jakichkolwiek nerwowych sytuacji na drodze.&lt;&#x2F;p&gt;
&lt;p&gt;Dzisiaj jechałem sobie rowerem po ścieżce rowerowej. Albo po ulicy. Dokładnie tak, jak kodeks drogowy przykazał, bo mam na tym punkcie lekkiego fioła. I tyle osób, ilu bym dzisiaj złamał kręgosłup przy bliższym spotkaniu pieszo-rowerowym, to ja nie zliczę. Chyba dla bezpieczeństwa tych wszystkich ludzi i dla spokoju mojego sumienia, portfela i odpowiedzialności prawnej, zapnę sobie nową heurystykę: każdy jeden pieszy ma tylko jeden cel - zabić się.&lt;&#x2F;p&gt;
&lt;p&gt;W sumie już tak robię w przypadku prowadzenia samochodu.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=bj3ih9EI99c&quot;&gt;MaJLo feat. Natalia Grosiak - Złoto (Official Lyric Video)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Facebook zaorany</title>
        <published>2021-07-21T12:34:56+00:00</published>
        <updated>2021-07-21T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-07-21-facebook-zaorany/"/>
        <id>https://mtsz.pl/blog/2021-07-21-facebook-zaorany/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-07-21-facebook-zaorany/">&lt;p&gt;Zaorałem swojego Facebooka. Zostawiłem tylko kilka tych wpisów, które są moimi refleksjami. Wywaliłem wszystkie polityczne sesje nienawiści, zaognione dyskusje na tematy jakimś cudem kontrowersyjne, wpisy bez sensu. Nikt nie będzie po nich płakał, bo Facebook to ściek bez refleksji o przeszłości, a mi jest lżej w głowie. Tym bardziej, że na część tematów zdążyłem już dawno zmienić zdanie. Np. na temat tego, że jakikolwiek sens ma komentowanie czegokolwiek. Albo jestem sprawczy i zmieniam rzeczywistość, albo nie jestem i się do niej dostosowuję. Komentowanie i frustracje niczego nie zmieniają, a jedynie zatruwają mój umysł.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=kZlaBqho6vE&quot;&gt;Polepiony - remastered 2018&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Znikający internet</title>
        <published>2021-04-10T12:34:56+00:00</published>
        <updated>2021-04-10T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-04-10-znikajacy-internet/"/>
        <id>https://mtsz.pl/blog/2021-04-10-znikajacy-internet/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-04-10-znikajacy-internet/">&lt;p&gt;Internet znika. Przeglądam sobie archiwalne wpisy na Wykopie, które zaplusowałem. Jakieś 70% stron nie istnieje, 70% obrazków linkuje nigdzie, 70% filmów zostało skasowanych, sprywatyzowanych, lub w jakiś inny sposób uszkodzonych.&lt;&#x2F;p&gt;
&lt;p&gt;Coraz bardziej przekonuję się, że prowadzenie niezależnego bloga jest pomysłem odpornym nawet na wojnę nuklearną. Albo pożar serwera.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Własne miejsce w internecie</title>
        <published>2021-04-08T12:34:56+00:00</published>
        <updated>2021-04-08T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-04-08-wlasne-miejsce-w-internecie/"/>
        <id>https://mtsz.pl/blog/2021-04-08-wlasne-miejsce-w-internecie/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-04-08-wlasne-miejsce-w-internecie/">&lt;p&gt;Mestosław - ten gość od narkotyków w internecie - znowu stracił swój profil internetowy. Tym razem na Instagramie.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=-LDuWnNk8So&quot;&gt;USUNELI MI KONTO NA INSTAGRAMIE TUŻ PRZED USTAWAMI W SEJMIE. KOMU NA TYM ZALEŻAŁO?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;W filmie wspomina, że stracił nie tylko możliwość dotarcia do jakichś 20 tysięcy osób, ale także dużą część swoich prywatnych zasobów, takich jak prywatne rozmowy ze znajomymi, osobiste zdjęcia czy filmy.&lt;&#x2F;p&gt;
&lt;p&gt;Jeśli to nie jest powód, żeby przestać opierać swoje funkcjonowanie w internecie o takie platformy społecznościowe, to ja nie wiem co nim jest. Oczywiście, kasowanie od razu całego swojego dobytku internetowego nie jest rozsądne, ale warto by było rozważyć opcję jakiegoś &lt;em&gt;backupu&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Skojarzył mi się przy tym od razu &quot;Tomasz Kopyra z blogu blog.kopyra.com&quot; - nawet jeśli straci swoje ostatnie konto internetowe, fani zawsze będą mogli znaleźć jego twórczość. A utrata domeny to już nie są przelewki, jak z Instagramem, Facebookiem czy Twitterem.&lt;&#x2F;p&gt;
&lt;p&gt;Ja swoje istnienie w internecie staram się zacementować tym śmiesznym blogiem, którego nikt nie czyta, bo nawet nikomu o nim nie powiedziałem.&lt;&#x2F;p&gt;
&lt;p&gt;Chyba czas ogarnąć RSSa.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=xmERFieaxCI&quot;&gt;The Longest Journey Soundtrack - 33 - Dragon&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Tłumaczone foldery na macOS</title>
        <published>2021-02-05T10:39:00+00:00</published>
        <updated>2021-02-05T10:39:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-02-05-tlumaczone-foldery-na-macos/"/>
        <id>https://mtsz.pl/blog/2021-02-05-tlumaczone-foldery-na-macos/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-02-05-tlumaczone-foldery-na-macos/">&lt;p&gt;Żeby dowolny folder na macOS miał przetłumaczoną nazwę, należy:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;dopisać do nazwy tego folderu końcówkę &lt;em&gt;&quot;.localized&quot;&lt;&#x2F;em&gt; - powinna zniknąć, bo jest czymś na kształt rozszerzenia&lt;&#x2F;li&gt;
&lt;li&gt;wewnątrz tego folderu stworzyć nowy folder o o nazwie &lt;em&gt;&quot;.localized&quot;&lt;&#x2F;em&gt; - powinien zniknąć, bo ma kropkę na początku, a to oznacza, że jest ukryty&lt;&#x2F;li&gt;
&lt;li&gt;wewnątrz nowoutworzonego folderu stworzyć pliki &lt;strong&gt;strings&lt;&#x2F;strong&gt; dla języków. Ja zawsze tworzę dla języka polskiego i angielskiego: &lt;em&gt;pl.strings&lt;&#x2F;em&gt; oraz &lt;em&gt;en.strings&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;w każdym z tych plików umieścić linijkę w następującej formie: &lt;code&gt;&quot;oryginalna nazwa folderu&quot; = &quot;przetłumaczona nazwa folderu&quot;;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;W moim przypadku, chciałem stworzyć sobie folder do przechowywania projektów programistycznych, który nazwałem &lt;em&gt;Development&lt;&#x2F;em&gt;. Chciałem też, żeby wyświetlał się jako folder &lt;em&gt;Programowanie&lt;&#x2F;em&gt;, bo tak mi się bardziej podoba. W moim przypadku plik &lt;em&gt;en.strings&lt;&#x2F;em&gt; zawiera linijkę: &lt;code&gt;&quot;Development&quot; = &quot;Development&quot;;&lt;&#x2F;code&gt;, a &lt;em&gt;pl.strings&lt;&#x2F;em&gt; zawiera linijkę: &lt;code&gt;&quot;Development&quot; = &quot;Programowanie&quot;;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Devblog[1]</title>
        <published>2021-01-28T12:34:56+00:00</published>
        <updated>2021-01-28T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-28-devblog-1/"/>
        <id>https://mtsz.pl/blog/2021-01-28-devblog-1/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-28-devblog-1/">&lt;p&gt;Zautomatyzowałem dzisiaj wgrywanie pliku GeoJSON na FTP Mapy Apostazji. Po co robić ciągle to samo, skoro można zautomatyzować.&lt;&#x2F;p&gt;
&lt;p&gt;Przy okazji natknąłem się na problem pt. &quot;jak ogarniać sekrety w projektach programistycznych, żeby nie wgrywać ich na serwer&quot;. Chciałbym mieć jakiś przyjemny, podręczny magazyn na hasła, adresy, loginy, identyfikatory itp., tak żebym mógł bez wyrzutów sumienia i strachu wrzucać kod na publiczne repo. macOS ma pęk kluczy, ale jest on o tyle ograniczony, że przechowuje hasło dla konkretnego serwisu oraz użytkownika. A te też chciałbym ukryć. Teraz przyszło mi na myśl, że można by to ukryć pakując w Secure Note w stylu: &lt;code&gt;identyfikator: login:hasło@serwis&lt;&#x2F;code&gt;. Niestety z tego co widzę, używana przeze mnie Pythonowa biblioteka &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jaraco&#x2F;keyring&quot;&gt;KeyRing&lt;&#x2F;a&gt; niekoniecznie obsługuje bezpieczne notatki. Na wszelki wypadek &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jaraco&#x2F;keyring&#x2F;issues&#x2F;488&quot;&gt;zapytałem&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Oprócz tego postanowiłem, że spróbuję pobawić się frameworkiem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aurelia.io&#x2F;&quot;&gt;Aurelia&lt;&#x2F;a&gt; i na nim postawić Mapę Apostazji. Internet twierdzi, że jest on bardzo prosty, mapa też jest bardzo prosta, więc integracja powinna być bardzo prosta. Trochę się jaram, a trochę się boję, bo jestem srogo uprzedzony do ogólnego WebDevelopmentu.&lt;&#x2F;p&gt;
&lt;p&gt;Słucham sobie również wykłady w ramach festiwalu &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wkontenerach.pl&#x2F;&quot;&gt;W Kontenerach&lt;&#x2F;a&gt;, i jako tako nadążam, chociaż ciężko znaleźć mi jakieś przypadki użycia, które mogłyby mi się przydać. Stawianie środowisk testowych w kontenerze super, ale na ten moment nie mam żadnych zasobów do tego, żeby to zrobić. Ani tym bardziej żadnych potrzeb. Ale oglądam, może nauczę się czegoś podświadomie.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Devblog[0]</title>
        <published>2021-01-18T12:34:56+00:00</published>
        <updated>2021-01-18T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-18-devblog-0/"/>
        <id>https://mtsz.pl/blog/2021-01-18-devblog-0/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-18-devblog-0/">&lt;p&gt;Zrobiłem dzisiaj tak dużo rzeczy, że chyba najlepiej będzie je opisać w formie dziennika. Jeśli kiedyś będę próbował odszukać informacje na tematy, o których tutaj napiszę, mój problem.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;custom-url-schemes-i-ios&quot;&gt;Custom URL schemes i iOS&lt;&#x2F;h1&gt;
&lt;p&gt;Pracując nad dokumentacją projektu dla klienta, dowiedziałem się, że umieszczając w aplikacji widok &lt;code&gt;SFSafariViewController&lt;&#x2F;code&gt;, a następnie klikając w nim na link ze schematem zarejestrowanym w tej aplikacji, nie pokazuje się okno popup z pytaniem, czy otworzyć tę aplikację. Jest to logiczne - już jesteśmy w tej aplikacji. Nie jest to intuicyjne, ponieważ WKWebView nie potrafi takich cudów, i trzeba nadpisywać delegata, żeby się dowiedzieć, co zostało kliknięte, a następnie przeanalizować to.&lt;&#x2F;p&gt;
&lt;p&gt;Tak sobie myślę, że użycie tego widoku Safari może i jest prostsze, ale za to mniej sportowe. Zintegrowanie Web View do tego samego nie jest dużo trudniejsze  - co najwyżej bardziej czasochłonne, ale też mamy dużo większą kontrolę. Za to na pewno jest bardziej &lt;em&gt;sportowe&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;mapa-z-wieloma-punktami&quot;&gt;Mapa z wieloma punktami&lt;&#x2F;h1&gt;
&lt;p&gt;Zdecydowałem, że wybiorę do implementacji Mapy Apostazji &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;leafletjs.com&#x2F;&quot;&gt;Leaflet&lt;&#x2F;a&gt;. Bo jest darmowy, a ma wszystkie możliwości, które są mi potrzebne.&lt;&#x2F;p&gt;
&lt;p&gt;Głównym problemem, który próbowałem rozwiązać, było straszne zacinanie mapy. Pierwsze pomysły, które przyszły mi do głowy, to klastrowanie oraz heat mapa. Niestety, żaden z tych pomysłów nie spełniał moich założeń. Klastrowanie gubiło informację o kolorze, a heatmapa po prostu rysowała gradienty. Ja miałem nadzieję na coś pokroju Airly.&lt;&#x2F;p&gt;
&lt;p&gt;Nie wiedziałem nawet, jak ugryźć temat, więc zacząłem od wyszukiwania i przeczesywania informacji na temat optymalizacji. Po chwili trafiłem na &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;domoritz&#x2F;leaflet-maskcanvas&quot;&gt;MaskCanvas&lt;&#x2F;a&gt;. Niewiele mi to mówiło, ale załadowanie wszystkich punktów do mapy - bez podziału na kolory - rozwiązało problem; mapa działała błyskawicznie. Tylko była jednokolorowa.&lt;&#x2F;p&gt;
&lt;p&gt;Podzieliłem więc punkty na trzy grupy (żeby móc je pokolorować na różne kolory), dodałem do osobnych warstw, a te do mapy. Niestety płynność spadła. Było i tak o niebo lepiej od pierwowzoru, ale to nadal nie było to, co chciałem. Poza tym, punktów będzie tylko przybywać, więc problem tylko by narastał. Szukałem dalej.&lt;&#x2F;p&gt;
&lt;p&gt;W końcu jednak natrafiłem na rozwiązanie zawarte już w samym Leaflet - &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;leafletjs.com&#x2F;reference-1.7.1.html#circlemarker&quot;&gt;CircleMarker&lt;&#x2F;a&gt;. Po doszukaniu informacji dowiedziałem się, że standardowe dodawanie punktów do mapy tworzy dla każdego punktu osobny element DOM, więc 500 punktów to 500 elementów DOM, a z tyloma elementami przeglądarka niekoniecznie chce sobie poradzić. CircleMarker dodaje się za to do płótna mapy (&lt;code&gt;canvas&lt;&#x2F;code&gt;), więc nie ma ani jednego nowego obiektu DOM, a samo przerysowywanie punktów jest błyskawiczne. Każdy punkt jest osobnym bytem, więc można mu nadać dowolny kolor. Jest także klikalny, więc bez problemu będzie można zaimplementować wyświetlenie szczegółów.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;panel-ze-szczegolami&quot;&gt;Panel ze szczegółami&lt;&#x2F;h1&gt;
&lt;p&gt;Tutaj poszło trochę szybciej. Potrzebowałem bocznego panelu do wyświetlenia informacji o klikniętym punkcie. Znalazłem &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Turbo87&#x2F;leaflet-sidebar&quot;&gt;Leaflet Sidebar&lt;&#x2F;a&gt;. Działa całkiem dobrze. Jedyny problem miałem z chowaniem panelu po kliknięciu na mapę, ponieważ kliknięcie markera wywoływało jednocześnie event kliknięcia mapy. Na szczęście &lt;code&gt;CircleMarker&lt;&#x2F;code&gt; ma parametr o wszystkomówiącej nazwie &lt;code&gt;bubblingMouseEvents&lt;&#x2F;code&gt;, więc żeby chowanie panelu działało poprawnie, wystarczyło wyłączyć &lt;em&gt;bąbelkowanie wydarzeń myszki&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;horyzonty&quot;&gt;Horyzonty&lt;&#x2F;h1&gt;
&lt;p&gt;Dzisiaj zdałem sobie też sprawę z tego, że nieświadomie mocno poszerzyłem swoje horyzonty. Na potrzeby projektu Mapa Apostazji napisałem skrypt w Pythonie, zrobiłem stronę w HTML, ostylowałem w CSS, teraz uczę się map Leaflet, wykresów Charts i ogólnie JavaScriptu, nawet silnik do bloga napisałem przy użyciu PHP.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Będę miał do portfolio xD&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Sortowanie w Everli</title>
        <published>2021-01-15T23:11:00+00:00</published>
        <updated>2021-01-15T23:11:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-15-sortowanie-w-everli/"/>
        <id>https://mtsz.pl/blog/2021-01-15-sortowanie-w-everli/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-15-sortowanie-w-everli/">&lt;p&gt;Po tym, jak Tesco wyprowadziło się z Krakowa, musiałem znaleźć alternatywny sklep do zamawiania zakupów przez internet. Po krótkich poszukiwaniach natrafiłem na Everli. Everli przypomina działaniem Glovo - jest to platforma kojarząca sklepy spożywcze z kurierami chętnymi dostarczać zakupy. Sklepów jest kilka, więc w teorii jest nawet lepiej, niż było w Tesco.&lt;&#x2F;p&gt;
&lt;p&gt;Problem z aplikacją Everli jest taki, że nie pozwala sortować produktów po cenach. Wpisuję w wyszukiwarkę &quot;mleko&quot;, i widzę wyniki w losowej kolejności. Postanowiłem rozwiązać ten problem przy użyciu JavaScriptu i &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.tampermonkey.net&#x2F;&quot;&gt;Tampermonkey&lt;&#x2F;a&gt;. Dla tych, co nie wiedzą - Tampermonkey to wtyczka do Chrome&#x27;a, która pozwala wykonać kod JavaScript na kodzie właśnie ładowanej strony.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwszy krok to podejrzenie ruchu strony Everli za pomocą inspektora przeglądarki.&lt;&#x2F;p&gt;
&lt;p&gt;Taka ciekawostka: Everli ma jakąś dziwaczną zależność renderowania strony z autoryzacją. Włączając inspektora, zmienia się rozmiar okna przeglądarki, więc strona przechodzi w tryb mobilny. Następne kliknięcie w cokolwiek na stronie wywala mnie na ekran logowania. Zostałem wylogowany, zmieniając rozmiar okienka...&lt;&#x2F;p&gt;
&lt;p&gt;Wracając. Interesują nas dwa rodzaje interakcji, których wyniki chcemy posortować: wyszukiwanie oraz wybór kategorii.&lt;&#x2F;p&gt;
&lt;p&gt;Po wpisaniu do wyszukiwarki hasła &quot;mleko&quot;, strona przechodzi na adres&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;https:&#x2F;&#x2F;pl.everli.com&#x2F;s#&#x2F;locations&#x2F;21674&#x2F;stores&#x2F;6027&#x2F;search&#x2F;mleko&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;W inspektorze zauważam zapytanie na adres API&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;https:&#x2F;&#x2F;api.everli.com&#x2F;sm&#x2F;api&#x2F;v3&#x2F;locations&#x2F;21674&#x2F;stores&#x2F;6027&#x2F;search?q=mleko&amp;amp;skip=0&amp;amp;take=40&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Po wybraniu kategorii &quot;Nabiał i jaja -&amp;gt; Mleko i śmietana&quot;, strona przechodzi na adres&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;https:&#x2F;&#x2F;pl.everli.com&#x2F;s#&#x2F;locations&#x2F;21674&#x2F;stores&#x2F;6027&#x2F;categories&#x2F;100852&#x2F;101270&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;W inspektorze zauważam zapytanie na adres API&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;https:&#x2F;&#x2F;api.everli.com&#x2F;sm&#x2F;api&#x2F;v3&#x2F;locations&#x2F;21674&#x2F;stores&#x2F;6027&#x2F;categories&#x2F;101278&#x2F;101280?skip=0&amp;amp;take=40&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Te dwa zapytania API są tutaj kluczowe. To one zwracają listę produktów w postaci JSONa. Dlatego nasz skrypt będzie wyczekiwał tylko ich, a całą resztę ignorował. Stwórzmy funkcję, ktora sprawdzi, czy to właśnie te zapytania są wykonywane.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;javascript&quot;&gt;function isSearchOrCategories(URL) {
    var apiRegex = new RegExp(
        &amp;quot;https:&#x2F;&#x2F;api.everli.com&#x2F;sm&#x2F;api&#x2F;v3&#x2F;locations&#x2F;[0-9]+&#x2F;stores&#x2F;[0-9]+&#x2F;&amp;quot;),
        searchRegex = new RegExp(&amp;quot;&#x2F;search[^&#x2F;]&amp;quot;),
        categoriesRegex = new RegExp(&amp;quot;&#x2F;categories&#x2F;[0-9]+&#x2F;[0-9]+[^&#x2F;]&amp;quot;);
    var isApi = apiRegex.test(URL),
        isSearch = searchRegex.test(URL),
        isCategories = categoriesRegex.test(URL);
    return isApi &amp;amp;&amp;amp; (isSearch || isCategories);
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Idźmy dalej. Odpowiedź na obydwa zapytania zawiera listę produktów, która jest wyświetlana zgodnie z kolejnością, w jakiej przyszła. Naszym celem jest przechwycenie tej odpowiedzi, zmodyfikowanie jej - czyli posortowanie, i zwrócenie jej z powrotem przeglądarce.&lt;&#x2F;p&gt;
&lt;p&gt;Przyjrzyjmy się strukturze odpowiedzi. Są one gigantyczne i pozbawione formatowania, dlatego formatuję je w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jsonformatter.curiousconcept.com&#x2F;#&quot;&gt;JSON Formatterze&lt;&#x2F;a&gt;. Do analizy potrzebuję tylko listy produktów - resztę ignoruję.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;json&quot;&gt;{
  &amp;quot;data&amp;quot;:{
    &amp;quot;body&amp;quot;:[
      {
        &amp;quot;widget_type&amp;quot;:&amp;quot;vertical-list&amp;quot;,
        &amp;quot;list&amp;quot;:[
          {
            &amp;quot;widget_type&amp;quot;:&amp;quot;product&amp;quot;,
            &amp;quot;name&amp;quot;:&amp;quot;Łaciate Mleko Uht 2,0%&amp;quot;,
            &amp;quot;price&amp;quot;:&amp;quot;2,79 zł&amp;quot;,
            &amp;quot;price_per_type&amp;quot;:&amp;quot;2,79 zł&#x2F;l&amp;quot;
          }
        ]
      }
    ]
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Żeby dostać się do listy produktów, musimy z obiektu &lt;code&gt;data&lt;&#x2F;code&gt; pobrać listę &lt;code&gt;body&lt;&#x2F;code&gt;, następnie odszukać obiekt, dla którego pole &lt;code&gt;widget_type&lt;&#x2F;code&gt; ma wartość &lt;code&gt;vertical-list&lt;&#x2F;code&gt;*, i dla tego obiektu posortować elementy listy &lt;code&gt;list&lt;&#x2F;code&gt; na podstawie pól &lt;code&gt;price&lt;&#x2F;code&gt; oraz &lt;code&gt;price_per_type&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Tutaj natknąłem się na pierwszy problem. W pierwotnym rozwiązaniu pobrałem po prostu pierwszy element z listy &lt;code&gt;body&lt;&#x2F;code&gt;, zakładając że jest tam zawsze tylko jeden element. Było to błędne założenie, ponieważ przy wyborze kategorii, na tej liście znajduje się jeszcze element &lt;code&gt;breadcrumbs&lt;&#x2F;code&gt;, i jest on właśnie jako pierwszy. Stąd konieczność wyszukania elementu na podstawie wartości pola &lt;code&gt;widget_type&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Oto funkcja, która wyciąga nam cenę z obiektu produktu.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;javascript&quot;&gt;const priceRegex = &#x2F;^\d+,\d{2}&#x2F;;

function getPrice(product) {
    var pricePerTypeMatch = product.price_per_type.match(priceRegex);
    if (pricePerTypeMatch != null) {
        var pricePerTypeString = pricePerTypeMatch[0].replace(&#x2F;,&#x2F;g, &amp;quot;.&amp;quot;);
        return parseFloat(pricePerTypeString);
    }
    var priceMatch = product.price.match(priceRegex);
    if (priceMatch != null) {
        var priceString = priceMatch[0].replace(&#x2F;,&#x2F;g, &amp;quot;.&amp;quot;);
        return parseFloat(priceString);
    }
    return 99999;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Teraz napiszmy funkcję, która otrzyma obiekt odpowiedzi na zapytanie API, odpowiednio go zmodyfikuje, i zwróci w takiej samej formie.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;javascript&quot;&gt;function sortProductsInPayload(payload) {
    var verticalListPredicate = function (bodyObject) {
        return bodyObject.widget_type === &amp;quot;vertical-list&amp;quot;;
    }
    var productPriceSort = function (a, b) {
        return getPrice(a) - getPrice(b);
    }
    var verticalListWidget = payload.data.body.find(verticalListPredicate);
    verticalListWidget.list.sort(productPriceSort);
    return payload
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Na sam koniec dodajemy kod, który przechwytuje zapytania, następnie modyfikuje odpowiedź, używając wcześniejszych funkcji, i zwraca podmienioną odpowiedź przeglądarce.&lt;&#x2F;p&gt;
&lt;p&gt;Przyznaję, że ten kod po prostu znalazłem w internecie - nie jestem pewien, jak on działa, nie znam w ogóle przeglądarkowych SDK ani JavaScriptu. Ale działa, i na ten moment to mi wystarczy.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;javascript&quot;&gt;var _open = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, URL) {
    var _onreadystatechange = this.onreadystatechange,
        _this = this;
    _this.onreadystatechange = function () {
        &#x2F;* USER SCRIPT GOES HERE *&#x2F;
        if (isSearchOrCategories(URL) &amp;amp;&amp;amp; _this.readyState == 4) {
            var payload = JSON.parse(_this.responseText);
            var sortedPayload = sortProductsInPayload(payload);
            var sortedString = JSON.stringify(sortedPayload);
            Object.defineProperty(_this, &amp;quot;responseText&amp;quot;, { value: sortedString });
        }
        &#x2F;* USER SCRIPT ENDS HERE *&#x2F;
        if (_onreadystatechange) _onreadystatechange.apply(this, arguments);
    };
    Object.defineProperty(this, &amp;quot;onreadystatechange&amp;quot;, {
        get: function () { return _onreadystatechange; },
        set: function (value) { _onreadystatechange = value; },
    });
    return _open.apply(_this, arguments);
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nie zapomnijmy też o nagłówku Tampermonkey, inaczej wtyczka będzie narzekać, że nie może sparsować kodu.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&#x2F;&#x2F; ==UserScript==
&#x2F;&#x2F; @name        Everli Sort
&#x2F;&#x2F; @author      mtsz
&#x2F;&#x2F; @description Sort Everli search&#x2F;categories response
&#x2F;&#x2F; @match       *:&#x2F;&#x2F;*.everli.com&#x2F;*
&#x2F;&#x2F; @version     1.0
&#x2F;&#x2F; @grant       none
&#x2F;&#x2F; ==&#x2F;UserScript==
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Gotowe. Funkcja sortowania w Everli dodana. Teraz wystarczy dodać skrypt do Tampermonkey, i cieszyć się z nowych możliwości portalu.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Alternatywny AppStore</title>
        <published>2021-01-13T17:49:00+00:00</published>
        <updated>2021-01-13T17:49:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-13-alternatywny-appstore/"/>
        <id>https://mtsz.pl/blog/2021-01-13-alternatywny-appstore/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-13-alternatywny-appstore/">&lt;p&gt;Biorąc pod uwagę, co się ostatnio wyprawia w świecie cyfrowym w kontekście przekazania prezydentury przez Donalda Trumpa (ban tegoż na Twitterze, Facebooku, YouTubie, skasowanie Parlera z serwerów Amazona, wywalenie aplikacji Parler z Apple AppStore i Google Play Store), warto wiedzieć o alternatywnych sposobach dogrywania aplikacji, bezpośrednio z pliku.&lt;&#x2F;p&gt;
&lt;p&gt;W przypadku Androida jest to proste. Ustawienia systemu zawierają opcję zezwalającą na instalację z &quot;nieznanych źródeł&quot; - wystarczy ją włączyć, i możemy spokojnie wgrywać, co chcemy. Istnieją już nawet alternatywne aplikacje-sklepy oraz repozytoria (np. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;f-droid.org&#x2F;&quot;&gt;F-Droid&lt;&#x2F;a&gt; czy &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;obtainium.imranr.dev&#x2F;&quot;&gt;Obtainium&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;W przypadku iOSa nie jest tak pięknie. Nie ma domyślnego sposobu na wgrywanie dowolnej aplikacji. Istnieje co prawda możliwość zbudowania aplikacji tak, aby dało się ją zainstalować z pliku, ale wymagają one aktywnej pracy twórcy takiej aplikacji. Może on albo skompilować ją w trybie Enterprise, co oznacza, że aplikację można zainstalować z pliku, ale taka licencja kosztuje tego programistę 200 dolarów rocznie i jest ograniczona do bodajże 10 tysięcy instalacji. Może też użyć kompilacji In-House, czyli na sztywno w aplikacji zaszyć identyfikator urządzenia, na którym uruchomimy aplikację, dzięki czemu będzie ona działać po instalacji z pliku - ale tylko na tych urządzeniach, których identyfikatory są zaszyte. A ich liczba jest ograniczona i wynosi 200 urządzeń.&lt;&#x2F;p&gt;
&lt;p&gt;Niektórzy próbują aplikacje wrzucać na TestFlight - to platforma Apple&#x27;a do publiwania aplikacji w wersji testowej - i dystrybuować w ten sposób. Istnieje nawet ich repozytorium, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;departures.to&#x2F;&quot;&gt;Departures&lt;&#x2F;a&gt;. Założenie jest takie, że przegląd aplikacji w TestFlight jest mniej skrupulatny, niż w przypadku publikacji do AppStore, więc teoretycznie mogą się tam pojawić aplikacje, które w sklepie by się nie znalazły. Jednak we wspomnianym na początku przypadku Parlera, raczej wątpliwe jest, żeby Apple dopuściło aplikację do tego etapu.&lt;&#x2F;p&gt;
&lt;p&gt;Na szczęście pozostaje nam jeszcze jedna opcja - &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;altstore.io&#x2F;&quot;&gt;AltStore&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;AltStore korzysta z uprzejmości, jaką Apple zrobiło programistom iOSa, którzy nie posiadają wykupionego programu developerskiego. Dzięki tej urzejmości, mają oni możliwość budowania, podpisywania oraz uruchamiania tworzonych przez siebie aplikacji na swoim urządzeniu z iOSem przez tydzień. Aplikacja, którą zbudują sobie bezpośrednio w Xcode na iPhone&#x27;ie podpiętym kablem do komputera, będzie działać przez 7 dni, a następnie jej podpis wygaśnie, i przestanie się ona uruchamiać.&lt;&#x2F;p&gt;
&lt;p&gt;Twórca AltStore sprytnie wykorzystał ten mechanizm. Stworzył aplikację, która pozwala na ponowne podpisywanie aplikacji, dzięki czemu będzie ona działać... w teorii wiecznie.&lt;&#x2F;p&gt;
&lt;p&gt;Szczegóły techniczne są dobrze opisane na stronie projektu, ale w skrócie działa to tak, że używając swojego Apple ID, udajemy programistę, który właśnie stworzył aplikację, i chce ją wgrać na telefon. Tyle że ta aplikacja wcale nie musi być stworzona przez nas, ani nie musi być stworzona &quot;właśnie teraz&quot;. Co więcej, mechanizm wgrywania aplikacji na iOSie sprawia, że nie tracimy żadnych danych - po prostu plik wykonywalny podmieniany jest nową wersją ze zaktualizowanym certyfikatem.&lt;&#x2F;p&gt;
&lt;p&gt;Sam projekt ma swoje repozytorium aplikacji, ale w tym momencie są tam jedynie dwie: Delta - emulator starych konsol, oraz Clip - menadżer schowka. Na szczęście twórca dodał możliwość instalowania dowolnego innego programu. Wystarczy plik w formacie &lt;code&gt;*.ipa&lt;&#x2F;code&gt; skopiować na dysk urządzenia (np. korzystając z synchronizacji iCloud Drive), a następnie dodać aplikację w AltStore. AltStore, we współpracy z AltServerem oraz klientem poczty Apple Mail, podpisze aplikację i zainstaluje ją na telefonie. Na liście aplikacji zobaczymy, ile czasu zostało do wygaśnięcia aplikacji, i jedyne co musimy zrobić, to kliknąć licznik dni zanim się wyzeruje, aby podpisać aplikację ponownie, i korzystać z niej dalej.&lt;&#x2F;p&gt;
&lt;p&gt;Rozwiązanie nie jest oczywiście idealne. Opiera się na możliwości podpisywania aplikacji przez de facto kogokolwiek na te 7 dni, i w związku z tym wymaga od nas ciągłej uwagi. Ale pomijając te niedogodności, rozwiązanie wydaje się nienajgorsze. W ten sposób możemy zainstalować na iOSa praktycznie dowolną aplikację.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Jak chciałem zostać pilotem</title>
        <published>2021-01-10T00:11:00+00:00</published>
        <updated>2021-01-10T00:11:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-10-jak-chcialem-zostac-pilotem/"/>
        <id>https://mtsz.pl/blog/2021-01-10-jak-chcialem-zostac-pilotem/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-10-jak-chcialem-zostac-pilotem/">&lt;p&gt;O wojsku jako realnej opcji na przyszłość pierwszy raz pomyślałem gdzieś w okolicach końca gimnazjum, gdy Grzesiek Bajerski, z którym trenowałem wtedy Sambo Systema, zaproponował, żebyśmy poszli do liceum o profilu wojskowym. Wtedy potoczyło się to inaczej i trafiłem do liceum ogólnokształcącego, ale idea pozostała gdzieś z tyłu głowy.&lt;&#x2F;p&gt;
&lt;p&gt;Nie minęły trzy lata, a pomysł powrócił, tym razem dużo bardziej sprecyzowany. Wyższa Szkoła Oficerska Sił Powietrznych w Dęblinie, specjalność: pilot bojowego samolotu odrzutowego. Przeczytałem gigantyczny temat na forum lotniczym na temat rektutacji do WSOSP. Rekrutacja na uczelnie wojskowe zaczyna się dużo wcześniej, niż na cywilne, a to z powodu badań, które trzeba przejść. Wszystko sobie rozplanowałem, zgromadziłem tyle pieniędzy, ile tylko mogłem, i wysłałem wniosek o przyjęcie na uczelnię.&lt;&#x2F;p&gt;
&lt;p&gt;Minęło kilka tygodni i dostałem pierwszy list ze skierowaniem na wstępne badania, które przechodzi każdy kandydat na żołnierza. Badania miały miejsce w szpitalu wojskowym przy ul. Wrocławskiej w Krakowie. Było ich trochę, i nie udało mi się ukończyć wszystkich jednego dnia, dlatego musiałem z mojego rodzinnego miasta, Nowego Sącza, jeździć dwa razy. Wynik badania: zdolny. Teraz musiałem poczekać na zaproszenie na badania do Dęblina. Przyszło ono jakiś tydzień później.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;2-marca-2009&quot;&gt;2 marca 2009&lt;&#x2F;h1&gt;
&lt;p&gt;Do Dęblina pojechałem pociągiem z Krakowa przez Warszawę. Na miejsce specjalnie przyjechałem dzień wcześniej, żeby porządnie wyspać się przed badaniami, które jak przeczytałem na forum, można było łatwo oblać właśnie przez takie trywialne na pierwszy rzut oka rzeczy.&lt;&#x2F;p&gt;
&lt;p&gt;Na miejscu byłem wczesnym popołudniem - byłem pierwszym kandydatem na miejscu - więc trochę pokręciłem się po samej bazie. Po jakimś czasie pokazali się kolejni kandydaci, miałem okazję poznać wszystkich, którzy do Dęblina startowali razem ze mną.&lt;&#x2F;p&gt;
&lt;p&gt;Byli to świetni ludzie. Większość z nich to byli synowie żołnierzy, oficerów, generałów. Doskonale wiedzieli, czego chcą, po co tutaj przyjechali, byli jednocześnie bardzo podekscytowani i przyjacielsko nastawieni. Wszystkim nam udzielał się bardzo optymistyczny nastrój.&lt;&#x2F;p&gt;
&lt;p&gt;Relację z mojego badania w Dęblinie opisałem na forum lotniczym. Poniżej znajduje się jej dłuższa wersja w formie cytatów - rozwinięta o to, co pamiętam dzisiaj i o czym warto wspomnieć poza kontekstem rekrutacyjnym.&lt;&#x2F;p&gt;
&lt;p&gt;Źródło: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lotnictwo.net.pl&#x2F;10-lotnictwo_wojskowe&#x2F;114-lotnictwo_wojskowe_tematy_ogolne&#x2F;7438-wsosp-38.html#post256941&quot;&gt;http:&#x2F;&#x2F;lotnictwo.net.pl&#x2F;10-lotnictwo_wojskowe&#x2F;114-lotnictwo_wojskowe_tematy_ogolne&#x2F;7438-wsosp-38.html#post256941&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;Mały opis badań (i innych procedur) w WKLL w Dęblinie dla zainteresowanych (w środku porady)&lt;&#x2F;p&gt;
&lt;p&gt;Okej, więc badania trwają 3 dni. Z Warszawy pociągi jeżdżą dość często do Dęblina (średnio co 2 godziny). Po przyjeździe od razu &#x2F;kierujemy się do&#x2F; do taksówki pod dworcem PKP (jeden z gości zabierze Was pod WSOSP za 10zł - inni biorą podobno 20zł - pytajcie). Prosicie go, żeby podwiózł was pod bramę WSOSP od strony szpitala – stamtąd łatwiej jest dostać się do hotelu, w którym będziecie mieszkać (&quot;IKAR&quot;). Wysiadacie z taksówki i idziecie prosto do bramy WSOSP (jeśli zatrzyma was strażnik mówicie po co przyszliście – czyli że na badania), przechodzicie przez bramę i idziecie cały czas PROSTO (będzie z kilometr), aż dojdziecie do dwóch dość reprezentatywnych budynków z napisem „Dedal&quot; i „Ikar&quot; (gratka dla przezornych).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Są to hotele przeznaczone dla rodzin żołnierzy i innych odwiedzających. Zbudowane z piaskowca, pomalowane na biało - robią imponujące wrażenie. Wystrój pokoi bardzo elegancki jak na hotel za 50 zł oraz jak na hotel wojskowy.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Meldujecie się, zostawiacie dowód i marnujecie resztę dnia, gdyż badania zaczynają się jutro. Możecie pozwiedzać ośrodek, żeby się zorientować gdzie jest co.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sam Dęblin jest bardzo małym i bardzo zwykłym miasteczkiem. Można tam spokojnie spędzić starość - no, wyjmując to, że co chwila startują odrzutowce i inne samoloty. Imponujący jest pomnik stojący u bramy głównej WSOSP: &quot;bohaterskim lotnikom dęblińskiej szkoły orląt&quot; - głosi napis.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tutaj bardzo ważna uwaga&lt;&#x2F;strong&gt;. Niech się komuś z Was nie zamarzy się czegoś napić (w sensie alkoholu) albo zażerać się słodyczami. Pierwsze badanie jakie was czeka następnego dnia to laboratorium. Przez to że goście żarli batony w poniedziałek wieczorem, mieli na morfologii podwyższony cukier – i dupa, bo muszą dosyłać wyniki i nie dostają od razu kategorii z1a.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Kategoria Z1A to najwyższa kategoria zdrowotna, uprawniająca do latania właściwie czymkolwiek, czym dysponuje Wojsko Polskie.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Następnego dnia wstajemy wcześnie (o godzinie 7:00 mamy być w budynku „Iskra&quot; - poszukajcie sobie wczoraj), nic nie jemy na śniadanie.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Iskra to internat dla żołnierzy-studentów. Spotkanie przed badaniami ma miejsce w sali na parterze.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Po briefingu prowadzonego przez majora odpowiedzialnego za rekrutację będziecie chodzili za wyznaczonym żołnierzem, który pomoże wam w pierwszym dniu z badaniami.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Z tym żołnierzem w końcu nie było tak kolorowo, bo po tym, jak odprowadził nas do szpitala, gdzieś sobie poszedł. Ale to nie był żaden problem, bo wszystkie badania były dokładnie rozpisane - nie potrzebowaliśmy niańki.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;3-marca-2009&quot;&gt;3 marca 2009&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Dzień 1:&lt;br &#x2F;&gt;
&lt;em&gt;Laboratorium&lt;&#x2F;em&gt; – morfologia krwi i moczu – zwykłe badanie zawartości krwi i moczu (tutaj ulewają za ten cukier po słodyczach z poprzedniego dnia – no chyba że ktoś faktycznie ma cukrzycę, tylko o tym nie wie, oraz za mitologiczną bilirubinę – co to jest, nie mam pojęcia, jeśli ktoś wie, może napisać)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Większość bilirubiny powstaje na skutek niszczenia starych erytrocytów, jej podwyższona zawartość może oznaczać problemy z wątrobą. Można niskim kosztem niechcący podnieść sobie jej poziom - na przykład intensywnie uprawiając sport. Łatwo jest też ją zbić - wystarczy przestać uprawiać sport.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Neurolog&lt;&#x2F;em&gt; – stanie na jednej nodze, stanie na palcach, dotykanie nosa palcem wskazującym z zamkniętymi oczyma i inne tego typu rozrywki.&lt;br &#x2F;&gt;
&lt;em&gt;Laryngolog&lt;&#x2F;em&gt; – tutaj pan doktor wkłada do ucha lunetę i patrzy, czy nie ma pęknięć (odpadają ci po zapaleniu ucha tudzież innych), niektórzy muszą przeczytać kawałek tekstu (seplenienie i inne wady mogą zdyskwalifikować)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Lekarz na początku każe się przedstawić, i na tej podstawie stwierdza, czy ktoś sepleni czy ma problemy z wypowiadaniem litery &#x27;r&#x27;. Zastanawiałem się, jakie to ma w ogóle znaczenie, czy ktoś sepleni, w końcu mnie oświeciło: w lotnictwie komunikacja słowna jest bardzo istotna, więc wszelkie wady wymowy z automatu dyskwalifikują.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Okulista&lt;&#x2F;em&gt; – najpierw klasyczna tablica i badanie na daltonizm, potem test na zeza (takie proste celowanie) oraz test dna oka (zakrapianie do syntetycznego rozszerzenia źrenic i oglądanie choinki). Podobno RedBull lub inne poprawia ostrość wzroku - ja nie widziałem różnicy, ale możecie się napić pół godziny przed.&lt;br &#x2F;&gt;
&lt;em&gt;RTG&lt;&#x2F;em&gt; klatki piersiowej (jeśli ktoś nie miał na TWKL), zatok i kręgosłupa – zwykła, radioaktywna sesja zdjęciowa&lt;br &#x2F;&gt;
&lt;em&gt;Audiogram&lt;&#x2F;em&gt; – powtórka z TWKL&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Zamykają cię w wygłuszonym pomieszczeniu, masz słuchawki na głowie oraz dwa przyciski w dłoniach. Do pojedynczej słuchawki puszczany jest bardzo cichy dźwięk o wysokiej częstotliwości, a ty, jak tylko go usłyszysz, naciskasz odpowiedni guzik.&lt;&#x2F;p&gt;
&lt;p&gt;Da się tutaj niestety trochę oszukiwać, bo wystąpienia dźwięków są w miarę regularne. Jednak w moim przypadku te badania były miarodajne - miałem doskonały słuch.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Próby obrotowe&lt;&#x2F;em&gt; – ciekawe badanie, najpierw kręcimy się na krześle z zamkniętymi oczyma względnie wolno, dotykając uchem powoli raz lewego raz prawego ramienia, po chwili wstajemy i mamy utrzymać równowagę.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Tutaj kombinowano, ubierając buty na twardej i szerokiej podeszwie, które mocno stabilizowały postawę. Sam miałem z tym delikatne problemy i uratowała mnie zimowo-wiosenna kolekcja obuwia.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;EKG - klasyk&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Podpinają cię pod milion elektrod i badają serce.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pomiary (wzrost + waga) – my tego nawet nie mieliśmy.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Pozycja znajdowała się jednak na karcie obiegowej (czyli tej z listą badań, salami i dniami).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;4-marca-2009&quot;&gt;4 marca 2009&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Dzień 2:&lt;br &#x2F;&gt;
&lt;em&gt;Stomatolog&lt;&#x2F;em&gt; – czyli klasyczne badanie zębów. &lt;strong&gt;Wyleczcie zęby&lt;&#x2F;strong&gt; - kilka osób poleciało na poprawę po tym.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Oczywiście moje połamane i sztuczne zęby w niczym nie przeszkodziły - chodzi o to, żebyś się nie udławił swoją plombą podczas dużych przeciążeń.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;EEG&lt;&#x2F;em&gt; – to badanie fal mózgowych. Dostajecie silikonowy czepek na głowę, podłącza się was milionem kabli do komputera i macie zamykać i otwierać oczy na rozkaz – uważajcie, kobieta wie, że ruszacie gałami nawet jak macie zamknięte oczy – straszliwie się wk...ia (przepraszam za mowę staropolską). Polecana gorzka czekolada i jogurt przed.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Nie wiem jakie jest uzasadnienie takiej diety.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Chirurg&lt;&#x2F;em&gt; - nic specjalnego, przysłowiowe &quot;jaja na chochelkę&quot;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;O ile dobrze pamiętam, sprawdzał takie rzeczy jak płaskostopie czy proste plecy.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Echo-2D serca&lt;&#x2F;em&gt; – takie przyjemne badanie z żelem w roki głównej&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Lekarz miał na ekranie skan serca oraz dźwięk! Brzmiało to co najmniej nieprzyjemnie, ale tak właśnie wyobrażam sobie, że brzmi serce - jak jakaś obrzydliwa pompka do lepkiej cieczy. Dowiedziałem się, że mam śladową niedomykalność zastawki trójdzielnej bez znaczenia hemodynamicznego - ot, taki pieprzyk na sercu.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;5-marca-2009&quot;&gt;5 marca 2009&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Dzień 3:&lt;br &#x2F;&gt;
&lt;em&gt;KNC&lt;&#x2F;em&gt; (komora niskich ciśnień) – badanie ma na celu sprawdzenie reakcji organizmu na niskie ciśnienie. Sama komora wygląda przerażająco ale bez obaw. Weźcie jakieś cukierki do środka - przyda się wzmożona praca ślinianek&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Przełykanie powoduje wyrównanie ciśnienia w uchu, dzięki czemu nie ma się tego okropnego uczucia, podobnego do uczucia zatkanego wodą ucha&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Internista&lt;&#x2F;em&gt; – lekarz ogólny, który na podstawie wyników przypisuje wam kategorię Z1A OCZYWIŚCIE!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Dostałem wtedy kategorię &lt;strong&gt;Z1A&lt;&#x2F;strong&gt; - najwyższą możliwą. Radość moja była nieskończona, dopóki nie poszedłem na badania psychologiczne do WKU w Nowym Sączu, gdzie pani psycholog stwierdziła - albo raczej uświadomiła mi - że nie chcę być żołnierzem; że nie chcę poświęcić swojego życia służbie.&lt;&#x2F;p&gt;
&lt;p&gt;Cóż, miała rację. Nie chciałem być żołnierzem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Chciałem latać odrzutowcami.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Mapa Apostazji welcome to</title>
        <published>2021-01-09T12:34:56+00:00</published>
        <updated>2021-01-09T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2021-01-09-mapa-apostazji-welcome-to/"/>
        <id>https://mtsz.pl/blog/2021-01-09-mapa-apostazji-welcome-to/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2021-01-09-mapa-apostazji-welcome-to/">&lt;p&gt;Dzień dobry. Kilka dni temu odpaliłem swój pierwszy, autorski projekt: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mapaapostazji.pl&#x2F;&quot;&gt;Mapa apostazji&lt;&#x2F;a&gt;. Jestem z niego bardzo zadowolony. Codziennie wrzucam jakieś minimalne ulepszenia, na bieżąco aktualizuję listę wpisów, które zbieram poprzez Formularz Google. Całość stworzyłem samodzielnie, korzystając z dostępnych mi darmowych narzędzi. Oprócz domeny, za którą zapłaciłem 12 zł.&lt;&#x2F;p&gt;
&lt;p&gt;Do stworzenia projektu użyłem następujących elementów:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;umap.openstreetmap.fr&#x2F;pl&#x2F;&quot;&gt;uMap&lt;&#x2F;a&gt; - darmowe narzędzie, pozwalające na mapy &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;openstreetmap.org&#x2F;&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt; umieszczać swoje własne elementy&lt;&#x2F;li&gt;
&lt;li&gt;własnoręcznie napisaną stronę w HTMLu oraz styl CSS - inspirowałem się tym ze strony &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.licznikapostazji.pl&quot;&gt;Licznik Apostazji&lt;&#x2F;a&gt;, ale ostatecznie bardzo mocno go okroiłem, i właściwie jedyne, co zostało, to styl dla hiperłączy oraz czcionka (których używam też tutaj)&lt;&#x2F;li&gt;
&lt;li&gt;domenę zakupioną w &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ovh.pl&#x2F;&quot;&gt;OVH&lt;&#x2F;a&gt; za 12 zł&#x2F;rok oraz przydzielony do niej darmowy hosting 10 MB;&lt;&#x2F;li&gt;
&lt;li&gt;formularz z Formularze Google&#x27;a, którym zbieram dane dotyczące apostazji&lt;&#x2F;li&gt;
&lt;li&gt;skrypt w Pythonie, który konwertuje dane wyeksportowane z formularza w postaci pliku CSV, do formatu pośredniego, w którym wyszukuję i obsługuję duplikaty i różne błędy (niepoprawne adresy, nazwy, złe lokalizacje), a następnie konwertuję ostatecznie do formatu GeoJSON, który wygrywam do uMapa.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Strona jest minimalistyczna, nie śledzi użytkownika, nie zbiera danych osobowych, nie ma reklam. Jest prawie idealna. To, co pozostało, to zaimplementowanie własnej mapy, np. w oparciu o &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;leafletjs.com&#x2F;&quot;&gt;Leaflet&lt;&#x2F;a&gt;, tak, żebym nawet na uMapie nie musiał polegać. Ale to zajmie trochę więcej czasu, więc na razie się tym nie przejmuję.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Spalone powietrze</title>
        <published>2020-09-10T12:34:56+00:00</published>
        <updated>2020-09-10T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2020-09-10-spalone-powietrze/"/>
        <id>https://mtsz.pl/blog/2020-09-10-spalone-powietrze/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2020-09-10-spalone-powietrze/">&lt;p&gt;Ciekawostka na dziś:&lt;&#x2F;p&gt;
&lt;p&gt;Wodór jest najczystszym paliwem na świecie, a jego &quot;spalinami&quot; jest jedynie woda. Jednak temperatura gazów wylotowych silników rakietowych zasilanych wodorem jest tak wysoka, że spalany jest azot w powietrzu otaczającym rakietę, uwalniając przy tym tlenki azotu.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Spotkania w podróży</title>
        <published>2016-08-22T12:34:56+00:00</published>
        <updated>2016-08-22T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2016-08-22-spotkania-w-podrozy/"/>
        <id>https://mtsz.pl/blog/2016-08-22-spotkania-w-podrozy/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2016-08-22-spotkania-w-podrozy/">&lt;p&gt;Podczas pobytu na Islandii, na kempingu w Akureyri, poznałem Betty, policjantkę ze Stanów, która swoją emeryturę spędzała, podróżując po świecie (odwiedziła ponad 27 krajów). Podróżowała sama. Rozmawialiśmy przez godzinę.&lt;&#x2F;p&gt;
&lt;p&gt;Podczas wchodzenia na szczyt Aconcagui w Argentynie, poznałem Torkjela, Norwega, którego projektem życiowym było właśnie zdobycie Korony Świata. Podróżował sam. Wspinalismy się razem przez kilka dni, razem zdobyliśmy szczyt.&lt;&#x2F;p&gt;
&lt;p&gt;Podczas wędrówki szlakiem Arctic Circle Trail na Grenlandii, poznałem Aline, pielęgniarkę z Kanady, która przez ostatni rok skrupulatnie zbierała urlopowe dni, żeby na miesiąc wyjechać właśnie na Grenlandię i Islandię. Podróżowała sama. Spędziliśmy razem praktycznie 2 tygodnie w trasie.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Nigdy nie podróżujesz sam.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=UfgQ9ddiYMI&quot;&gt;ELSIANE - HYBRID&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Koniec gry</title>
        <published>2016-06-28T12:34:56+00:00</published>
        <updated>2016-06-28T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2016-06-28-koniec-gry/"/>
        <id>https://mtsz.pl/blog/2016-06-28-koniec-gry/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2016-06-28-koniec-gry/">&lt;p&gt;Właśnie skończyłem Firewatcha. Świetna gra. Poważnie, wszystko jest w niej dobre: grafika, muzyka, dialogi, sposób prowadzenia rozgrywki, a przede wszystkim fabuła. Pierwsze, co zrobiłem po jej wyłączeniu, to szukanie jakiegoś DLC-ka albo sequela. Pierwsze, co znalazłem, to wywiad z głównym programistą, który powiedział, że Firewatch to kompletna historia. Pod wywiadem znajdował się komentarz, który szedł mniej więcej tak:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;ludzie nie potrafią przyjąć do wiadomości, że rzeczy się kończą&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=jLjfhGGuHZo&quot;&gt;Firewatch Original Soundtrack (OST)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Spóźniony na koncert</title>
        <published>2016-02-19T12:34:56+00:00</published>
        <updated>2016-02-19T12:34:56+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2016-02-19-spozniony-na-koncert/"/>
        <id>https://mtsz.pl/blog/2016-02-19-spozniony-na-koncert/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2016-02-19-spozniony-na-koncert/">&lt;p&gt;Ostatnio non stop słucham UNKLE. Nie, żebym wcześniej nie słuchał - po prostu teraz słucham codziennie. Świetna muzyka plus ten wokal Gavina Clarka. Doszedłem do wniosku, że pójdę na pierwszy koncert, jaki tylko będą grali. Wtedy dowiedziałem się, że Gavin Clark nie żyje od roku.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Co za pech.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=QfHaRG1e5Jw&quot;&gt;UNKLE ~ Can&#x27;t Hurt&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="pl">
        <title>Z Korwinem nad morzem</title>
        <published>2008-07-28T12:34:00+00:00</published>
        <updated>2008-07-28T12:34:00+00:00</updated>
        
        <author>
          <name>
            
              mtsz
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mtsz.pl/blog/2008-07-28-z-korwinem-nad-morzem/"/>
        <id>https://mtsz.pl/blog/2008-07-28-z-korwinem-nad-morzem/</id>
        
        <content type="html" xml:base="https://mtsz.pl/blog/2008-07-28-z-korwinem-nad-morzem/">&lt;p&gt;Tę notatkę spisałem niedługo po powrocie z opisanej w niej wyprawy, ale nie pamiętam dokładnie, który to był rok, ani miesiąc, ani dzień. Dlatego datę wpisu wymyśliłem sobie na tydzień po powrocie w roku, który mi się wydaje.&lt;&#x2F;p&gt;
&lt;p&gt;Z perspektywy czasu jest ona bardzo zabawna, ale to moja przeszłość, tak było.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-2-1-0&quot;&gt;Dzień -2, -1, 0&lt;&#x2F;h1&gt;
&lt;p&gt;Jak co dzień, również tego dnia spokojnie przeglądam sobie czytnik RSS. Podłączyłem do niego stronę Nowej Prawicy, bloga JKM, prof. Rybińskiego i kilka innych – wszystko schowane w folderze &quot;Polityka&quot;. Pierwszy wpis na blogu JKM: &quot;Uwaga! Wyjazd na lipiec !!!&quot;. No to czytam.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Idea: Codziennie po południu trzy spotkania w różnych sąsiednich miejscowościach na Wybrzeżu&lt;&#x2F;p&gt;
&lt;p&gt;Technika: Rano wypisywanie danych do plakatów i rozlepianie plakatów, od 13.tej opalanie się na plaży, 17.00, 19.30, 22.00 – spotkania.&lt;&#x2F;p&gt;
&lt;p&gt;Warunki: Chętni przyjeżdżają na miejsce zbiórki na własny koszt. Zamieszkanie w namiotach (ale, jak kto chce wynająć coś, to jego prywatna sprawa – tyle że prawie codziennie cyrk zmienia miejsce pobytu!), śniadania na koszt firmy. Można przyjechać na część planowanego tournée.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Dalej jest napisane, gdzie wysłać zgłoszenie oraz co ma ono zawierać. Mając w perspektywie bezproduktywne wakacje, decyduję, że się zgłoszę – spać mogę w namiocie, a śniadania stawia firma, więc koszty bądź co bądź, wakacji nad morzem, minimalne. No i poznam osobiście Prezesa KNP. Nie zastanawiając się długo, wysyłam zgłoszenie. Czekam dzień, drugi – odpowiedzi nie ma. No to wysyłam jeszcze raz. W międzyczasie wypytuję kogo mogę o jakiekolwiek informacje. W końcu dostaję numer telefonu do niejakiej Pani Julii – ponoć organizatorki tego całego &quot;cyrku&quot;. Mam przynajmniej punkt zaczepienia. Z blogu Prezesa odczytuję, że wyjazd zaczyna się jutro. Jasny sygnał do startu. Miałem ambicje, żeby spakować się do jednego plecaka. Koniecznośc zabrania namiotu i śpiwora wymogła na mnie torbę podróżną i plecak. Spakowany, wsiadam w pierwszy autobus...&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-1-12-lipca&quot;&gt;Dzień 1 – 12 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;No i jadę. Za przejechanie 865 km od Nowego Sącza do Krynicy Morskiej płacę w sumie niecałe 60 zł. Nie wiem czy to dużo – z jednej strony skorzystałem z ulgi studenckiej, z drugiej strony muszę wziąć pod uwagę, ile i tak wróciło do kasy państwowej w milionie podatków, o które się potknąłem płacąc za bilet. Tak czy inaczej, jadąc samochodem zapłaciłbym dużo więcej. Co innego wygoda. Trasę pokonałem w jakieś 16 godzin, co daje średnią prędkość 54 kmph. W rzeczywistości jechałem szybciej, za to przesiadałem się chyba z 10 razy. Ot, polskie koleje państwowe.&lt;&#x2F;p&gt;
&lt;p&gt;Dojeżdżam do miasta Tczew. Postanowiłem zadzwonić do Pani Julii, żeby wypytać się, gdzie mam się zgłosić. Ona odpowiada, żebym zadzwonił do Prezesa. Co mnie mile zaskakuje po wyjściu z pociągu to publiczna toaleta z prysznicem (nigdy wcześniej nie spotkałem). Po kolejowych wojażach jestem niepierwszej świeżości. 7 zł i 20 minut później czuję się jak nowo narodzony. Dzwonię do Prezesa. &quot;Niech pan przyjedzie do Sztutowa – stamtąd pana zabiorę&quot; – słyszę w słuchawce. No to jadę.&lt;&#x2F;p&gt;
&lt;p&gt;Po dojechaniu na miejsce na Prezesa czekam jakieś 15 minut. Następnie jedziemy do domu, gdzie wynajmował pokój, aby tam się przepakować. Szukając miejsca na rozbicie namiotu, znalazłem opodal kemping. Jednak jego właściciel, nie wiedzieć czemu, nie pozwolił mi rozbić namiotu – oczywiście za opłatą. Nie zastanawiając się długo, zacząłem zwiedzać okolicę i natrafiłem na pustostan. Postanowiłem, że w nim prześpię tę jedną noc. Po tym jak Prezes wrócił skądś, udaliśmy się w pierwsze planowane miejsce – do Krynicy Morskiej. Podczas tej trasy miejsce miał pewien zabawny incydent – nie wspomnę o nim ze względu na poprawność polityczną, ale regułą stało się, że każdy dzień był okraszony jakąś minikatastrofą – z tego też względu ciągle miałem, mówiąc poetycko, banana na twarzy i ogólnie bardzo dobrze wspominam cały wyjazd. Ale do rzeczy!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;krynica-morska&quot;&gt;Krynica Morska&lt;&#x2F;h1&gt;
&lt;p&gt;W Krynicy poznałem Pana Jacka. Przedstawił się jako Fanatyk Idei. Miał ze sobą psa, jamnika szorstkowłosego, którego rozmiar był odwrotnie proporcjonalny do energii, z którą szczekał na wszystko.&lt;&#x2F;p&gt;
&lt;p&gt;Ponieważ nie mieliśmy materiałów do uzupełniania oraz mocowania plakatów, naszym pierwszym przystankiem był sklep przemysłowy. Tam nabyliśmy taśmy klejące, kilka tubek kleju Vikol, markery oraz pinezki. Pan Jacek następnie zaprowadził nas do miejsca, które załatwił na pierwsze spotkanie. Była to restauracja niedaleko latarni morskiej. &quot;Za daleko – nikomu nie będzie chciało się tutaj przychodzić&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Wróciliśmy do miasta, i tam, po godzinie szukania zlokalizowaliśmy odpowiednie miejsce między wesołym miasteczkiem a molo, w okolicach &quot;Green Baru&quot;. Potrzebny był jeszcze tylko przedłużacz 25m. No ale mamy już miejsce – czas więc na wypisanie plakatów.&lt;&#x2F;p&gt;
&lt;p&gt;Plakaty wypisywaliśmy dwojako – na podłużnych czerwonych paskach oraz na plakatach ze zdjęciem – wypisaliśmy w sumie ponad 40 plakatów. Następnie udaliśmy się na miasto, aby je porozwieszać. Była nas w sumie piątka: ja, Prezes, Pan Jacek, córka Prezesa, Korynna oraz wnuczka Kamila. Ja poszedłem plakatować miasto z Prezesem - co chwila jakaś osoba podchodziła do nas przywitać się z nim. Podczas plakatowania wstąpiliśmy do sklepu zakupić przedłużacz. Przedłużacza nie było – natomiast był kabel i końcówki, więc po męsku stwierdziliśmy, że sobie sami zrobimy przedłużacz. Ponieważ brakowało nam czasu, poprosiliśmy panią ekspedientkę, aby przygotowała nam kabel oraz końcówki, a my, wracając z plakatowania, odbierzemy i zapłacimy za towar. Powiedziała, że jak nie przyjdziemy, to wie gdzie nas szukać. Poszliśmy dalej. Podczas rozwieszania plakatów na deptaku podszedł do nas młody chłopak (nie pamiętam jego imienia) i zaprosił nas (Prezesa oraz mnie) na darmowy rejs statkiem &quot;Monika&quot;. W trakcie tego rejsu przypomniałem sobie o przedłużaczu, który mieliśmy odebrać. Prezes zadzwonił do córki, aby ten przedłużacz odebrała i w ten sposób udało nam się uniknąć agresji ze strony ekspedientki. Po powrocie z rejsu udaliśmy się na miejsce spotkania. W tym miejscy czekał już na nas Pan Jacek oraz Pani Julia, która okazała się Julią maturzystką. Rozłożyliśmy sprzęt nagłaśniający, flagi, niebieski transparent z adresem strony Prezesa, a na lokalnym stoliku wylądowały publikacje do sprzedania. Wbrew naszym obawom, na spotkaniu pojawiło się dużo osób (na tyle dużo, żeby blokować przejście, obok którego się usadowiliśmy). Pojawił się również burmistrz Krynicy, który wyraził aprobatę dla naszych idei. Pierwszą częścią spotkania było około godzinne przemówienie Prezesa. Druga – moim zdaniem najważniejsza – część, to otwarta dyskusja, w której każdy mógł zadać Prezesowi pytanie – również trwała godzinę. Trzecia to rozmowy kuluarowe, podpisywanie książek oraz wspólne zdjęcia.&lt;&#x2F;p&gt;
&lt;p&gt;Pierwsze spotkanie zakończyło się sukcesem. Po spotkaniu okazało się, że 100 metrów od nas było świetne miejsce do takiego spotkania, scena, przed którą można by zgromadzić dużo więcej słuchaczy. No cóż, Polak mądry po szkodzie. Spakowaliśmy sprzęt i decyzją Prezesa pojechaliśmy do następnej miejscowości.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;piaski&quot;&gt;Piaski&lt;&#x2F;h1&gt;
&lt;p&gt;Tutejsze spotkanie było całkowicie spontaniczne i niezaplanowane. Po zlokalizowaniu &quot;centrum&quot; tej malutkiej mieściny – była to ławka naprzeciwko &quot;Baru Rybnego&quot;, podłączyliśmy głośniki, przez które Pan Jacek informował, że &quot;już za 20 minut w tym miejscu spotkanie z Panem Januszem Korwin-Mikke&quot;. Co nas mile zaskoczyło, również tutaj frekwencja dopisywała. To spotkanie, ponieważ było proporcjonalnie mniejsze, miało dużo bardziej kontaktowy charakter. Formuła była dokładnie taka sama, z tym, że część &quot;pytaniowa&quot; trwała 2 razy więcej niż przemówienie. Tutaj też pierwszy raz spotkaliśmy się z twardym oporem na argumenty ze strony jednej z mieszkanek Piasków – z tego co pamiętam, okazała się utrzymanką państwową. Po tym wydarzeniu wróciliśmy to Sztutowa, gdzie mieliśmy spać. Wtedy też okazało się, że zostawiliśmy w Piaskach baner z adresem strony Prezesa, którego to baneru z tego co mi wiadomo do tej pory nie udało się odzyskać.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;schylek&quot;&gt;Schyłek&lt;&#x2F;h1&gt;
&lt;p&gt;Na zakończenie dnia zjechaliśmy do domu, w którym Prezes, jego córka i wnuczka oraz Julia wynajęli pokoje. Ja oraz Pan Jacek rozbiliśmy mój namiot przed owym pustostanem, za darmo, na ziemi niczyjej. Kapitalista kempingowy stracił kilkadziesiąt złotych. Kolację po pomorsku (ryba oraz wino) zasponsorował Pan Jacek. W międzyczasie Prezes miał problemy ze skorzystaniem z internetu, co świadczy o świetnym wpływie długoletniego monopolu TP S.A. na dostępność usług telekom w naszym kraju. Wieczór upłynął nam na żarliwych dyskusjach dotyczących tematów wszelakich, która trwała do 2 w nocy, kiedy to Julia poszła spać. Następnie z Panem Jackiem udaliśmy się do namiotu, żeby przez kolejne 2 godziny roztrząsać dzieje naszego kraju. Zasnęliśmy około godziny 4, by o godzinie 9 powitać nowy dzień i nowe spotkania.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;wnioski-pierwszego-dnia&quot;&gt;Wnioski pierwszego dnia&lt;&#x2F;h1&gt;
&lt;p&gt;Pierwszy dzień za nami. Można powiedzieć spokojnie, że był to dzień wzorcowy, bo miała w nim miejsce akcja zarówno planowana jak i całkowicie spontaniczna. Każdy kolejny dzień wyglądał mniej więcej tak samo.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-2-13-lipca&quot;&gt;Dzień 2 – 13 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Na dzisiaj zaplanowane mieliśmy trzy miejscowości: Sztutowo, Stegnę oraz Kąty Rybackie. Po wygramoleniu się z namiotu, porannej toalecie i dokończeniu wczorajszej ryby na śniadanie, pojechaliśmy do Sztutowa. Podczas wyjeżdżania ze Sztutowa miał miejsce zabawny incydent, o którym przez poprawność polityczną nie wspomnę. Ponieważ mieliśmy do dyspozycji aż cztery samochody, podzieliliśmy się na dwie drużyny, tak że Prezes z córką i Panem Jackiem szukali miejsca w Sztutowie, a ja z Julią w Stegnie. Po znalezieniu miejsc zjechaliśmy z powrotem do Sztutowa. Kąty to była tak strasznie rozległa wieś, że ciężko byłoby nam rozwiesić plakaty oraz zachęcić mieszkańców do 10km pielgrzymki na krótkie spotkanie. Dlatego zrezygnowaliśmy na wstępie.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sztutowo&quot;&gt;Sztutowo&lt;&#x2F;h1&gt;
&lt;p&gt;Sztutowo okazało się małą wsią, tym gorzej, że średnio zurbanizowaną. Skończyło się to tym, że na miejsce spotkania wybraliśmy skrzyżowanie drogi prowadzącej na plażę z pierwszą lepszą – i tak też pisaliśmy na plakatach. Na bazę wypadową obraliśmy bardzo nowoczesny ogrodzony plac zabaw dla dzieci z Wi-Fi! oraz sąsiadującą z hotelem restaurację. Najpierw zjedliśmy obfity obiad w ramach sponsorowanego śniadania, a następnie przystąpiliśmy do pisania plakatów. Po skończeniu część z nas została w Sztutowie, a część pojechała do Stegny – oczywiście rozwieszać plakaty. Po skończeniu wyruszyliśmy z powrotem w stronę Sztutowa. Tutaj miejsce miała zabawna sytuacja. Pani z budki rybnej, która sąsiadowała z naszym miejscem spotkania, nie chciała użyczyć nam prądu, mówiąc, że zamyka o 16 – spotkanie było o 18. Oczywiście to okazało się nieprawdą – podejrzewam, że skuszona potencjalnym tłumem klientów, została na dłużej. Dlatego szybko z Panem Jackiem pojechaliśmy w poszukiwaniu przedłużacza – najbliższe dostępne źródło prądu było oddalone o 40 metrów. Zawróciliśmy zatem do Stegny sprawdzając każdy możliwy sklep. Tutaj warto wspomnieć, że mieliśmy cały sprzęt nagłaśniający przy sobie, w samochodzie. Po poszukiwaniach zakończonych niepowodzeniem, postanowiliśmy wrócić do Sztutowa. Na 3 kilometry przed dojazdem zadzwonił Prezes, mówiąc, że nie ma sensu, żebyśmy wracali, bo nikt się nie pojawia – było około 15 minut przed spotkaniem. Nawróciliśmy więc i zaczęliśmy pędzić w stronę Stegny. Po tych 15 minutach – spotkanie rozpoczynało się wtedy oficjalnie – zadzwoniła Julia z pytaniem gdzie jesteśmy. &quot;Prezes mówił, że spotkanie jest odwołane – no to jedziemy do Stegny&quot;. &quot;Wracajcie, jednak jacyś ludzie przyszli, dużo ludzi&quot;. W ten sposób przejechaliśmy w sumie jakieś 70 km bez większego sensu. Ale skoro Prezes zwraca za paliwo, to tylko zwiedzać! Kiedy dojechaliśmy na miejsce, spotkanie już było rozpoczęte, dlatego szybko rozstawiliśmy sprzęt. Samo spotkanie przebiegło wg schematu. Następnie spakowaliśmy się i pojechaliśmy do Stegny.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;stegna&quot;&gt;Stegna&lt;&#x2F;h1&gt;
&lt;p&gt;W Stegnie z urbanizacją było trochę lepiej – na miejsce spotkania wybraliśmy &quot;Bar u Maćka&quot; przy głównej ulicy, przed którym był duży plac mogący pomieścić zwolenników konserwatywnego liberalizmu. W Stegnie nie było żadnych wyjątkowych sytuacji, ale na spotkaniu było bardzo mało osób – mimo tego, że udało nam się przylepić plakat na wejściu do tłumnie odwiedzanej przez turystów Biedronki! Po zakończeniu spotkania właścicielka lokalu wraz z obsługą zrobili sobie pamiątkowe zdjęcie z Prezesem i wyruszyliśmy.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;koniec-dnia&quot;&gt;Koniec dnia&lt;&#x2F;h1&gt;
&lt;p&gt;Po spotkaniu swoje kroki skierowaliśmy w stronę Sopotu, gdzie miały miejsce kolejne spotkania. Noc spędziliśmy w domu Pana Zdzisława i jego żony. Warto zaznaczyć, że ich synem jest Janek, szef bardzo prężnie działającej sopockiej młodzieżówki. Zostaliśmy powitani suto zastawionym stołem oraz winem najlepszego gatunku i rocznika. Dyskusja trwała chyba do czwartej nad ranem, po czym, strudzeni ciężkim dniem pracy, poszliśmy spać.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-3-14-lipca&quot;&gt;Dzień 3 – 14 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Dzisiaj pobudka była ok. godziny 12 – trudy dnia poprzedniego dały się we znaki. Po śniadaniu wyruszyliśmy na plac Monte Casino, gdzie rozłożyliśmy się i zorganizowaliśmy spontaniczną akcję.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sopot&quot;&gt;Sopot&lt;&#x2F;h1&gt;
&lt;p&gt;Jako że Monciak jest tranzytem między molo a deptakiem, frekwencja była zadowalająca, było dużo inteligentnych pytań, tam też pierwszy raz wplątałem się w dyskusję z umiarkowanymi przeciwnikami liberalizmu gospodarczego, którzy swoje argumenty podsumowali hasłem &quot;człowiek jest najważniejszy&quot; - przyznam, zmiażdżyli mnie doszczętnie. Po spotkaniu obowiązkowo wykwintny obiad w chińskiej restauracji. Po obiedzie zwinęliśmy sprzęt i pojechaliśmy z powrotem do domu Pana Zdzisława, gdzie miała miejsce ogólna narada, co będziemy dalej robić.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;koniec-dnia-1&quot;&gt;Koniec dnia&lt;&#x2F;h1&gt;
&lt;p&gt;Ten dzień do dzisiaj jest dla mnie zagadką, ponieważ nie mogę za żądne skarby przypomnieć sobie co robiliśmy po spotkaniu organizacyjnym. Całkowicie wykluczam możliwość utraty pamięci spowodowaną nadmiernym raczeniem się winem. Po prostu: nie pamiętam!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-4-15-lipca&quot;&gt;Dzień 4 – 15 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Wstawanie z łóżka nie było tak uciążliwe jak wczoraj, ale zanim wywlekliśmy się z domu Pana Zdzisława, była już 12. Dzisiejszym jedynym celem był Grunwald.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;grunwald&quot;&gt;Grunwald&lt;&#x2F;h1&gt;
&lt;p&gt;Trasa na Grunwald była o tyle ciekawa, że w pewnym momencie doszczętnie się zgubiliśmy, w konsekwencji czego straciliśmy jakieś dwie godziny. Podczas przejeżdżania przez Malbork natrafiliśmy na gigantyczny korek – wyglądało, jakby w Malborku był tylko jeden most, przez który akurat wszyscy chcieli przejechać. Dodając do tego temperaturę 40 stopni... Po dojechaniu na miejsce zapłaciliśmy za parking 12 zł od samochodu i poszliśmy szukać miejsca. W końcu znaleźliśmy dogodne na samym szczycie wzgórza. Była już 18, więc na plakatowanie czasu nie było. Ponieważ targanie całego sprzętu na samą górę byłoby niezłą mordęgą, Prezes postanowił, że pojedziemy tam samochodem. Oczywiście zwykłym śmiertelnikom wjeżdżać na górę nie wolno, dlatego wyciągnęliśmy przez okno dwie flagi, a kontrolującym chłoptasiom powiedzieliśmy, że jedziemy ze sprzętem na inscenizację. W ten sposób z naturalnych oponentów stali się neutralni. Jeden nawet zagrodził innemu samochód tak, żebyśmy swobodnie przejechali. Ot, kombinowanie. Po rozstawieniu sprzętu zaczęło się spotkanie. Frekwencja była wybitnie marna, głównie z powodu turnieju, który odbywał się w naszej okolicy. Jednak i tutaj nie brakowało atrakcji. W pewnym momencie trójka rodowitych Grunwaldian przyjechała z taczką i z chęcią wywiezienia Prezesa. Jednak znalazło się wśród tłumów kilku osobników stricte prawicowych, którzy z wdziękiem tamtych przepędzili. Zjawiła się również życzliwsza grupa, która Prezesowi w podzięce za walkę o wolność podarowała lokalny miód pitny. Na nasze nieszczęście część pytaniową zdominował domorosły podchmielony młodzieniaszek, któremu kibicowała jemu podobna grupka chwiejących się pachołków. Zamiast wnieść cokolwiek sensownego do dyskusji, tylko marnowała czas Prezesa oraz słuchaczy. Po spotkaniu szybko uporaliśmy się ze sprzętem i pojechaliśmy do jakiejś małej miejscowości.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;wieczor&quot;&gt;Wieczór&lt;&#x2F;h1&gt;
&lt;p&gt;Trasa była dość daleka. Za to nocleg, równie wyśmienity co ostatnio. Tym razem ugościł nas naukowiec, którego imienia niestety nie pamiętam. Tego wieczoru w domu owego Pana zdarzył się śmieszny incydent z wanną i wykręconym modułem hydromasażu. Była również mrożąca krew w żyłach sytuacja, w której ogromny pies Gospodarza wziął w swoje ostre kły małego, ale żwawego pieska Pana Jacka. Na szczęście wszystko skończyło się dobrze, i mogliśmy w spokoju podyskutować, zanim nas sen nie zmorzył.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-5-16-lipca&quot;&gt;Dzień 5 – 16 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Dzisiejszego dnia miały miejsce 3 spotkania w każdym z Trzech Miast.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;gdynia&quot;&gt;Gdynia&lt;&#x2F;h1&gt;
&lt;p&gt;Gdynia – w ogóle nie pamiętam tego miejsca. Jak sobie przypomnę, dopiszę.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sopot-1&quot;&gt;Sopot&lt;&#x2F;h1&gt;
&lt;p&gt;W Sopocie rozstawiliśmy się przed wejściem na molo. Frekwencja umiarkowana – na Monciaku było lepiej.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;gdansk&quot;&gt;Gdańsk&lt;&#x2F;h1&gt;
&lt;p&gt;Oplakatowaniem Gdańska zajął się Janek i jego drużyna. Spotkanie miało miejsce pod pomnikiem Neptuna i tutaj mieliśmy dużą i świadomą publiczność – co zawdzięczamy głównie akcji plakatowania.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;koniec-dnia-2&quot;&gt;Koniec dnia&lt;&#x2F;h1&gt;
&lt;p&gt;Po tym jakże owocnym dniu pojechaliśmy z powrotem do tej małej miejscowości. Tym razem miała miejsce dużo zabawniejsza sytuacja, z pianinem, ale o niej, oprócz mnie, wiedzą tylko dwie inne osoby, i nawet na łaskotkowych torturach nie powiedziałbym, o co chodzi. Trzeba było jechać z nami.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-6-17-lipca&quot;&gt;Dzień 6 – 17 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Tego dnia, ku ogólnemu niezadowoleniu, opuścił nas Pan Jacek. Niedługo jednak po tym pojawił się kolejny działach, o imieniu, a jakże: Jacek. Okazało się ponadto, że Jacek jest ze Szwecji! i jest naukowcem. Nowa Prawica naprawdę ściąga różne osobowości.&lt;&#x2F;p&gt;
&lt;p&gt;Po śniadaniu we Władysławowie naszym zadaniem było znalezienie miejsca na trzy jutrzejsze spotkania. Dzisiejszy dzień spędziliśmy więc głównie na jeżdżeniu. A jeździliśmy od miasta do miasta, stojąc nieraz w korku – droga na Helu kręta i wąska. To, co udało nam się załatwić, to miejscówki na spotkania w Helu oraz bodajże Juracie. Z tymi informacjami wróciliśmy na spotkanie do Władysławowa.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;wladyslawowo&quot;&gt;Władysławowo&lt;&#x2F;h1&gt;
&lt;p&gt;We Władysławowie spotkanie odbyło się spontanicznie, na rogu jakichś dwóch ulic, niedaleko szkoły muzycznej. Tutaj miejsce miało interesujące zdarzenie. Mianowicie w pewnym momencie głośniki przestały działać. Minęło trochę czasu, zanim zdaliśmy sobie sprawę z tego, że ktoś przeciął kabel zasilający nożem. Z takim zjawiskiem się jeszcze nie spotkałem! Myślę, że ten sabotażysta, nie umiejąc bądź nie mogąc argumentami walczyć z poglądami prawicowymi, posłużył się jedyną sobie znaną, a w szerszych kręgach za barbarzyńską uznawaną metodą. Na szczęście sklejenie tego kabla to była tylko formalność, więc spotkanie trwało dalej. Swoje pięć minut miał również pewien bezdomny. Pomijając stężenie alkoholu w jego krwi, zadał on pytanie Prezesowi &quot;co pan zrobi dla bezdomnych&quot;. Prezes, znany ze swojej bezpośredniości odpowiedział bez kozery &quot;nic&quot;, za co został przez owego bezdomnego obsypany jednoznacznymi gestami dezaprobaty. Niestety, nasz ustrój wychował tłum niedorajdów i nierobów, którzy uważają, że coś im się należy – dopóty będzie źle, dopóki nie zdadzą sobie oni sprawy, że każdy jest kowalem własnego losu, jak sobie pościelesz, tak się wyśpisz, a chcącemu nie dzieje się krzywda. Gdy próbowałem – jak później słusznie skwitował to Pan Jacek, odważnie i naiwnie – wytłumaczyć to naszemu koledze, dostało mi się, że jestem gówniarzem i próbuję go umoralniać. Wniosek: nie dyskutować z głupcami. Po 15 minutach w naszym koledze zebrała się kolejna fala agresji, ale ta została efektywnie stłumiona u zarodka, dzięki pewnemu aktywnemu działaczowi – dziękujemy! Podczas spotkania miałem też okazję poznać Pana Arkadiusza – był to nadmorski odpowiednik Pana Jacka, również &quot;fanatyk idei&quot;. Pomógł nam szczególnie przy wyjeździe z Władysławowa. Również dziękujemy!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;schylek-1&quot;&gt;Schyłek&lt;&#x2F;h1&gt;
&lt;p&gt;Po jakże aktywnym dniu udaliśmy się do miejsca, które nie wiadomo jak, znalazła Julia. Rozpakowaliśmy się ze swoimi bagażami, kolacja, wino i spanie.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-7-18-lipca&quot;&gt;Dzień 7 – 18 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Wszystkie trzy, a właściwie cztery spotkania, były spontaniczne, czyli bez plakatowania. Pomimo tego, że takie były plany, poprzedniego dnia nie starczyło nam na to czasu.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;hel&quot;&gt;Hel&lt;&#x2F;h1&gt;
&lt;p&gt;W Helu odbyły się dwa. Jedno w miejscu, które znaleźliśmy ad hoc, a drugie, niespodziewanie, w poprzednio zaplanowanym miejscu. Dlaczego niespodziewanie? Okazało się, że właściciel lokalu, obok którego miało się ono odbyć, wszystko zorganizował i rozreklamował wydarzenie. W ten sposób odrobił nasze zadanie domowe. Tutaj wyszły na jaw nasze tragiczne problemy z organizacją. W konsekwencji, owo drugie spotkanie było bardzo krótkie. Cóż poradzić.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;jastarnia&quot;&gt;Jastarnia&lt;&#x2F;h1&gt;
&lt;p&gt;W Jastarni oplakatowaliśmy z Julią i Jackiem główny deptak, ale za prawdziwą promocję odpowiadałem ja i szczekaczka, przez którą krzyczałem ile sił w płucach. Dało to nienaganną frekwencję, a i pytania były niczego sobie.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;jurata&quot;&gt;Jurata&lt;&#x2F;h1&gt;
&lt;p&gt;W tym czasie Julia i Jacek pojechali do Juraty zorganizować ostatnie dziś spotkanie. Tego spotkania niestety nie pamiętam.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;schylek-2&quot;&gt;Schyłek&lt;&#x2F;h1&gt;
&lt;p&gt;Ponieważ nie mieliśmy zorganizowanego noclegu, Julia magiczną mocą znalazła takowy w pierwszej miejscowości, o którą zahaczyliśmy. Wysoki budynek, w którym zajęliśmy ostatnie, najwyższe piętro. Po wieczornej dyskusji, ok. godziny 3 nad ranem, poszliśmy spać.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-8-19-lipca&quot;&gt;Dzień 8 – 19 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Kolejny dzień i kolejne spotkanie. Na dzisiaj było zaplanowane tylko jedno: w Łebie. Po śniadaniu udaliśmy się prosto do Łeby poszukiwać miejsca. Po drodze zgarnęliśmy nowe dwie osoby, które wyraziły chęć uczestniczenia w tournée po wybrzeżu. Mariusz oraz Marek.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;leba&quot;&gt;Łeba&lt;&#x2F;h1&gt;
&lt;p&gt;Mieliśmy do wyboru albo deptak, który w południe zdawał się być opuszczony, albo park, tzw. Skwer Rybaka. Wybraliśmy skwer, mając nadzieję, że pod wieczór będzie tam dużo ludzi. I mieliśmy rację – przez park przewalały się tłumy. Swoje stoiska rozłożyły dwie grupy indiańskie, i odtwarzając tragicznie głośno muzykę ze swojego sprzętu, rytmicznie co kilka sekund krzyczeli do mikrofonu &quot;hej!&quot; - mieli niezłą oglądalność. Ponieważ nie było miejsca dla naszego cyrku, przenieśliśmy się na sąsiedni placyk. Mi przypadło zaszczytne zadanie obwieszczenia ludowi przez krzykaczkę, że &quot;spotkanie z Januszem Korwin-Mikke zostało przeniesione na sąsiedni plac&quot;. Ku mojej uciesze, dużo osób zaczęło się kierować w moją stronę z pytającymi minami, więc tym głośniej krzyczałem o zmianie lokalizacji. Po siedmiu takich sesjach i ja poszedłem na spotkanie. Stała tam już porządna grupa ludzi, słuchająca wykładu. Później nastąpiła jedna z lepszych sesji pytaniowych, pojawiło się wiele osób z inteligentnymi pytaniami. Jedyną niedogodnością były komary – cała ich falanga zaatakowała tłum tak, że w końcu tylko najbardziej wytrwali zostali. Ja wylałem na siebie całą butelkę jakiegoś płynu, który miał rzekomo odstraszać to paskudztwo – niestety i tak byłem już podziurawiony i z rosnącą irytacją parzyłem, jak moje nogi zwiększają objętość. Po spotkaniu spakowaliśmy się i wtedy okazało się, że nie mamy zorganizowanego noclegu – wynikło to z jakiegośtam nieporozumienia. W końcu po rozmowie z którymś z sympatyków dostaliśmy proksymalny namiar i udaliśmy się w jego kierunku. Na nasze szczęście znaleźliśmy wolne pokoje, w których się zakwaterowaliśmy na tę noc. Uff!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-9-20-lipca&quot;&gt;Dzień 9 – 20 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;Dzisiejszy dzień przyjął nową formułę. Ponieważ do naszego obozu dołączyły nowe osoby, mogliśmy wszystko lepiej zaplanować. Postanowiliśmy więc, że się rozdzielimy – równolegle będziemy pracować w dwóch miejscach. Ja, Marek i Mariusz pojechaliśmy do Rowów, natomiast reszta udała się do Ustki.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rowy&quot;&gt;Rowy&lt;&#x2F;h1&gt;
&lt;p&gt;W Rowach mieliśmy standardowe zadanie: znaleźć miejsce oraz oplakatować miejscowość. Od Prezesa dostaliśmy namiar, jakoby w pewnym pensjonacie – aby odwzajemnić złośliwość, nie wspomnę jego nazwy – możemy spokojnie takie spotkanie zaaranżować. Niestety dyrektorka ów placówki albo nie chciała, albo nie mogła nam jej udostępnić na satysfakcjonujących nas warunkach. Trudno. Nasze kolejne poszukiwania skończyły się na znalezieniu sceny w Parku Rozrywki i czegośtam, jak się później dowiedzieliśmy w informacji turystycznej, bardziej znanym jako żulpark, albo muszla koncertowa. Tak też napisaliśmy na plakatach, które następnie rozwiesiliśmy w cały miasteczku. Pomimo naszych obaw, na spotkanie przyszła satysfakcjonująca liczba osób. Podczas pytań pojawił się pewien człowiek o poglądach na wskroś dualnych: popierał Nową Prawicę jednocześnie mówiąc, że państwo powinno więcej mu dawać. Zjawiła się też kobieta, która oskarżyła Prezesa, że tylko gada i nic nie robi, machnęła ręką i poszła. Cóż poradzić. Jeszcze inny jegomość powiedział, że jeśli Prezes zrobi to, o czym mówi, to na niego zagłosuje. Tutaj Prezes, przedzierając się przez salwy śmiechu, wyjaśnił temuż obywatelowi, że żeby mógł zrobić cokolwiek, najpierw ów obywatel musi zagłosować. Ogólnie spotkanie było radosne i wszyscy opuścili je w świetnych nastrojach. Tak się rozciągneło to spotkanie, że spóźniliśmy się na kolejne, w Ustce, 15 minut.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;ustka&quot;&gt;Ustka&lt;&#x2F;h1&gt;
&lt;p&gt;Jadąc na pełnym gazie, dojechaliśmy do Ustki. Po kilkuminutowym błądzeniu trafiliśmy na miejsce spotkania. Ku mojemu przerażeniu, tłum ludzi, który się zjawił, był nie do policzenia. Przedzieranie się przezeń było nie lada sztuką. Tłum zebrał się pod ogromną sceną, przy której domniemanie, miało odbyć się spotkanie. Niestety zarządca sceny, jak na prawdziwego Polaka przystało, nie zgodził się. Bo nie. No to robimy obok. Jak na złość, mieliśmy też problem z podpięciem sprzętu do prądu. To spowodowało kolejne kilka minut opóźnienia, z powodu którego stopniało jakieś 10% audiencji. W końcu udało się wszystko podłączyć i spotkanie się rozpoczęło. Na tym spotkaniu pierwszy raz spotkałem się z fanatykami Prezesa. Tak samo jak istnieje grupa emerytek, które oddałyby całą rentę i życie swoje za prezesa Kaczyńskiego czy Tuska, tak i Pan Korwin-Mikke ma takie fanki. Obcowanie z tą kobietą uświadomiło mi, że fanatyzm, bez względu na to, jakiej idei przyświeca, tylko tą ideę dewaluuje. No i okazało się, wbrew temu co myślą o mnie znajomi, że nie jestem fanatykiem. Całe szczęście. Po spotkaniu udaliśmy się do pokojów, które załatwił nam były aktywny działacz prawicowy. Dziękujemy!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dzien-10-21-lipca&quot;&gt;Dzień 10 – 21 lipca&lt;&#x2F;h1&gt;
&lt;p&gt;To był mój ostatni dzień. Po przebudzeniu, nauczeni doświadczeniem poprzedniego dnia, od razu wyruszyliśmy w trasę znaleźć nocleg. Tam też zjedliśmy śniadanie, a następnie udaliśmy się do Jarosławca.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;jaroslawiec&quot;&gt;Jarosławiec&lt;&#x2F;h1&gt;
&lt;p&gt;Na miejsce spotkania wybraliśmy restaurację DW przy głównej ulicy – przede wszystkim ze względu na niepewną pogodę; a restauracja miała zadaszony ogródek. Usiedliśmy w piątkę i zaczęliśmy wypisywać plakaty. W Jarosławcu zostawiliśmy zaprawionych już w boju Mariusza i Marka, aby je porozklejali, natomiast reszta pojechała do Darłowa. Na tym spotkaniu nie byłem obecny ze względu na pracę w Darłowie właśnie.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;darlowo&quot;&gt;Darłowo&lt;&#x2F;h1&gt;
&lt;p&gt;Po szybkim rozeznaniu uznaliśmy, że najlepszym miejscem na spotkanie będzie plac po zachodniej części mostu rozsuwanego. Wróciliśmy do samochodów po plakaty, pisaki i inne kleje, a następnie udaliśmy się do pobliskiej cukierni, gdzie wypisywaliśmy plakaty i raczyliśmy się słodkościami. Następnie udaliśmy się rozwieszać plakaty: ja i Jacek na wschód a Korynna, jej córka oraz Julia, na zachód. Ponieważ plakatów narobiliśmy na potęgę, to rozwieszaliśmy je bardzo gęsto – przełożyło się to na nienaganną frekwencję. Po rozwieszeniu plakatów udaliśmy się coś zjeść, i wtedy zdałem sobie sprawę z pewnej niedogodności większości nadmorskich miast. W całym Darłowie były tylko dwa lokale z dostępem do internetu, i w żadnym ten internet nie działał. Nie wiem czy to jest świadomy zabieg – w końcu mamy tu odpoczywać – ale z tego powodu musiałem zaprzestać swojej działalności w internecie. No cóż, i tak sądzę, że praca u podstaw wśród ludzi dała dużo lepsze efekty.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;pozegnanie&quot;&gt;Pożegnanie&lt;&#x2F;h1&gt;
&lt;p&gt;Ponieważ był to mój ostatni dzień, pożegnałem się z kim mogłem i w 15. minucie przemówienia Prezesa opuściłem Darłowo. Oczywiście, żeby nie było za nudno, podczas odwożenia mnie mój kierowca dostał mandat i zarobił kilka punktów. Za co? Ano za wjazd pomimo zakazu na opuszczony plac dworcowy. Tym oto uroczym akcentem zakończyłem nadmorską przygodę; przy tym utwierdziłem się w przekonaniu, że w tym kraju nie jest dobrze – prawo, zamiast karać przestępców, znęca się nad Bogu ducha winnymi ludźmi. Czeka nas jeszcze wiele pracy.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Tę sekcję aktualizuję po dłuższym czasie. Dopisałem rzeczy, które sobie przypomniałem.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;11-lutego-2021&quot;&gt;11 lutego 2021&lt;&#x2F;h1&gt;
&lt;p&gt;Zabawny incydent w Sztutowie: córka Korwina, Korynna, wjechała w jakiś znak na wstecznym.&lt;&#x2F;p&gt;
&lt;p&gt;Pamiętam że dom w Sopocie w którym nocowaliśmy, był ogromny, Janek miał gigantyczny pokój na poddaszu, a impreza wieczorna była w salonie, gdzie na ścianach wisiały szable i herby. Było bogato.&lt;&#x2F;p&gt;
&lt;p&gt;Ta akcja z hydromasażem. Córka Korwina, Korynna, brała kąpiel w łazience na piętrze. Po jakimś czasie usłyszeliśmy kapiącą wodę w przedsionku. Woda kapała... z lampy. Okazało się, że właścicel domu wykręcił moduł hydromasażu z wanny, ale niczym go nie zaślepił. Jak Korynna się kąpała, woda zaczęła się przelewać do wnętrza wanny, następnie po podłodze, i jakimś cudem przedostała się do kanału na przewód od lampy. Mogło się to skończyć trochę gorzej.&lt;&#x2F;p&gt;
&lt;p&gt;W Sopocie przy molo podczas przemówienia Korwin stał na ławce.&lt;&#x2F;p&gt;
&lt;p&gt;Akcja z pianinem. Na wstępie dodam, że właściciel był&#x2F;jest ekspertem od &quot;wody ultra czystej&quot; - takiej, której używa się na przykład w reaktorach atomowych. Ale do zeczy. Właściciel domu czekał na nas do późna, ale że wróciliśmy jeszcze później, to on w tym czasie poszedł do swoich sąsiadów na imprezę. W domu go nie było, i nie wiedzieliśmy gdzie jest, ale mieliśmy klucze i pozwolenie, więc weszliśmy, zjedliśmy kolację i położyliśmy się spać. Jakiś czas później wrócił właściciel. Był srogo nawalony. Konsewkencją takiego stanu jest wolne myślenie oraz pełny pęcherz, a z połączenia tych dwóch stanów właściciel wywnioskował, że najlepiej będzie się wypróżnić na podłogę. Obok fortepianu. Nie wiem, może fortepian coś mu przypominał. W każdym razie leżenie w śpiworze na podłodze kilka metrów od lejącego po płytkach gościa to nie jest coś, co się zapomina. Właściciel poszedł do sypialni, a ja i chyba pan Jacek ogarnęliśmy sytuację i posprzątaliśmy. Nawet nie było nic czuć. Ale ta noc się jeszcze nie skończyła. Bo właściciel poszedł do swojej sypialni, w której znalazł kogoś, kto z nami był (nie pamiętam jego imienia, szczupły, miał pewnie z 28 lat, w chyba w okularach). Nie wiem, jak potoczyła się ta historia. Wiem natomiast, jak potoczyła się historia Korwina wracającego z kibla w nocy. Postanowił się on na mnie potknąć - w końcu leżałem na ziemi, nieopodal jego miejsca snu. Człowiek już wtedy był raczej starszy, więc wystraszyłem się, że złamał biodro, czy coś, ale on tylko chwilę pojęczał, i poszliśmy w końcu spać. Nie wiem, czemu tego wszystkiego nie napisałem w oryginalnej relacji.&lt;&#x2F;p&gt;
&lt;p&gt;Pamiętam, że reklamowanie spotkania z Korwinem przez megafon w Jastarni było dla mnie paraliżująco stresujące. Ale o dziwo, tylko przez pierwsze kilka minut.&lt;&#x2F;p&gt;
&lt;p&gt;Nocleg w Ustce to były pokoje w takim niskim białym budynku. Pokoje były odrobinę zbyt wilgotne, ale pościele były miękkie i głębokie.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
