Sway w Waylandzie zamiast X-ów.

Z X Window System szedłem przez życie, ale odkąd pierwszy raz przeczytałem o Wayland, od czasu do czasu sprawdzałem postępy w tym projekcie. Nie, żebym miał jakieś wielkie „ale” do X-ów, jednak na moje niewielkie potrzeby ta armata zawsze wydawała mi się zbyt wielkiego kalibru.

Mijały lata, zawsze czegoś jednak brakowało. Na początku duże „desktopy” jeszcze Wayland nie wspierały, później moja karta graficzna niezbyt działała (NV3100m, bo lubię stare laptopy). Aż w końcu nouveau i kernel polubiły się z moim retro-sprzętem i jest:

Najbardziej zaskoczył mnie sway. Złapał „w locie” moją konfigurację i3 na tyle skutecznie, że musiałem sie upewnić, czy to na pewno sway.

Fujinet-pc na Raspberry Pi Zero W.

Trafiłem ostatnio na wątek forum Atari Age, w którym Jan Krupa (apc) informował o postępach prac nad jego portem Fujinet na PC. Pierwsza myśl – jakby to działało na RPi Zero W?

Zamówiłem, szybko dotarło. Dopracowane jako produkt genialnie.

Instalacja Arch Linux na Arm6 to jakieś 10 minut na przygotowanie karty i konfigurację Wifi. Konfiguracja distcc zajmuje trochę dłużej, ale działa i bez tego – kompilacja na Raspberry to jakieś 15 minut. Źródła kompilują się bez żadnych warningów (zależności są minimalne: gcc, cmake, make i libbsd).

Update (sierpień 2022):

Niestety Archlinux Arm porzucił wparcie dla Arm6, więc przeinstalowałem Fujinet na Raspberry Pi OS z Debianem 11.4 Bullseye. Działa tak samo pięknie, a może nawet nieco lepiej.

Zwykle uruchamiam Fujinet w sesji screen przy starcie Raspberry Pi: screen -d -m ./run-fujinet, bo w razie konieczności zawsze można się przypiąć i odpiąć screenem po zalogowaniu przez ssh żeby zobaczyć co się dzieje. Interfejs webowy pozwala też na reset fujinet, ale szybciej i wygodniej zrobić to z Termux Widget na telefonie (skrypty uruchamiane są via ssh na Raspberry Pi):

#!/bin/bash
killall -9 fujinet
cd /home/greblus/fujinet/
screen -d -m ./run-fujinet

Skoro działa, to może jakiś niezbyt miarodajny test, np. RWTEST. Testy w SpartaDos X na Rpi, laptopie z Linuksem i w moim porcie AspeQt na Androidzie. Ten sam obraz atr z RWTEST.COM podmontowany jako D1. Fujinet na Rpi Zero działa fajnie z hsindex=0 i SIO2PC-USB, ale dobrze jest wyjście debuggowania w skrypcie run-fujinet przekierować do /dev/null, jest jednak nieznacznie szybciej, nawet przy odpiętym terminalu screen.

Fujinet na Rpi Zero W
Fujinet na laptopie
AspeQt na Androidzie

Jest ok. Zaskakujące, że na PC działa wolniej. Tłumaczę sobie to tym, że odczyty realizowane są z pamięci RAM bo obraz atr jest wczytywany do pamięci, a zapisy na Rpi i Androidzie realizowane są na pamięci Flash, tymczasem na moim starym laptopie kręci się stary dobry dysk talerzowy 5400rpm 🙂

Drzwi otwierane fotokomórką.

Chciałbym nauczyć dzieciaki podstaw programowania. Długo zastanawiałem się jak to zrobić i po przemyśleniach postanowiłem spróbować pythonowego mcpi, bo maluchy od kilku lat budują co popadnie w Minecraft na Androidzie. Uruchomiłem spigot, zainstalowałem RaspberryJuce i Geyser… I sam wsiąkłem na kilka wieczorów ;).

from mcpi import minecraft
import mcpi.block as block
import minecraftstuff
import time
from threading import Thread
import sys
from pathlib import Path

mc = minecraft.Minecraft.create()

if not (Path(".house_coordinates.txt").is_file()):
    print("Zbuduj najpierw dom za pomocą house.py")
    sys.exit()
else:
    f = open(".house_coordinates.txt", "r")
    x,y,z = f.readline().split(',')
    f.close()
    housePos = minecraft.Vec3(int(x),int(y),int(z))

