lampy

eh. i kolejny produkt którego nie mam jak kupić 🙁
trafiłem na stronę firmy eurofase. wbrew nazwie nie ma nic wspólnego z europą.
firma zajmuje sie produkcją wszystkiego co świeci. żyrandole, kinkiety, lampy ogrodowe. i to co robią jest zdecydowanie mniej "masowe" – w rozumieniu wyglądu, a i pewnie ceny.
przykłady które mnie zafascynowały – seria żyrandoli opartych na motywach roślinnych:

perl best practices critic

jakiś czas temu damian conway napisał "perl best practices" ("perl. najlepsze rozwiązania"). zawarł w niej szereg sugestii jak pisać.
książkę ogólnie polecam, choć nie zgadzam się ze wszystkim co napisał. ale to już inna bajka.
w oparciu o to co napisał, powstał program: perlcritic (można go zainstalować przez "install Perl::Critic" w shellu cpanowym).
program ten analizuje twój program perlowy i wypisuje błędy (błędy czytaj konstrukcje inne niż zalecane przez damiana). wraz z odnośnikami do numerów stron w książce!
warto zobaczyć jak to wygląda. przykładowo. dla jednego z moich (działających!) programów wynik perlcritica wygląda tak:

=> perlcritic archiveMails.pl
Code before strictures are enabled at line 9, column 1.  See page 429 of PBP.  (Severity: 5)
Integer with leading zeros at line 75, column 55.  See page 58 of PBP.  (Severity: 5)
Don't modify $_ in list functions at line 94, column 37.  See page 114 of PBP.  (Severity: 5)

nie najgorzej. nie? zobaczmy co się dzieje jak każę mu wyświetlać wszystkie błędy, a nie tylko krytyczne:
ojć. całości nie pokażę. za dużo, ale to mogę pokazać:

=> perlcritic -1 archiveMails.pl  | wc -l
69

to mało mówi. więc zróbmy prostą statystykę:

=> perlcritic -1 archiveMails.pl  | perl -pe 's/at line \d+, column \d+/at line X, column Y/' | sort | uniq -c | sort -nr
     14 Mixed-case variable name(s) at line X, column Y.  See page 44 of PBP.  (Severity: 1)
     10 Regular expression without "/x" flag at line X, column Y.  See page 236 of PBP.  (Severity: 3)
      9 Regular expression without "/m" flag at line X, column Y.  See page 237 of PBP.  (Severity: 2)
      6 Builtin function called with parens at line X, column Y.  See page 13 of PBP.  (Severity: 1)
      4 Postfix control "unless" used at line X, column Y.  See pages 96,97 of PBP.  (Severity: 2)
      3 Useless interpolation of literal string at line X, column Y.  See page 51 of PBP.  (Severity: 1)
      3 Subroutine does not end with "return" at line X, column Y.  See page 197 of PBP.  (Severity: 4)
      2 "unless" block used at line X, column Y.  See page 97 of PBP.  (Severity: 2)
      2 Mixed-case subroutine name at line X, column Y.  See page 44 of PBP.  (Severity: 1)
      2 File handle for "print" is not braced at line X, column Y.  See page 217 of PBP.  (Severity: 1)
      1 RCS keywords $Revision$, $Source$, $Date$ not found at line X, column Y.  See page 441 of PBP.  (Severity: 2)
      1 RCS keywords $Revision$, $HeadURL$, $Date$ not found at line X, column Y.  See page 441 of PBP.  (Severity: 2)
      1 RCS keywords $Id$ not found at line X, column Y.  See page 441 of PBP.  (Severity: 2)
      1 Postfix control "if" used at line X, column Y.  See pages 93,94 of PBP.  (Severity: 2)
      1 Package variable declared or used at line X, column Y.  See pages 73,75 of PBP.  (Severity: 3)
      1 No "VERSION" variable found at line X, column Y.  See page 404 of PBP.  (Severity: 2)
      1 Integer with leading zeros at line X, column Y.  See page 58 of PBP.  (Severity: 5)
      1 Forbid $b before $a in sort blocks at line X, column Y.  See page 152 of PBP.  (Severity: 1)
      1 Double-sigil dereference at line X, column Y.  See page 228 of PBP.  (Severity: 2)
      1 Don't modify $_ in list functions at line X, column Y.  See page 114 of PBP.  (Severity: 5)
      1 Code is not tidy at line X, column Y.  See page 33 of PBP.  (Severity: 1)
      1 Code before warnings are enabled at line X, column Y.  See page 431 of PBP.  (Severity: 4)
      1 Code before strictures are enabled at line X, column Y.  See page 429 of PBP.  (Severity: 5)
      1 Capture variable used outside conditional at line X, column Y.  See page 253 of PBP.  (Severity: 3)

