Konfiguracja karty graficznej na ubuntu

Ktoś kiedyś powiedział, że Linux jest darmowy dla ludzi których czas nie jest nic warty. I mówiąc szczerze, jest w tym dość dużo prawdy. Szczególnie jeśli chce się korzystać z tego systemu do zastosowań „domowych” – czyli i do pracy i do zabawy. A jedną z sytuacji gdzie to widać jest poprawne skonfigurowanie karty graficznej w laptopie.

Zanim jednak przejdziemy do sedna sprawy musimy mieć kontekst. W „nowoczesnych laptopach” możemy często znaleźć dwie karty graficzne – szczególnie jeśli mówimy o high-endzie czy laptopach gamingowych – „wbudowaną” w procesor, często nazywaną kartą zintegrowaną, czy kartą dedykowaną / zewnętrzną. Takie rozdzielenie ma sens jeśli chodzi o laptopy i ich pracę na baterii. Karta zintegrowana jest wolniejsza i słabsza, ale dzięki temu pobiera o wiele mniej prądu czy też nie nagrzewa aż tak jak karta zewnętrzna. A karta dedykowana jest zaś silniejsza, ale skraca czas pracy na baterii i mocniej nagrzewa laptopa.

Idealnie by było gdybyśmy mogli uruchamiać gry czy inne aplikacje multimedialne na dedykowanej karcie graficznej, zaś całą resztę na zintegrowanej. I tak działa obsługa kart na Windowsie – przy uruchamianiu aplikacji możemy wybrać z którego procesora graficznego ma korzystać. A w niektórych przypadkach system sam wybierze najlepszą opcje.

Jak można się domyślić, tak to nie działa na Linuksie. Po części pewnie dlatego że system graficzny w każdej dystrybucji (czyli X Windows) pierwsze wydanie miał w 1984 roku, czyli 35 lat temu. Innym winowajcą będzie też słaba obsługa takiego mechanizmu przez sterowniki, dlatego że producenci kart graficznych nie uważają Linuksa za platformę gamingową czy też domową.

Kończąc wstęp, posiadam laptopa Dell Inspiron (którego nie polecam) z dwoma kartami graficznymi: zintegrowaną od Intela i dedykowaną od Nvidi.

Problem

Out of the box, zamknięte sterowniki do karty graficznej pozwalają na przełączanie się między nią a zintegrowaną. Takie rozwiązanie ma jednak trzy problemy, pierwsze – by zmienić kartę należy się co najmniej wylogować, drugie – gdy mam odpaloną kartę graficzną laptop się nagrzewa nawet gdy nic się nie jest uruchomione (na przykład jest wyświetlany tylko pulpit), trzeci – czas baterii jest mocno skracany.

Sterowniki otwarto źródłowe, czyli nouveau, nie są wcale lepsze w tym względzie. Dlatego na potrzeby tego artykułu je pominę i będę stosował tylko i wyłącznie oficjalne od Nvidii.

Co chcemy więc zrobić? Chcemy by można było uruchamiać per aplikacja dedykowaną kartę graficzną bez obawy o to że laptop będzie się niepotrzebnie nagrzewał czy skracał czas baterii.

Czytaj dalej »

Aplikacja na pełnym ekranie której nie da się przywrócić

Taki problem miałem na Ubuntu Mate przy aplikacji Spotify. Z jakiegoś powodu aplikacja po obudzeniu laptopa postanowiła być odpalona na pełnym ekranie.

Funkcje otwarcia na pełnym ekranie posiada samo spotify (aktywować można ją w prawym dolnym rogu), ale nie było to to. Po pierwsze, dlatego że widok okna się nie zmienił (wyglądało ono tak samo jak na zdjęciu wyżej), a po drugie nie dało się tego wyłączyć przy pomocy przycisku ESC.

Dlaczego coś takiego się działo? Błąd w systemie, środowisku graficznym czy możne nawet samym spotify (sprawdzając w sieci nie byłem odosobniony z takim błędem). Z perspektywy czasu usunięcie skrótu klawiszowego – który zmieniał tryb okna – pomogło i takie błędy się mi nie pojawiają. Nie wiem jednak dlaczego ten skrót był aktywowany. Na pewno nie naciskałem go świadomie.

Ale jak to można wyłączyć oprócz restartu komputera czy ubicia samej aplikacji? Z pomocą przychodzi terminalowy program: wmctrl. Najpierw musimy pobrać tytuł okna (jeśli go znamy to można ten krok pominąć):

wmctrl -l

U mnie wynik działania tego programu wyglądał tak:

psychob@rgb-lighthouse#192.168.0.24!13:41:40
$ ~ wmctrl -l
0x01200003 -1 rgb-lighthouse Górny panel
0x01200017 -1 rgb-lighthouse Dolny panel
0x01600006 -1 rgb-lighthouse x-caja-desktop
0x04600003  0 rgb-lighthouse Mozilla Firefox
0x0500000b  0 rgb-lighthouse Urządzenia Bluetooth
0x05400007  1 rgb-lighthouse psychob@rgb-lighthouse: ~
0x07600001  5 rgb-lighthouse P.O.D. - Roots in Stereo
0x08200059  0            N/A KeePass
0x04600191  0 rgb-lighthouse Monitoring server-side ECS application with Prometheus and Grafana (see post) : gamedev - Mozilla Firefox
0x0460030c  3 rgb-lighthouse Mozilla Firefox
0x03800007  5 rgb-lighthouse Terminal
0x04800008  4 rgb-lighthouse Skróty klawiszowe

U mnie spotify aktualnie nazywa się: P.O.D. - Roots in Stereo. By zmienić tryb wyświetlania okna należy wykonać następujące polecenie, przy czym nie musimy wpisywać całej nazwy, na przykład:

wmctrl -r "P.O.D" -b toggle,fullscreen

Ogłoszenia parafialne