blocksPos = [ (0,0,0), (-1,0,0), (-2,0,0), (0,1,0), (-1,1,0),
              (-2,1,0), (0,2,0), (-1,2,0), (-2,2,0), (0,3,0),
              (-1,3,0), (-2,3,0) ]

doorsPos = housePos + minecraft.Vec3(6,0,0)
doorsBlocks = [minecraftstuff.ShapeBlock(x,y,z,block.WOOD_PLANKS.id) for [x,y,z] in blocksPos]
doorShape = minecraftstuff.MinecraftShape(mc, doorsPos, doorsBlocks)

def openDoor():
 while True:
  pos = mc.player.getTilePos()
  if pos.x in range(doorsPos.x-3, doorsPos.x+1) and abs(pos.y-doorsPos.y)<2 and abs(pos.z-doorsPos.z)<2:
     doorShape.moveBy(0, -4, 0)
     time.sleep(5)
     doorShape.moveBy(0, 4, 0)

Thread(target=openDoor).start() 
from mcpi import minecraft
from pathlib import Path

mc = minecraft.Minecraft.create()
if not (Path(".house_coordinates.txt").is_file()):
    housePos = mc.player.getTilePos()+minecraft.Vec3(0,0,10)
    f = open(".house_coordinates.txt", "w")
    f.write("{},{},{}".format(housePos.x, housePos.y, housePos.z))
    f.close()
else:
    f = open(".house_coordinates.txt", "r")
    x,y,z = f.readline().split(',')
    f.close()
    housePos = minecraft.Vec3(int(x),int(y),int(z))

mc.setBlocks(housePos.x+0,  housePos.y+0,  housePos.z+0,
             housePos.x+10, housePos.y+10, housePos.z+10, 17)
mc.setBlocks(housePos.x+1,  housePos.y+1,  housePos.z+1,
             housePos.x+9,  housePos.y+9,  housePos.z+9, 0)
mc.setBlocks(housePos.x+4,  housePos.y,    housePos.z,
             housePos.x+6,  housePos.y+3,  housePos.z, 0)
mc.setBlocks(housePos.x+1,  housePos.y+5,  housePos.z,
             housePos.x+2,  housePos.y+6,  housePos.z, 0)
mc.setBlocks(housePos.x+8,  housePos.y+5,  housePos.z,
             housePos.x+9,  housePos.y+6,  housePos.z, 0)

Pobudujemy z pętli, pokażę młodemu minecraftstuff, kształty i obiekty 3d i myślę, że mu się spodoba. A poniższe, to drzwi na fotokomórkę. Wystarczy podejść ;).

auto&&… args.

Kiedyś zastanawiałem się nad tym, co jeszcze można będzie zrobić z auto? Auto może być użyte do dedukcji typów uniwersalnych referencji pakietu parametrów, w funkcjach o dowolnej liczbie parametrów. Brzmi strasznie ale wbrew pozorom nie jest to takie skomplikowane:

#include <iostream>

using namespace std;

int main()
{
        auto f = [] (auto ... args) {
            ((cout << args << " "), ...);
            cout << endl;
        };

        f(1, 2.3, "cztery");
}

~/cpp_fun>$ ./”variadic_lambdas1″
1 2.3 cztery

Niedługo mam nadzieję będzie to działać nie tylko dla funkcji lambda, ale też dla „zwykłych” funkcji.

std::variant, std::any i ranges-v3 czyli prawie jak w Pythonie.

Ostatnio w ramach „się odstresowywania” czytam sobie o zmianach w standardzie c++17 i c++20 (wielkie dzięki Bartkowi Filipkowi za jego bloga). Dużo tego, ale zmiany są ogromne i dzisiejszy C++ jest po prostu fascynujący. Nawet nie komentuje poniższego kodu. Wklejam tu dla samego siebie i powiem tylko, że jak g++/clang++ będą z c++20 zgodne, to ja już nie chcę nic więcej. Może jeszcze tylko ogarnięcie parallelstl. Intel-tbb działa pięknie. Tylko jeden cytat apropos:

„Do you know how much of the processing power of a typical desktop machine we can utilize using only the core version of C++/Standard Library? 50%, 100%? 10%?[…] we can usually access only around 0,25% with single-threaded C++ code and maybe a few percent when you add threading from C++11/14.” (Sean Parent).

Przyznam szczerze, że nieco otworzyło mi to oczy:

GPU power CPU vectorization CPU threading Single Thread
75% 20% 4% 0,25%
#include <iostream>
#include <vector>
#include <variant>
#include <any>