łał. a przypominam – ten kod działa i robi co trzeba.
tak czy inaczej – warto spojrzeć. to co perlcritic pokazuje, to czasem całkowicie nieistotne szczegóły (jak np. mixed case variable name), ale czasem jest to coś co warto poprawić. sam po przeczytaniu best practices sporo zmieniłem w swoim stylu kodowania.

gotowanie na filmie

jak może zauważyliście co jakiś czas robię sesję zdjęciową nt. gotowania.
jakiś czas temu zauwazyłem, że wszystkie książki z przepisami są pisane dla ludzi którzy już umieją gotować. po prostu takie przypominajki. o dużej ilości rzeczy nie mówią, lub traktuja jako oczywiste i warte tylko jednego słowa.
stąd wzięła się wizja fotografowania (nie mam kamery, bo jakbym miał to bym kręcił filmiki).
dziś trafiłem na stronę videojug. zawiera ona filmy pokazujące różne rzeczy które można robić w życiu. nie tylko gotowanie. zajmowanie się zwierzakami, majsterkowanie, sporty, maseczki pielęgnacyjne itd.
ale to część kuchenna mnie zauroczyła.
każdy przepis jest sfilmowany. bez udziału aktorów – po prostu pokazują co i jak się dodaje, jak się miesza, ile czasu. co trzeba mieć. filmy są po angielsku co może lekko utrudniać (ktoś wie czemu w przepisie na jambalayę mówią "green pepper" a pokazują coś co wygląda jak poszatkowana zielona papryka?).
ale poza tym – cód, miód i orzeszki. są przepisy na praktycznie każdy rodzaj żarcia. od zup, przez dania główne, desery aż po takie ciekawostki jak sałatka "coleslaw" znana choćby z kfc.

drzewa w sql’u – metoda “zagnieżdżonych zbiorów”

metodę zagnieżdżonych zbiorów poznałem po raz pierwszy po przeczytaniu którejś z książek joe celko. chyba tej: Advanced SQL Programming, ale na 100% nie jestem pewien.
zagnieżdżone zbiory (nested sets) polegają w duzym skrócie na tym, że każdy element drzewa jest opisany nie jednym id, ale parą liczb. są to w miarę dowolne liczby, z założeniem jedynie takim, że "lewa" jest mniejsza od "prawej", oraz, że obie liczby (lewa i prawa) wszystkich elementów drzewa poniżej danego muszą się mieścić w zakresie (lewa, prawa) swoich rodziców.
skomplikowane? też nie zrozumiałem.
przypomnijmy sobie nasze oryginalne, testowe drzewo:

teraz.
tworzymy sobie taką tabelkę:

# create table nested_sets ( id_left int4 primary key, id_right int4 not null check (id_left < id_right), name text);

jako primary key wybrałem sobie id_left, ale mogłem wybrać też right. w szczególności – wartości w polach id_left i id_right muszą być unikatowe. czyli jeśli w którymś elemencie w polu id_left jest wartość 5, to nie może się ona powtórzyć ani w id_left ani w id_right.
ok. jak nadać numerki?
proste. zaczynamy od elementu głównego, i przyznajemy mu id_left = 1. potem idziemy do jego pierwszego dziecka. jego id_left dajemy kolejny numer. jeśli ten element ma podelementy, to powtarzamy zejście w dół z przyznawaniem kolejnych id_left. jeśli dany element nie ma "dzieci", to nadajemy mu id_right równy kolejnej liczbie. i wracamy piętro wyżej.
mało jasne? pewnie nie umiem za dobrze opisać. więc lecimy w krokach:

  1. elementowi sql, przypisujemy id_left = 1, i schodzimy w dół do "postgresql".
  2. elementowi postgresql, przypisujemy id_left = 2, i ponieważ ma jakieś dzieci, schodzimy w dół – do "linux"
  3. elementowi linux przypisujemy id_left = 3
  4. ponieważ linux nie ma "dzieci", przypisujemy mu id_right = 4 i wracamy wyżej
  5. ponieważ postgresql nie ma "dzieci", przypisujemy mu kolejne id_right. czyli id_right = 5. i wracamy wyżej.
  6. jesteśmy z powrotem w sql. wchodzimy w kolejne dziecko – oracle
  7. elementowi oracle przypisujemy id_left = 6.
  8. itd. aż dojdziemy do ustawienia dla elementu sql, id_right = 18