Pisałem o tym na stronie facebookowej, ale jako że część osób może przychodzić tutaj z dziwnych źródeł to pomyślałem że warto by o tym napisać także tutaj.

Dwa miesiące temu postanowiłem, że zrobię sobie na miesiąc przerwę od publikowania tekstów. Chciałem w ten sposób nagromadzić ich trochę bym później mógł je publikować co tydzień – to w konsekwencji sprawiłoby że nie musiałbym się martwić że się nie wyrobie na deadline. Całe to postanowienie skończyło się tak jak można się domyślić, ostatni wpis na blogu o Red Dead Redemption nie powstał w w/w miesiącu.

Brak przygotowania tekstów nie oznacza że chce zrezygnować z postanowienia o cotygodniowym publikowaniu wpisów na moim blogu. Niestety mój proces pisania zajmuje trochę czasu, jako że potrzebuje zastanowić się nad tym co chce powiedzieć i jak to przekazać.

Dlatego postanowiłem że w tych cotygodniowych wpisach będą pojawiały się też krótsze formy. Wpisy które będą pokazywały rozwiązanie pewnego specyficznego (lub nie) problemu. W zamyśle ma być to taka ściąga na problemy na które napotkałem, a których rozwiązań zawsze szukam bo zapomnę sobie je zapisać.

Taki wpis pojawi się już w tą niedziele koło południa – to będzie pora o której postaram się publikować co tydzień nowe rzeczy.

Kolejny „duży” wpis będzie pewnie dotyczył Red Dead Redemption 2 i o ile chciałbym napisać że będzie on dostępny 24 listopada (czyli za dwa tygodnie), to ta gra jest tak duża że nie wydaje mi że ją skończę do tego czasu. Oprócz tekstu mam nadzieje też nagrać go by można było – zamiast czytania – obejrzeć to na YouTube (co pewnie też zajmie trochę czasu).

Na koniec chciałbym powiedzieć że strumieniuje też rozgrywkę z gier w które gram, a można to zobaczyć na moim kanale na twitch.tv.

Red Dead Redemption

Red Dead Redemption jest jedną z tych gier w którą nie da się zagrać na PC – przynajmniej bez emulatora. To był jeden z powodów dla którego nie zagrałem w tego klasyka studia Rockstar gdy wyszedł on w 2010. Gdy rok temu kupiłem sobie Playstation 3 był to jeden z tych tytułów w który musiałem zagrać, szczególnie że chciałem już wtedy zagrać w trzecią odsłonę serii Red Dead, intuicyjnie nazwaną Red Dead Redemption 2. I rok temu udało mi się tą grę przejść, ale jak to bywa mimo prób nie udało mi się podsumować gry tekstem. Ostatnio postanowiłem wrócić jednak i do gry i do tekstu.

Gra opowiada historię Johna Marstona – rewolwerowca, który w 1911 roku wraca na dziki zachód zmuszony przez swoich nowych „pracodawców”. Jego zadanie to znalezienie i złapanie (żywych lub martwych): Billa Williamsona, Javiera Escuellę i Dutcha van der Linde – którzy byli razem z nim w gangu Dutcha. Jak dowiadujemy się później z gry, John został zmuszony do tego przez nowo powstałe biuro federalne (FBI), które postanowiło złożyć mu propozycję nie do odrzucenia – albo znajdziesz swoich dawnych kompanów, albo już nigdy nie zobaczysz swojego syna i żony.

Nie wiemy jednak wszystkiego od razu, gra rozpoczyna się przerywnikiem filmowym (na silniku gry) gdzie jedyne dialogi jakie są to te zasłyszane od pobliskich NPCów, które opisują nam świat w którym będzie działa się akcja gry. Jeśli chodzi zaś o samego bohatera to wszystko czego się o nim dowiadujemy jest nam przekazane przez jego jego wygląd czy stosunek do innych postaci. Wiemy że naszym protagonistą będzie kowboj, który nie lubi panów w garniturach – w domyśle agentów rządowych.

Po skończeniu przerywnika i dotarciu do celu, którym jest małe miasteczko Armadillo, John Marston wyrusza odwiedzić swojego byłego kompana Billa Williamsona, który razem ze swoim gangiem terroryzuje lokalne hrabstwo. Jak można się domyślić wyruszenie do kryjówki lokalnego watażki i błaganie go o to by się poddał nie jest dobrym pomysłem i John kończy z kulą w piersi. To jest – jak można się domyślić – początek historii Johna.

Gra jest podzielona na cztery rozdziały, gdzie każdy dotoczy jednego członka gangu: pierwszy Billa, drugi Javiera, trzeci Dutcha, ostatni zaś podsumowuje historię samego Johna. I słowa „dotyczy” używam tutaj bardzo szczodrze, bo o ile poznajemy historię Johna, to jedyne czego dowiadujemy się o „głównych złych rozdziału” to tego że zostawili go na śmierć.

Jeśli chodzi o mechanikę, każdy z tych rozdziałów (poza czwartym) odblokowuje część mapy gdzie będzie się działa jego akcja. Z samym odblokowywaniem części mapy mam problem, dlatego że o ile mogę się zgodzić że sąsiednie państwo nie pozwala na przejście granicy i dzięki temu nie możemy się do niego dostać na początku. To nie rozumiem dlaczego hrabstwo odblokowywane w trzecim rozdziale jest zablokowane na początku gry. Przecież jest to część Stanów Zjednoczonych, co nie? Czyżby miastowi nie mogli znieść widoku ciężko pracujących farmerów? Nie czepiałbym się tego, gdyby nie to że gra tłumaczy – w gazecie którą można kupić – dlaczego nie można się dostać aktualnie do meksyku.

Nie będę się tutaj bardzo rozwodził o historii opowiedzianej w grze, dlatego że na samym końcu tego tekstu polecę tą grę przede wszystkim dla niej. Przyczepie się jednak do rozdziału dziejącego się w meksyku i jego konkluzji.