using namespace std;

template <typename T1, typename T2>
class T {
    T1 a; T2 b;    
    public:
    T(T1 a, T2 b) : a(a), b(b) {}
    void show() {        
        cout << a << b;
    }    
};

int main() {
    T<char, const char*> t1('C', "++");
    T<int, const char*> t2(17, " nie taki straszny ;)\n");
    T<string, int> t3("66.", 6);

    typedef variant<T<char, const char*>, T<int, const char*>, T<string, int>> var_t;
    vector<var_t> var_v {t1, t2, t3};

    auto callShow = [](auto& obj) { obj.show(); };

    for (auto& obj : var_v)
        std::visit(callShow, obj);   

    cout << endl << "------" << endl;

    vector<any>anyv {1, 2.0, "trzy"};

    for(auto &i: anyv) {
        if (i.type() == typeid(int))
            cout << any_cast<int>(i) << endl;     
        if (i.type() == typeid(double))
            cout << any_cast<double>(i) << endl;     
        if (i.type() == typeid(const char *))
            cout << any_cast<const char *>(i) << endl;   
        if (i.type() == typeid(string))
            cout << any_cast<string>(i) << endl;    
    }
}

PS E:\cpp_fun> .\templ1.exe
C++17 nie taki straszny 😉
66.6
——
1
2
trzy

#include <iostream>
#include <range/v3/all.hpp> 
#include <string>
#include <vector>

using namespace std;
using namespace ranges;

int main()
{
    auto print = [](auto &i) {cout << i << " "; };    
    auto even = [](int i){ return 0 == i % 2; };
    auto square = [](int i) { return i * i; };
    auto end = ranges::end;

    vector<int> ints = views::ints(1, 50)  | views::filter(even) | 
                       views::transform(square) | views::slice(end-5, end) | 
                       ranges::to<vector>();

    ranges::for_each(ints, print);

    auto chars = views::iota('a', 'z'+1) | views::reverse
                       | ranges::to<vector>();
    
    ranges::for_each(chars, print);

    auto t = views::ints(0, 50) | 
         views::filter([](int i) { return i<20 ? true : false; }) | 
         ranges::to<vector>();
    
    ranges::for_each(t, print);
    cout << endl;    
}

PS E:\cpp_fun> .\ranges2.exe
1600 1764 1936 2116 2304 z y x w v u t s r q p o n m l k j i h g f e d c b a 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

BTW: dzięki Bartkowi odkryłem, że nie boję się już lambd, a nawet je trochę lubię 😉

Flutter for the Web.

Flutter for the Web

Aplikacje Flutter w przeglądarce? Właśnie na Google Developers Days pojawiło się info o tym, że Flutter for the Web znalazło się w głównym repozytorium. Wystarczy zmienić flutter channel ze stable na master aby zgodnie z opisem tutaj odpalić aplikację w przeglądarce.  Drugi brakujący feature: Foreign Function Interface (FFI). Przyznam szczerze – te zmiany robią wrażenie. Kawał ciekawej i przydatnej technologii. Jedno jest pewne – będzie się działo!

Flutter for the Desktop

Dart i Flutter.

Fajny ten Dart. Jakoś wcześniej nie mogłem się do niego przekonać, ale moje ostatnie eksperymenta z ES6 trochę mi to ułatwiły.

Analizator i system typów robi spore wrażenie. OOP w Dart to chyba najlepsze co do tej pory widziałem – dziedziczenie, interfejsy, klasy i metody abstrakcyjne, mixins, overrides, listy inicjalizacyjne konstruktora, prosta inicjalizacja argumentów nazwanych konstruktora, po prostu trzeba to zobaczyć. Flutter to temat na kilka osobnych wpisów ;), a StatefullWidget mnie zachwycił. Poniżej mój pierwszy eksperyment – kolejne wcielenie apki do sterowania esp8266 za pomocą http request.

Kliknij w obrazek powyżej żeby zobaczyć plik źródłowy.Widać w tym przyszłość i to raczej pozytywną, zarówno dla użytkowników, jak i programistów. A i jeszcze jedno – nie sądziłem, że to kiedyś powiem, ale Visual Studio Code to świetny edytor ;).

Aktualizacja: oficjalnie zaliczam Dart i Flutter do grona zjawisk i technologii, które mnie zafascynowały (patrz strip na górze ;)).

Kliknij w obrazek powyżej żeby zobaczyć plik źródłowy.