zwracam uwagę na to, że w tej numeracji widać od razu, że ilość elementów jest równo połową największego id_right. co jest poniekąd logiczne.
cała tabelka wygląda tak:

id_left id_right name
1 18 sql
2 5 postgresql
3 4 linux
6 17 oracle
7 8 solaris
9 14 linux
10 11 glibc1
12 13 glibc2
15 16 windows

ok. jak się pyta taką bazę?
tu uwaga – ten model znam najsłabiej. głównie dlatego, że go osobiście nie lubię. jeśli znajdziecie błąd w tym co poniżej napiszę – proszę o informację. nie jestem nieomylny, a jak już mówiłem – tego modelu drzew nie lubię i nie bawiłem się nim w ogóle.
1. pobranie listy elementów głównych (top-levelowych)

SELECT
    ns1.*
FROM
    nested_sets ns1
    LEFT OUTER JOIN nested_sets ns2 ON (ns1.id_left > ns2.id_left AND ns1.id_right < ns2.id_right)
WHERE
    ns2.id_left IS NULL
;

zwrócić należy uwagę na fakt iż jeśli nasze drzewo ma tylko i wyłącznie 1 element top-levelowy to zapytanie można uprościć do:

# SELECT * FROM nested_sets WHERE id_left = 1;

jeśli stosujemy numerację od 1, lub

# SELECT * FROM nested_sets ORDER BY id_left ASC LIMIT 1;

jeśli numeracja startuje od nieznanej liczby.

2. pobranie elementu bezpośrednio “nad” podanym elementem:

dane wejściowe:

  • ID : id_left elementu
SELECT
ns.*
FROM
nested_sets ns
WHERE
[ID] BETWEEN ns.id_left + 1 AND ns.id_right
ORDER BY ns.id_left DESC LIMIT 1

jeśli zapytanie nic nie zwróci – znaczy to, że dany element był “top-levelowy”.

3. pobranie listy elementów bezpośrednio “pod” podanym elementem

dane wejściowe:

  • ID : id elementu
SELECT
nsc.*
FROM
nested_sets nsp
JOIN nested_sets nsc ON (nsc.id_left BETWEEN nsp.id_left + 1 AND nsp.id_right)
WHERE
nsp.id_left = [ID]
AND NOT EXISTS (
SELECT *
FROM nested_sets ns
WHERE
( ns.id_left BETWEEN nsp.id_left + 1 AND nsp.id_right )
AND
( nsc.id_left BETWEEN ns.id_left + 1 AND ns.id_right )
)

4. pobranie listy wszystkich elementów “nad” danym elementem (wylosowanym)

dane wejściowe:

  • ID : id elementu
SELECT
    ns.*
FROM
    nested_sets ns
WHERE
    [ID] BETWEEN ns.id_left + 1 AND ns.id_right

5. pobranie listy wszystkich elementów “pod” danym elementem (wylosowanym)

dane wejściowe:

  • ID : id elementu
SELECT
    nsc.*
FROM
    nested_sets nsp
    JOIN nested_sets nsc ON nsc.id_left BETWEEN nsp.id_left + 1 AND nsp.id_right
WHERE
    nsp.id_left = 6

6. sprawdzenie czy dany element jest “liściem” (czy ma pod-elementy)

dane wejściowe:

  • ID : id elementu
>SELECT true from nested_sets WHERE id_left = [ID] AND id_right = [ID] + 1;

jeśli zwróci true – to jest liść. jeśli nic nie zwróci – to nie jest liściem.

7. pobranie głównego elementu w tej gałęzi drzewa w której znajduje się dany (wylosowany) element

  • ID : id elementu
SELECT
    ns.*
FROM
    nested_sets ns
WHERE
    [ID] BETWEEN ns.id_left + 1 AND ns.id_right
ORDER BY
    ns.id_left ASC LIMIT 1

podstawową zaletą tego rozwiązania jest to, że bardzo szybko zwraca listę wszystkiego "nad", "pod" czy listę liści.