Celem drugiego rozdziału – prócz dorwania Javiera – jest obalenie dyktatora który rządzi daną krainą i zainstalowanie tam jednej z postaci pobocznych. W trakcie naszego zadania poznajemy różne postacie, które z różnym stopniem entuzjazmu reagują na tego typu plany. Rozdział kończy się zamontowaniem nowego „lepszego” dyktatora który – jak dowiadujemy się z gazety na końcu gry – nic nie zmienia.

Problem mam z tym taki, że Marston – jak i sam gracz, czy postacie niezależne – jest wykorzystywany przez tego pretendenta i nic nie można z tym zrobić. Może kłuje mnie to że pretendent się z tym nie kryje, a może to że ten cały rozdział pokazuje to co spotyka idealistów gdy stykają się z realnym cynicznym światem. Można oczywiście doszukiwać się tu paraleli do epilogu, gdzie pokazuje to że nic co zrobimy i tak na końcu nie zmieni naszego losu.

Jeszcze zwrócę uwagę na jeden szczegół z meksyku. W jednej z misji, NPC komentuje że John skacząc między płotem może się na niego nadziać. Jest to aluzja do tego że możemy – i przez możemy rozumiem że w końcu musimy – robić zadania dla aktualnego reżimu. I to może być powód dla którego ludzie nie chcą pomóc mu w znalezieniu Javiera. Problem w tym jest taki, że tą misje da się zrobić zanim zaczniemy ugadywać się z reżimem czy to rebeliantami. Jest to mały problem z ciągłością historii, ale kuło mnie to gdy przechodziłem tę misje.

Jeśli chodzi o rozgrywkę, to mamy tutaj standardową strzelankę trzecioosobową. John Marston strzela tam gdzie wskażemy a do dyspozycji ma różnego rodzaju osłony za którymi możemy się schować. Co prawda nie grałem w GTA 4 na konsoli, ale zgaduje że oba systemy walki są podobne. Red Dead Redemption ma jednak jeden dodatkową mechanikę: system celowania dead eye. Działa to tak że John może w dowolnym – zakładając że nie mamy pustego paska – momencie spowolnić czas i zaplanować gdzie mają lecieć kolejne pociski.

Z jednej strony upraszcza to rozgrywkę – szczególnie jeśli ustawimy w opcjach by system dead eye automatycznie kierował celownik na wroga – i dodaje to de facto specjalny przycisk wyjścia z każdych tarapatów. Ale z drugiej strony, sprawia to że możemy poczuć się jak rewolwerowiec, który dzięki latom praktyki – której my przecież nie mamy – potrafi posłać sześć kolejnych kul w stronę przeciwników którzy mają pecha i stoją po drugiej stronie lufy.

Oprócz walki co możemy jeszcze w tym świecie zrobić? Możemy jeździć na naszym koniu, czy też bardziej generalnie poruszać się. Jeśli chodzi o system poruszania się, to gra preferuje bardziej realistyczne podejście do tematu, dzięki czemu bieganie przypomina bardziej popychanie bohatera niewidzialną ręką rynku.

Jeśli chodzi zaś o konie, to w grze jest ich wiele rodzajów, mają swoje własne statystyki i zamysł projektantów był pewnie taki by je zdobywać (w domyśle kraść, ale można też je ujeżdżać) i zamieniać na lepsze. Tak pewnie by było, gdyby nie to że – w wersji w którą ja grałem czyli Game of the Year – od początku rozgrywki mamy do dyspozycji jednego z najlepszych koni – i to za darmo.

Przy podróży przez dziki zachód możemy spotkać na trasie szeryfa któremu uciekło dwóch więźniów, albo możemy spotkać damę której ktoś ukradł wóz z koniem i tym podobne. Mechanika losowych zdarzeń sama w sobie jest ciekawa, tylko w tej grze jest za mało typów wydarzeń. Pod koniec gry gdy jeździłem po mapie i pojawiało mi się że ktoś potrzebuje mojej pomocy to wiedziałem od razu jakiego typu jest to wydarzenie. Szeryf, pomoc kobiecie, zasadzka, próba kradzieży konia czy zmierzenie się z NPCem w strzelaniu, szukaniu kwiatów czy polowaniu.

Inną rzeczą którą możemy zrobić w świecie gry, jest zbieranie roślin i polowanie na zwierzęta. Same czynności w sobie nie prowadzą do niczego, jedyny zysk jaki z nich mamy to możliwość ich sprzedania. Nie można ich łączyć w jakimś systemie wytwarzania przedmiotów, bo takowy nie istnieje. Jedyne gdzie to zbieractwo się przydaje to do systemu wyzwań.

W grze mamy 6 głównych wyzwań które są podzielone na 10 mniejszych. I nie miałbym nic do tego, gdyby nie fakt że te pod-wyzwania trzeba robić w ustalonej przez dewelopera kolejności. Weźmy dla przykładu wyzwanie Survivalist, które polega na zbieraniu kwiatków. Każdy poziom wyzwania wymaga od nas zebrania odpowiedniej ilości jak i specyficznego typu rośliny. Kwiaty w świecie gry są zazwyczaj zgrupowane w strefy które gracz będzie zwiedzał wykonując główne misje. Co jeśli pójdziemy do nowej strefy zanim skończymy zbieranie kwiatków? To musimy się wrócić. Nie będziemy mieli też zaliczanych roślin z wyższych poziomów wyzwania jeśli uda nam się je znaleźć wcześniej.

Samo zbieranie kwiatów to jest definicja busy-work, chodzimy z punktu A do punktu B szukając kwiatów po drodze. Możemy zmniejszyć ilość błądzenia po mapie dzięki specjalnemu przedmiotowi: Survivalist Map, które przez 20 minut oznacza na naszej mapie lokacje wszystkich kwiatów.

Moim pomysłem na naprawienie tego było by odblokowanie wszystkich „pod-wyzwań” od razu i danie możliwości graczowi by mógł je naturalnie zebrać gdy będzie podróżował po mapie. Sam limit kwiatów do zebrania musiałby pewnie być lekko podwyższony, ale koniec końców – według mnie – ulepszyło by to rozgrywkę.

Inną kwestią są nagrody za zrobienie tych wyzwań. Dla przykładu wykonanie 5 wyzwań z kategorii Survivalist nagradza nas tym, że Survivalist Map działa nie 20 a 40 minut. Zaś zrobienie wszystkich wyzwań z tej kategorii daje nam specjalny przedmiot: Tonik – który odnawia pasek dead eye. Jest to o tyle bezużyteczne że po ukończeniu wszystkich wyzwań z tej grupy nie będziemy potrzebowali korzystać z mapy (bo najbliższe kwiaty i tak się pojawiają na mapie) a pasek dead eye sam się odnawia i w grze są inne przedmioty które potrafią go odnowić a można je kupić w sklepie.

By nadal być negatywny chciałbym ponarzekać jeszcze na animacje. I nie chce pisać że są słabe – bo nie są – tylko jest ich za dużo. Przy zebraniu kwiatka, odpala się animacja. Przy oskórowaniu zwierzęcia, mamy animacje. Przy zbieraniu przedmiotów z zabitych przeciwników – animacja. Nie da się ich pominąć (chyba że uda nam się odpowiednio wjechać koniem) i musimy czekać aż się skończą. A jeśli postanowimy – tak jak ja przy pierwszym przejściu – zajrzeć pod każdy kamień na który się natkniemy czy przeszukać każdego przeciwnika którego pokonamy, to skumuluje nam się dużo animacji. Na dłuższą metę: powtarzalnych i nudnych.

Sama gra bardzo dużo czerpie z innej serii Rockstara czyli z wspomnianego wyżej Grand Theft Auto. Mamy więc poboczne „marnowacze czasu” takie jak poker, blackjack, granie w kości czy rzucanie podkową. Gdzie poker potrafi trwać wiele dni (przynajmniej w świecie gry), a dla mnie mechanika rzucania ową podkową nigdy nie została poprawnie wytłumaczona.

Nagrodą za wygranie w takim pobocznym zadaniu są pieniądze. Według mnie nie opłaca się jednak bawić w coś takiego dlatego że kombo misje + zbieranie paprotek jest bardziej dochodowe – jak ja ukończyłem tą grę pierwszy raz na koncie miałem ponad 10 tysięcy dolarów. Co gorsza, nie miałem na co ich wydać, dlatego że wszystko można znaleźć przy poległych przeciwnikach.

Mamy też system szybkiej podróży który czerpał swoją inspiracje z tego dostępnego w GTA 4. Podróżować możemy albo ze swojego obozu, który możemy rozłożyć w dowolnym miejscu o ile nie jest za blisko miasta, bandytów czy drogi, co tak swoją drogą oznacza więcej animacji. Albo możemy też znaleźć w świecie gry dyliżans który zawiezie nas za opłatą do miejsca do którego chcemy jechać. Tutaj widać inspiracje GTA 4, bo gdy już opłacimy przejazd możemy obserwować jak dyliżans przemierza drogi. Możemy też – jak normalni ludzi – ominąć to i przejść od razu do miejsca docelowego.

Na sam koniec warto wspomnieć o misjach głównych i pobocznych. Misje główne są podtrzymywane przede wszystkim dzięki dialogom, fabule i postaciom. Piszę tak dlatego że schemat misji jest identyczny: idź do jakiegoś miejsca gdzie będziesz strzelał do złych. O ile gra stara się nieco urozmaicić ten schemat poprzez lokacje gdzie będziesz strzelał do innych, to zazwyczaj misja kończy się strzelaniną. Brakuje mi tutaj kreatywności która była choćby w GTA San Andreas czy w prequelu – o którym mam nadzieje w przyszłości napisze – Red Dead Redemption 2.

Misje poboczne – podobnie jak główne – opierają się na scenariuszu. Nie ma w nich aż tylu strzelanin, jednak najwięcej co mogą zaoferować to „fetch questy”, czyli zadania polegające na zdobyciu przedmiotu i zaniesieniu go zainteresowanemu.

Jeśli chodzi o warstwę techniczną, to paleta barw jest dość blada. I o ile gra posiada funkcje zmiany kontrastu/odcieni, to nie rozumiem dlaczego nie jest to ustawione poprawnie domyślnie. Na monitorze 2K gra wygląda… brzydko. Ale z późniejszych testów mogę z pewnością stwierdzić że była to wina rozciągnięcia obrazu który jest domyślnie w 720p.

Muzyka jak i oprawa dźwiękowa jest za to bardzo dobra. Soundtrack gry należy do tych które zostają z tobą nawet jak przejdzie się grę. Mi się osobiście ścieżka dźwiękowa bardzo podoba i jestem szczęśliwy że można ją znaleźć na spotify. Ale z drugiej strony ja ten soundtrack odkryłem zanim zagrałem w grę więc mogę być stronniczy.

Podsumowując, historia jest największym atutem Red Dead Redemption. Sposób w jaki został opowiedziany epilog do historii Johna Marstona i gangu którego był członkiem jest bardzo dobry i nadal ma swój czar w 2019 roku. Oprócz tego muzyka czy atmosfera która wprost wylewa się z ekranu. Rozgrywka zaś – mimo że bardzo powtarzalna – jest wystarczająco ok by nie nudzić. Te wszystkie cechy są powodem dla którego mogę bez żadnych skrupułów polecić tą grę.

Prince of Persia (2008)