wadami jest mała intuicyjność, skomplikowane przenoszenie elementów (gdybym miał to zaimplementować, to najprawdopodobniej po prostu po każdym przeniesieniu od nowa bym numerował id_left/id_right.

dodatkowo – część zapytań wymaga albo "order by xxx limit 1", albo subselectów co raczej nie wróży dobrze wydajności. a order by limit 1 nie zawsze można użyć (np. użycie tego w joinach jest już mocno problematyczne).

latający dywan

właśnie przeczytałem o nowym produkcie do domu. zasadniczo dla dzieci, ale ja tam bym się nie obraził jakbym dostał 🙂
jest to .. dywan. z podpórkami typu "górki". w sumie – ciężko opisać. lepiej zobaczcie:

oczywiście konfiguracja górek jest dowolna.
chętni do kupienia? zapraszam tu – ale uprzedzam – nie jest to najtańszy dywanik.

vista – system którego nie można używać? c.d.

jakiś czas temu pisałem o opracowaniu nt. kosztów drm w windows vista. dziś dzięki informacji od znajomego (yo, negativ 🙂 dowiedziałem się, że w sieci pojawiło się pełne tłumaczenie tego tekstu na polski. warto spojrzeć by wiedzieć co nas czeka w najbliższym czasie. aha. tekst jest długi.

second life – open source!

w 1990 mało znany (wtedy) pisarz – neal stephenson opublikował swoją trzecią książkę – snowcrash, znaną pod polskim tytułem zamieć.
książka ta w/g mnie (i pewnie nie tylko) jest genialna. krótką recenzję jej napisał alex.
w książce tej stephenson przedstawił wizję "ulicy". jest to wirtualny świat (metawers), do którego dostęp jest z całego świata, korzystają z niego miliony ludzi. do czego? do wszystkiego. by pogadać, ubić biznes, spotkać się. to samo co w rzeczywistości. ale lepiej – bo w miejscu gdzie nie widać, że nie stać cię na porządne ciuchy czy mieszkanie.
w oparciu o wizję przedstawioną w książce (aha – ulica nie jest osią fabularną książki, jest to bardziej skomplikowane, polecam recenzję alexa oraz własnooczne przeczytanie 🙂 powstało kilka realnych produktów informatycznych.
w większości nieznanych.
z jednym wyjątkiem.
tym wyjątkiem jest "second life" firmy linden labs.
oczywiście można by się spierać czy second life "pochodzi od" metawersu. tym co mnie przekonuje to fakt, że tak jak i metawars tak i second life nie są grami mmorpg. nie łączysz się z grą by zabić smoka czy wziąć udział w jakiejś misji. łączysz się by po prostu żyć. tak jak chcesz. chcesz jeździć na desce? samochodem? projektować ciuchy? stać się gwiazdą? czy może wielkim posiadaczem ziemskim? to wszystko jest możliwe. i nie jest istotne jak wyglądasz w rzeczywistości. nie ważne, że nie masz kasy na paliwo do swojego "malucha". w second life możesz jeździć hummerem czy innym czołgiem. czy być projektantem wziętych ubrań. czy choćby "call-girl".
po co? a po co ludzie robią cokolwiek modyfikującego rzeczywistość? prochy? alkohol? światy gier rpg?
anyway – z second life korzystają setki tysięcy (jak nie miliony) ludzi. świat ten ma swoją walutę (wymienialną na dolary). ma gazety. ma spotkania. ma wszystko co ten (no, poza fizycznym kontaktem, ale to się pewnie zmieni).
najlepszym miernikiem rzeczywistości tego świata jest fakt iż dzienny obrót giełdy na której można kupić (za dolary lub "lindeny") rzeczy do użycia w grze przekroczył milion dolarów. faktycznych. prawdziwych.
ludzie kupują i sprzedają wszystko. ziemię, przedmioty, czas (np. wynajmując się do jakichś prac w second life).
od dawna chciałem spróbować. wejść w ten świat i zobaczyć czy i na ile odbiega od moich wyobrażeń stephensonowej ulicy. ale nie mogłem. aplikacje klienckie były tylko na windows i macos'a (była wersja linuksowa, ale miała kupę bugów).
ale. stał się cud. linden labs otworzyli kod klienta na licencji gpl v2. pozwoli to na szybkie udostępnienie klienta linuksowego. dzięki czemu i ja będę mógł sobie urządzić biuro w tym świecie.
po co? po to co inni. swoje biura w second life otworzyły już firmy takie jak microsoft, toyota, intel, cnet networks, dell, reuters czy sun. ma spotkania ze znanymi (w tym świecie – "first life"). ma swoich terrorystów. niedługo może się okazać, że to tam życie będzie oferowało więcej – choćby ze względu na faktyczny brak granic.