Prince of Persia, jest jednym z klasyków gier komputerowych. Oryginalnie wydany w 1989 roku na komputer Apple II (a później w zasadzie na wszystkie inne platformy), przeszedł długą drogę od oryginalnej trylogii, wykupienie praw do serii przez Ubisoft i stworzenie przez nich trylogii Piasków Czasu, aż do 2008 roku gdzie zostanie wydana gra o takiej samej nazwie: Prince of Persia. Co powoduje że muszę dodać do tytułu tego wpisu rok jej wydania, by ludzie wiedzieli o której grze pisze.

Głównym powodem dla którego Ubisoft Montreal – w którym powstały między innymi gry z trylogii Piasków Czasu – postawił na taki ruch był reset serii. Z perspektywy ponad dekady, możemy stwierdzić z pewnością, że reset był nieudany. W tej sub serii gier powstała tylko jedna gra – tytułowy Prince of Persia (2008) – i jedno DLC, które z tego co rozumiem zawiera zakończenie którego brak w bazowej grze. A kolejną grą z serii (ignoruje gry mobilne i Ty drogi czytelniku także powinieneś) jest The Forgotten Sands który kontynuuje historię z Piasków Czasu.

Miała być to pierwsza gra z serii wydana na konsole next gen, którymi wtedy były Playstation 3 i Xbox 360. Jak dobrze pamiętam, jej port na PC miał nie mieć żadnego DRM, co było interesującym wyborem w tamtym czasie. Trudno mi stwierdzić czy się to opłaciło, na Wikipedii jest napisane że w miesiąc (gra była wydana w grudniu 2008 roku, a raport jest ze stycznia 2009) sprzedano ponad dwa miliony kopii na wszystkie platformy.

Zanim przejdę do krytyki gry, chciałbym wspomnieć że grałem w tą grę na PC plus/minus dekadę temu, nawet w jego pełną polską wersję której teraz nie da się kupić oficjalnie (przynajmniej w sklepie Ubisoftu). Na początku myślałem że jest to sytuacja podobna jak przy pierwszym Assassin’s Creedzie którego w Polsce wydawała Cenega i Ubisoft nie ma praw do jego tłumaczenia, ale nie na Wikipedii jest napisane że to Ubisoft Polska wydawał tutaj grę. Więc decyzja o tym, by nie można było kupić tego tytułu po polsku jest dość dziwna.

Wracając z tej dygresji, chciałem napisać że miałem z tą grą związane miłe wspomnienia – z dzisiejszej perspektywy kompletnie nie rozumiem czemu – ale pamiętałem też o tym że końcówka była rozczarowująca. Dekadę później odświeżam sobie tą grę na PS3. Mając ten wstęp za sobą możemy omówić grę:

Czytaj dalej »

Konfiguracja Linuksa

Największym plusem Linuksa jest to że można go mocno spersonalizować i dostosować do swoich potrzeb. W tym wpisie opiszę konfiguracje z której ja korzystam i która – mam nadzieje – ułatwi Wam w jakiś sposób korzystanie z Linuksa.

GRUB

Jedną z pierwszych rzeczy którą pamiętam przy korzystaniu z Linuksa było to że przy uruchamianiu go zawsze wyświetlał się log zamiast tak zwanego splash screenu. Aktualnie nie jest to jednak domyślna konfiguracja. By to zmienić należy zmodyfikować plik: /etc/default/grub i zmienić linie:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

na:

GRUB_CMDLINE_LINUX_DEFAULT=""

Po modyfikacji należy wykonać następujące polecenie:

sudo update-grub2

Snap

Snap jest jednym z wielu menedżerów paczek który jest dostępny na Linuksa – głównie na Ubuntu i ich różnego rodzaju dystrybucje. Jego plusem jest to że dystrybuuje aplikacje razem z zależnościami i umieszcza je w stosownym sandboxie.

Nie miałem z nim problemów, do czasu aż nie zauważyłem że wrzuca wszystkie zainstalowane aplikacje do /var/snap: który u mnie jest na mniejszym – szybszym dysku. Jako że przez snapa zainstalowałem między innymi dockera, nie podobała mi się perspektywa by cały dockerowy cache, volumeny i tego typu pliki przetrzymywać na dysku systemowym. Ale jako że nie jest to windows, można ten katalog przenieść w inne miejsce.

By przenieść snapa, nie można po prostu przenieść katalogu i zrobić symlinka, jako że snap korzysta z AppArmour które tego typu zachowań nie lubi. By go przenieść, musimy więc zamountować odpowiedni katalog.

Na samym początku należy wyłączyć samego demona snapa:

services snapd stop

Gdy już to zrobimy należy – jako root – skopiować zawartość katalogów: /var/lib/snapd i /var/snap do nowych lokalizacji – tam gdzie ich miejsce, przy okazji z oryginałów robiąc backup:

cp -r /var/lib/snapd ~/.offload_drive/snapd
cp -r /var/snap ~/.offload_drive/snap

mv /var/lib/snapd /var/lib/snapd.bak
mv -r /var/snap /var/snap.bak

Później należy utworzyć te katalogi na nowo, jako że gdy chcemy coś zamountować, to musimy mieć do tego katalog.

mkdir /var/lib/snapd
mkdir /var/snap

Na sam koniec należy dodać do pliku /etc/fstab następujące linie:

/home/psychob/.offload_drive/lib_snapd    /var/lib/snapd  none  bind     0    0
/home/psychob/.offload_drive/var_snap     /var/snap       none  bind     0    0

I zatwierdzić to poleceniem:

mount -a

Źródło: 1

Bash

Bash jest domyślnym shellem w Ubuntu i wyłącznie z tego powodu jest tym z którego korzystam. A skoro już z niego korzystam, to miło jest go sobie spersonalizować. Tutaj jedyne co opiszę to jak zmodyfikować $PS1, czyli tak zwany prompt.

Najprostszą rzeczą przy modyfikacji promptu, jest skorzystanie z gotowych generatorów, na przykład z bashrcgenerator.com. Na tej stronie wystarczy wyklikać sobie wymarzonego prompta, i gdy skończymy to wystarczy wygenerowany kod dodać na końcu pliku: ~/.bashrc.

Ale skoro już upiększyliśmy sobie prompta, to fajnie byłoby gdyby wyświetlał nam brancha jeśli jesteśmy w jakimś repozytorium. By to zrobić, należy do $PS1 dodać następujące wyrażenie:

$PS1 +="\$(__git_ps1 '(%s) ')"

Ale nie zadziała to tak od razu, bo potrzebujemy mieć jeszcze definicje funkcji __git_ps1, można ją znaleźć na stronach githuba. By wszystko zadziałało, należy dodać przed skorzystaniem z w/w funkcji kod który dołączy ten plik do naszego ~/.bashrc.

source ścieżka-do-pliku

Źródło: 1,2,3,4

Docker

Docker jest jednym z tych narzędzi które na stałe weszły do zestawu narzędzi każdego dewelopera (czy tego chce czy nie), więc dobrze jest go sobie poprawnie skonfigurować.

By nie było potrzeby przełączanie się na roota za każdym razem gdy chcemy coś zrobić z naszymi kontenerami, warto dodać naszego użytkownika jako zaufanego. By to zrobić należy dodać siebie do grupy docker.

sudo usermod -a -G docker psychob

Przy czym może zdarzyć się to, że po zainstalowaniu dockera, nie będziemy mieli takiej grupy. W takim wypadku należy ją stworzyć:

sudo groupadd docker

Docker domyślnie korzysta z sieci 172.12/16, może być to dość niefortunne gdy w naszym domu lub pracy korzystamy z takiego zakresu, na szczęście łatwo jest to zmienić w konfiguracji. W pliku /etc/docker/daemon.json (lub jeśli zainstalowaliście dockera przez snapa to: /var/snap/docker/current/config/daemon.json), należy dodać następującego json’a:

{
  "bip": "172.26.0.1/16"
}

Po tym należy zrestartować dockera

Źródło: 1,2

SSH

SSH jest wygodnym sposobem na uwierzytelnienie siebie w komunikacji z innymi serwerami. W szczególności jeśli korzystamy z szyfrowania asymetrycznego i kluczy RSA.

Zawsze gdy konfiguruje na nowo system, to nigdy nie pamiętam jakie uprawnienia mają mieć pliki id_rsa i id_rsa.pub:

chmod 0600 id_rsa      # RW only for owner
chmod 0644 id_rsa.pub  # RW for owner, Read for anyone else

Innym problem zaczyna się wtedy, gdy musimy korzystać z większej ilości kluczy, jak wtedy zarządzać nimi by ssh samo wiedziało który klucz służy do jakiego połączenia? Służy do tego plik ~/.ssh/config.

Należy w nim wymienić zapisać hosty z którymi się chcemy łączyć, jak i kluczy z których powinien korzystać.

Host work.git.com
    HostName work.git.com
    User git
    IdentityFile ~/.ssh/id_rsa_work


Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa


Źródło: 1, 2

Firefox

Bardzo dużo czasu spędziłem na Windowsie i przyzwyczaiłem się do konfiguracji firefoxa która jest domyślnie na tym systemie. Co prawda nie rozumiem dlaczego różni się ona między systemami, ale pewnie jest to jedna z tych rzeczy które dawno temu zostały ustalone i nikt nie chce ich teraz zmienić.

By zmienić niżej wymienione rzeczy należy wejść na stronę about:config i zmienić następujące rzeczy:

Co jest zmieniane Klucz Wartość
Klawisz backspace odpowiada za cofnięcie się do poprzedniej strony browser.backspace_action 2
Firefox nie wyłącza się gdy zamkniemy ostatnią kartę browser.tabs.closeWindowWithLastTab false

Źródło: 1, 2

VIM

VIM jest jednym z tych narzędzi na którego ludzie lubią psioczyć, nie bez powodu. Jest to trudne w obsłudze narzędzie które ma tą zaletę że jest w zasadzie zainstalowane wszędzie. Można je nawet ulepszyć stosując odpowiednią konfiguracje, a taka znajduje się na wiki vima. Dla mnie jest wygodniej jak wyłączy się obsługę myszy:

" Enable use of the mouse for all modes
" set mouse=a

Źródło: 1

PHPStorm/Jetbrains IDE

Projekty przy których pracujemy mogą być bardzo duże, dlatego środowiska programistyczne od jetbrains sugerują by dostosować konfiguracje systemu. Dzięki zmianie konfiguracji PHPStorm czy jakiekolwiek inne środowisko od nich będzie potrafiło szybciej indeksować zmiany w naszym projekcie.

By zwiększyć maksymalną ilość obserwowanych plików należy utworzyć nowy plik: /etc/sysctl.d/60-jetbrains.conf, z zawartością:

# Set inotify watch limit high enough for IntelliJ IDEA (PhpStorm, PyCharm, RubyMine, WebStorm).
# Create this file as /etc/sysctl.d/60-jetbrains.conf (Debian, Ubuntu), and
# run `sudo service procps start` or reboot.
# Source: https://confluence.jetbrains.com/display/IDEADEV/Inotify+Watches+Limit
# 
# More information resources:
# -$ man inotify  # manpage
# -$ man sysctl.conf  # manpage
# -$ cat /proc/sys/fs/inotify/max_user_watches  # print current value in use

fs.inotify.max_user_watches = 524288

Zmiana zostanie zaaplikowana po restarcie.

Źródło: 1, 2

Spotify

Z jakiegoś powodu, gdy zainstalowałem spotify przez snapa, środowisko graficzne – u mnie jest to mate – nie potrafiło wyświetlić go przy widgecie który odpowiadał za głośność systemu.

Poprawienie tego było proste, należało zmienić nazwę jednego pliku:

sudo mv /var/lib/snapd/desktop/applications/spotify_spotify.desktop /var/lib/snapd/desktop/applications/spotify.desktop

Źródło: 1

Obsługa błędów w PHP

Co się powinno dziać gdy w programie zostanie napotkany błąd? W najlepszym przypadku: poinformuje nas o tym kompilator lub interpreter, co – przynajmniej w teorii – zmusi nas do jego naprawienia. Innym dobrym rozwiązaniem jest przerwanie wykonywania programu tak by nieprawidłowa operacja nie wyrządziła żadnych szkód. Opcjonalnie dobrze by było by aplikacja mogła przechwycić tego typu błąd, by później go wyświetlić w zjadliwej formie. W najgorszym wypadku, aplikacja zignoruje ten błąd i będzie kontynuowała wykonywanie.

Problem

PHP posiada dwa mechanizmy raportowania błędów, które wpisują się w całe spektrum przedstawione wyżej. Ma ono wyjątki (Exception) jak i błędy (trigger_error, ale nie możemy mylić tego ze specjalną wersją wyjątku Error, czy też inną specjalną wersją wyjątku ErrorException). Miło by było, gdyby w następnej wersji jedna z tych funkcjonalności została porzucona (i by to były błędy) na korzyść drugiej (czyli wyjątków).

Wyjątków tutaj nie chce jakoś mocno omawiać, bo są one zaimplementowane podobnie jak w każdym normalnym języku programowania, a jeśli macie doświadczenie z Javą to się szybko z nimi odnajdziecie.

Błędy są specyficznym mechanizmem który składa się z dwóch kroków: pierwszy to wyświetlenie na ekranie błędu który właśnie wystąpił, a drugi to – w zależności od tego czy interpreter potrafi poradzić sobie z błędem – przerwanie skryptu albo wykonanie go zakładając że to czego nie ma to NULL.

Tego typu błędy są wyzwalane (z ang. trigger) w zasadzie w każdej sytuacji gdy PHP nie potrafi poradzić sobie z błędem, dla przykładu:

<?php
    $array = [
        // this array doesn't have any key
    ];

    // this line will emit warning
    var_dump($array['missing-key']);

    // this line will also emit warning
    var_dump($non_existing_var);


Jeśli wykonamy taki kawałek kodu, to dostaniemy taką informacje z interpretera:

PHP Notice:  Undefined index: missing-key in /home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php on line 9
PHP Stack trace:
PHP   1. {main}() /home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php:0
/home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php:9:
NULL
PHP Notice:  Undefined variable: non_existing_var in /home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php on line 12
PHP Stack trace:
PHP   1. {main}() /home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php:0
/home/psychob/Projekty/Blog/php-error-handling-weirdness/01-php-emitting-errors.php:12:
NULL


Jak można zauważyć, PHP założył że w zmiennych których nie ma znajduje się wartość NULL.

Innym miejscem gdzie interpreter nas poinformuje błędem, jest jeśli podamy do funkcji niepoprawną ilość argumentów, na przykład:

<?php
    var_dump(strlen('string', 'bad-argument'));
    var_dump(strlen());


Taki skrypt na wyjściu da nam:

PHP Warning:  strlen() expects exactly 1 parameter, 2 given in /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php on line 5
PHP Stack trace:
PHP   1. {main}() /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:0
PHP   2. strlen() /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:5
/home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:5:
NULL
PHP Warning:  strlen() expects exactly 1 parameter, 0 given in /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php on line 6
PHP Stack trace:
PHP   1. {main}() /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:0
PHP   2. strlen() /home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:6
/home/psychob/Projekty/Blog/php-error-handling-weirdness/02-incorrect-argument-count-to-system-function.php:6:
NULL

Ten konkretny przypadek może być jednak zmieniony w wyjątek automatycznie jeśli skorzystamy z „nowej” funkcjonalności PHP czyli declare(strict_types=1), na przykład:

<?php
    declare(strict_types=1);

    var_dump(strlen('string', 'bad-argument'));
    var_dump(strlen());

Ale nie zadziała to przy wywoływaniu funkcji które my zdefiniowaliśmy, na przykład:

<?php
    declare(strict_types=1);

    function my_func($abc, $def)
    {
    }

    my_func(1, 2, 3, 4);


Jak widać, PHP wyzwoliło dwa rodzaje błędów: Notatkę (Notice) i Ostrzeżenie (Warning). Oba typy błędów charakteryzują się podobnym zachowaniem: Poinformuj użytkownika, i kontynuuj wykonywanie zakładając że to czego nie ma jest równe NULL.

Ale PHP posiada jeszcze inne typy błędów, o – bardzo intuicyjnej nazwie – Błąd (Error). W tej puli znajdują się błędy które nie pozwalają na poprawne wykonanie skryptu, na przykład nie poprawna składnia, nie istniejąca klasa, nie istniejąca funkcja, itp.:

<?php
    return unknown_function('?');


Zwróci nam:

PHP Fatal error:  Uncaught Error: Call to undefined function unknown_function() in /home/psychob/Projekty/Blog/php-error-handling-weirdness/05-fatal-error-unknown-function.php:2
Stack trace:
#0 {main}
  thrown in /home/psychob/Projekty/Blog/php-error-handling-weirdness/05-fatal-error-unknown-function.php on line 2

<?php

    interface /* Empty */  {

    }


Zwróci nam:

PHP Parse error:  syntax error, unexpected '{', expecting identifier (T_STRING) in /home/psychob/Projekty/Blog/php-error-handling-weirdness/06-fatal-error-bad-grammar.php on line 3


Co możemy zrobić?

Pierwszą rzeczą która przychodzi na myśl, to po prostu wyłączenie raportowania błędów

error_reporting(0)

error_reporting pozwala na wyłączenie wyświetlania błędów przez PHP. Jest to na pewno przydatna funkcjonalność którą wypada skonfigurować na środowisku produkcyjnym, a jej działanie wygląda tak:

<?php
    /** @noinspection PhpUndefinedVariableInspection */

    error_reporting(0);

    $array = [
        // this array doesn't have any key
    ];

    // this line will emit warning
    var_dump($array['missing-key']);

    // this line will also emit warning
    var_dump($non_existing_var);


Na wyjściu powinniśmy dostać:

/home/psychob/Projekty/Blog/php-error-handling-weirdness/07-error-reporting.php:11:
NULL
/home/psychob/Projekty/Blog/php-error-handling-weirdness/07-error-reporting.php:14:
NULL


Tylko nie jest to idealne rozwiązanie, dlatego że błąd w kodzie nadal jest, my tylko spowodowaliśmy że nie można go zobaczyć. Dlatego idealnym rozwiązaniem byłoby gdybyśmy mogli taki błąd zmienić w wyjątek. I da się to zrobić przy pomocy paru narzędzi które twórcy nam przygotowali, a mówiąc konkretnie set_error_handler i ErrorException.

set_error_handler

set_error_handler jest funkcją która pozwala nam na zastąpienie domyślnego error handlera naszym własnym. Funkcja ta przyjmuje dwa argumenty: funkcje która ma być wywołana w przypadku błędu jak i dla których typów błędu ma być wykonana.

Przykładowa funkcja która zacznie rzucać wyjątki w przypadku wystąpienia błędu wygląda tak:

set_error_handler(function (int $level, string $message, string $file, int $line) {

 if (error_reporting() === 0) {

 return;

 }

 

 throw new \ErrorException($message, 0, $level, $file, $line);

});


Taka implementacja zapewni nam że wszystkie błędy które można przechwycić, rzucą wyjątek. Warto tutaj też zwrócić uwagę na warunek który zwróci nam wartość null z funkcji, jest to obsługa specjalnego operatora który istnieje w PHP: ‘@’ tak zwany operator STFU. O ile nie jest zalecane korzystanie z niego, to nigdy nie wiemy która z naszych zależności będzie z niego korzystać. Co do zwracanej wartości, to jeśli nasz handler zwróci wartość false, to kontrole przejmie domyślny handler (ten co wyświetla błąd na standardowym wyjściu).

Ale co z błędami których przechwycić się nie da? Bo jak to przystało na PHP, istnieją błędy których się nie da przechwycić przy pomocy set_error_handler, dla przykładu:

<?php
    set_error_handler(function (int $level, string $message, string $file, int $line) {
        if (error_reporting() === 0) {
            return;
        }

        throw new ErrorException($message, 0, $level, $file, $line);
    });

    interface foo
    {
        public function bar();
    }

    class baz implements foo
    {
    }


Co można w takim wypadku zrobić?

register_shutdown_function

Należy zaznaczyć tutaj, że tego typu błędów nie da się przechwycić w taki sposób by można było kontynuować normalną egzekucje programu, dlatego że w większości przypadków jest to brak zaimplementowanej metody która jest w interfejsie, abstrakcyjna metoda itp. Nie zmienia to faktu, że możemy zareagować na tego typu błąd i możemy wyświetlić swoją informacje o błędzie.

By to zrobić, należy podpiąć się pod „shutdown function”, czyli funkcje która będzie wykonywana po zakończeniu skryptu, służy do tego funkcja register_shutdown_function. I nie ma tu rozróżnienia czy wykonywanie zakończy się sukcesem czy porażką. W naszym przypadku taka funkcja mogłaby wyglądać tak:

    register_shutdown_function(function () {
        $lastError = error_get_last();
        if ($lastError !== NULL) {
            throw new ErrorException($lastError['message'], 0, $lastError['type'], $lastError['file'],
                $lastError['line']);
        }
    });


Jak można zauważyć z implementacji, sprawdzamy jaki był ostatni błąd i jeśli nie został obsłużony to rzucamy wyjątek. Tutaj pojawia się pytanie: Skoro ten kawałek kodu wykona się już po zakończeniu skryptu, to jak taki wyjątek złapać?

Nie da się, nawet przy pomocy set_exception_handler. By przejąć tego typu wyjątek należy go samemu przekazać do naszego exception handlera, albo obsłużyć go w tej funkcji.

set_exception_handler

set_exception_handler działa tak samo jak set_error_handler, z tym wyjątkiem że ta funkcja jest wykonywana gdy zostanie rzucony wyjątek i nie zostanie on złapany przy pomocy bloku try...catch. Po wykonaniu naszego exception handlera, wykonywanie skryptu się zakończy.

Przykład takiej funkcji:

<?php
    set_error_handler(function (int $level, string $message, string $file, int $line) {
        if (error_reporting() === 0) {
            return;
        }

        throw new ErrorException($message, 0, $level, $file, $line);
    });

    set_exception_handler(function (Throwable $e) {
        var_dump($e->getMessage());
        var_dump($e->getTraceAsString());
    });

    var_dump($array); // not existing variable


set_error/exception_handler a register_shutdown_function

Warto wspomnieć o różnym zachowaniu między tymi funkcjami. set_error/exception_handler przy wywołaniu podmienią aktualnego handlera, a starego wrzucą na stos którego można przywrócić przy pomocy funkcji restore_error/exception_handler. Takie zachowanie może się przydać, jeśli chcemy błędy obsługiwać „blokowo”, czyli w części aplikacji będziemy chcieli zamieniać błędy na wyjątki (bo ta część je obsługuje), a w innej chcemy na przykład je ignorować, bo jest to część legacy naszej aplikacji.

register_shutdown_function, rejestruje kolejną funkcje która zostanie uruchomiona po zakończeniu wykonywania skryptu. Czyli jeśli odpalimy ją dwa razy, to nasza funkcja zostanie wykonana dwa razy.

Podsumowanie

PHP posiada dwa konkurujące ze sobą mechanizmy raportowania błędów. Na szczęście jeden jest w odwrocie i – miejmy nadzieje – zostanie wkrótce zastąpiony w całości przez wyjątki.