Dziś kumpel miał za zadanie zrobić prostą funkcję, która z kolekcji usług spełniających odpowiednie kryteria wybierze jedną, której da specjalne przywileje. Jeśli w wybranym zestawie znajdzie się usługa danego typu, to tej usłudze, pierwszej w kolejności należy te przywileje dać.

Tych usług spełniających kryteria nawet w najgorszym wypadku nie ma więcej jak kilkanaście, więc można wybrać sobie wszystkie do (w tym przypadku) Perla, i odpowiednią pętlą z warunkami znaleźć te co trzeba. Zamiast tego, przerzuciliśmy to do MySQL, sortując tych kilka elementów:

[...] ORDER BY `type`, `id` LIMIT 1[...]

Byłoby idealnie, gdyby nie to, że najbardziej potrzebny nam typ wcale nie jest pierwszy w kolejności (niezależnie czy pierwszy od początku czy od końca ;) ). Zakładając, że mamy typy liczbowe: 1, 2, 3, 4, 5, i chcemy mieć je w kolejności: najpierw wszystkie z typu 3, później wszystkie z typu 5, kolejno wszystkie z typu 2, a reszta bez znaczenia, to zaczyna robić się ciekawie ;) Jednym ze sposobów jest użycie UNII. My użyliśmy innego: funkcji FIELD(). Jak działa w ogóle ta funkcja, można przeczytać w podlinkowanym kawałku manuala. Niżej za to jest przykład, jak jej użyć do naszego celu:

SELECT `f1`, `f2`, `type` FROM `table` WHERE [warunki] ORDER BY FIELD(`type`, 3, 5, 2, 1, 4) ASC, `id` ASC

Tym sposobem mamy posortowane tak jak chcemy elementy, i mniej zabawy po odebraniu danych ;) Ale uwaga: to nie jest optymalne rozwiązanie, jeśli trzeba przetworzyć większą ilość elementów! Użycie funkcji (w tym wypadku FIELD()) przy sortowaniu/w warunku spowoduje że MySQL będzie musiał gdzieś sobie przechować dane do posortowania, i zazwyczaj użyje tabeli tymczasowej (chyba że tych danych będzie niewiele). A jedno z drugim potrafi nieco zamulić maszynę ;)


Wczoraj odbyła się druga konferencja z serii 4Developers. I ja tam byłem, Allegro i herbatę piłem, ciastek się najadłem i w ogóle ;)

Sama konferencja była podzielona na 4 ścieżki: Zarządzanie projektami IT, Java, .Net & C# oraz PHP. Ja wybrałem sobie kilka wykładów z Zarządzania projektami IT (w sumie większość) i zahaczyłem także o wykłady nt. PHP.

Pierwszy wykład na którym byłem, była to zrealizowana w formacie Pecha Kucha (coś na kształt Lightning Talk) seria 3 prezentacji na tematy dotyczące, a jakże, zarządzania ;) Podobało mi się, 3 panów z organizacji PMI Poznań fajnie poopowiadało o tematach takich jak “Produktywne lenistwo”, “Przyczyny porażek startupów” i “Projekt w opałach”. Wykłady dużo nowego mi nie powiedziały, ale kilka rzeczy nazwały po imieniu w miejscach gdzie się czegoś domyślałem, albo zwróciły mi na coś uwagę. Ogólnie zdecydowanie za.

Kolejny wykład który mnie interesował, odbył się w tej samej sali, też z Zarządzania projektem IT. Tym razem Monika Konieczny opowiadała o tym, jak można pogodzić/ułatwić współpracę testerów z programistami. Trzeba przyznać, że Monika miała świetny pomysł z ciastem ;) Oprócz tego, że wykład dał mi sporo tematów do przemyśleń i podsunął trochę pomysłów, to z przyjemnością patrzyło się na kogoś kto z łatwością i zaangażowaniem prowadził zajęcia. Widać było, że Monika raz, wiedziała o czym mówi, dwa, ma sporo swoich przemyśleń na ten temat, trzy, była doskonale przygotowana. Myślę że dla mnie to najlepszy wykład na całej konferencji. A Monice tylko pogratulować :)

Na następny wykład miałem dylemat: pójść na PHP: “Aplikacje internetowe wydajne od początku”, czy zostać na Zarządzaniu projektami IT: “Zarządzanie rozwojem oprogramowania – nieco bardziej ‘funky’”. W końcu stwierdziłem że trochę technikaliów mi nie zaszkodzi, poszedłem sobie na PHP. Jeszcze wtedy nie wiedziałem co czynię… Panowie niestety nie dość że byli słabo przygotowani do wykładu (więcej czytali ze slajdów niż byli w stanie powiedzieć, patrzyli co chwila na siebie, który ma właśnie mówić etc), to nie do końca mieli pojęcie o czym mówią. Niestety. Być może później wyprostowali trochę swój wizerunek, ale tego już nie wiem, bo wyszedłem po 15 minutach. Po tym jak kilkukrotnie potraktowali wymiennie bufor z cache (używali tych słów jak synonimów), a wcześniej puścili kilka innych bezsensownych stwierdzeń. Najgorszy z możliwych wykładów IMHO.

Po tym jak uciekłem z “Aplikacji internetowych wydajnych od początku”, poszedłem na wspomniane “Zarządzanie rozwojem oprogramowania – nieco bardziej ‘funky’”. Peter Horsten poopowiadał nieco o rzeczach które znałem już doskonale, więc sam temat mnie nie do końca zainteresował (myślałem że będzie to nieco głębsze wejście w temat, tutaj było tylko pobieżnie), ale sam sposób prowadzenia wykładu to bajka. Najlepiej poprowadzony wykład na całym 4Developers, z tych na których byłem. Peter z lekkością i wprawą poopowiadał o wszystkim, z humorem, etc. Z przyjemnością go słuchałem :)

Po lunchu znów poszedłem na wykład PHP: “PHP wysokiej wydajności”. Tutaj było zdecydowanie lepsze przygotowanie techniczne Mariusza Gila niż kolegów od wydajności z poprzedniego wykładu. Nie było już wrażenia że nie wie o czym mówi, wręcz przeciwnie, większość tego o czym wspominał znam z własnych testów, choć nigdy nie miałem tak porywającego serwisu napisanego w PHP żebym musiał to stosować w praktyce :) Ogólnie sam wykład mnie nie szczególnie zainteresował, bo bardzo niewiele nowego miałem okazję się dowiedzieć (zapisałem sobie chyba tylko kilka nazw narzędzi z którymi warto żebym się zapoznał), ale oceniam go znacznie wyżej niż poprzedników ;)

Później już nie wychodziłem ze ścieżki “Zarządzania projektami IT”. Najpierw Jakub Dąbkowski w fajny sposób, z humorem, poopowiadał o jednym z aspektów metodyki Scrum, czyli o pytaniach jakie są ważne podczas “scrum meeting”. Wykład oceniam wysoko, Jakub zwrócił uwagę na powody dla których te pytania są ważne dla członków zespołu.

Następnie byłem na “Praktyce zarządzania portfelem projektów IT”. Okazało się jednak, że temat nie zainteresował mnie tak bardzo jak na to liczyłem. Wygląda na to, że te 40 minut jakie miał Szymon Włochowicz to zdecydowanie za mało na omówienie choćby częściowo tego tematu, usłyszeliśmy ledwie zajawkę, więc na sali było sporo osób które, jak mi się wydaje, podobnie jak ja nie zostali przekonani do takiego podejścia.

Ostatnim wykładem był “Łączenie ognia i wody – proces projektowy w Gratka Technologie”, ale tutaj było za mało interesujących tematów, ot, prelegent poopowiadał o swoich doświadczeniach, niestety myślę że zrobił to nieco za wcześnie, gdyż jeszcze miał ich nieco za mało. Mam mocno mieszane uczucia odnośnie tej prezentacji.

Ogólnie jestem bardzo zadowolony z całości. Ciekawe wykłady, rewelacyjne hostessy ;) darmowy wyjazd (sponsorowany przez firmę ;) ), i nie za daleko od domu (w sensie: mało czasu straconego w ciapągu) – zdecydowanie było warto :) Do tego stopnia, że jak tylko będę miał możliwość, to w przyszłym roku na pewno się wybiorę na kolejną edycję – nawet pomimo tego że konkurs komiksowy wygrał rysunek uzupełniony z oryginalnego Garfielda, a nie nasz :)


Bawię się ;)

Zainspirowany serwisem Kiedy Będzie Wielkanoc by Marcin Kaszyński, zrobiłem sobie bardziej ogólną zabawkę ;) Moja wersja pokazuje najbliższy dzień wolny – uwzględnia weekendy i święta (według listy z Wikipedii) :) Jeśli ktoś chce, to może kliknięciem sobie wyłączyć wyliczanie dla sobót i/lub niedziel (prawy górny róg), ale nie jest to na razie zapamiętywane (będzie pewnie w ciachu). I tyle ;)

Dostępne pod: ZaIleWolne.pl – enjoy! ;)


Używałem już Windowsa, używałem przez wiele lat Linuksa. Od ponad roku mam okazję pracować na co dzień na Macu – i nie wrócę już ani do Linuksa (którego bardzo sobie chwaliłem), ani do Windowsa (którego chwaliłem sobie znacznie mniej :) ). Mac to dla mnie świetne połączenie obydwóch wspomnianych na początku systemów: prostoty obsługi Windowsa, i mocy i funkcjonalności Linuksa. Tyle tytułem wstępu :)

Postanowiłem sobie zrobić małą listę programów na Maca (czasem nie tylko), bez których nie wyobrażam sobie pracy – lub które mi ją po prostu uprzyjemniają :) a jednocześnie spowodować aby coś się w końcu na tym blogu pojawiło ;)

Przejdź do reszty tego wpisu »


Jakiś czas temu chciałem pobawić się Blip!em za pomocą Pythona. Ot, mam w planach zrobienie sobie coś a’la Sekretarka (która oddaje nieocenione usługi – dzięki ^TomaszTopa :) ), tyle żeby wysyłał codziennie lisię prywatnych i kierowanych do mnie statusów na maila. Prosta dość sprawa, trzeba tylko do tego zasiąść ;) Ale nadszedł ten dzień, i się zmusiłem. Jako, że wiedziałem że do Blip!a istnieją aż dwie biblioteki napisane w Pythonie (lista różnych aplikacji znajduje się na Blip!owym wiki), to po prostu uznałem że skorzystam z którejś z nich… Ech, za dobrze by było. Żadna z nich nie jest na tyle kompletnym rozwiązaniem, żeby jej w normalnych warunkach użyć. Oczywiście nie mam pretensji do ich autorów – stworzyli narzędzie którego potrzebowali, i podzielili się nim ze światem, czyli jest OK :)

Jednak to spowodowało na razie zarzucenie moich planów o Pythonowej Emailowej Sekretarce ™ ;) Owszem, również mógłbym napisać w sumie dwa polecenie do pobierania statusów kierowanych i prywatnych (directed_messages i private_messages) ale ja lubię kompleksowe rozwiązania – tak samo jak dla WP-Blip!a napisałem BlipApi.php :)

Jest w tej chwili jeden drobny błąd (zauważony przez ^mrkjego blog, dzięki :) ) związany z tym, że podczas testowania siedziałem w folderze gdzie są wszystkie pliki bilbioteki, i tak jakoś było łatwiej… no i w tej chwili nie działa to poprawnie jako osobny moduł Pythona tylko jak luźne pliki które gdzieś w PYTHONPATH trzeba umieścić ;) Błąd ten, jako że zaczynam dochodzić do się, niedługo postaram się naprawić oczywiście, być może zgłoszę też bibliotekę do Python Package Index. A na razie zapraszam do pobierania: blipapi.googlecode.com, używania i zgłaszania problemów i/lub nowych featur :)


Dawno tu nie pisałem… No cóż, (bardzo) dużo pracy, życie osobiste i takie tam – to odstrasza od blogowania ;) Jeśli już, to od czasu do czasu coś publikuję jeśli chodzi o zdjęcia, a sprawy “kodowe” to raczej “robię” niż o nich piszę :)

Jako że od kilka dni jestem na L4, to się ostro opierdzielam, ale dopiero dziś jestem w stanie podjąć jakikolwiek intelektualny wysiłek… No to popatrzyłem sobie m.in. na GoldenLine. Dziś na forum PHPowym ktoś poruszył dość banalny problem, ktoś inny podrzucił rozwiązanie (preg_replace_callback (), a ja zacząłem się zastanawiać czemu wszyscy w PHP tak napierają na regexpy (rozumiem w Perlu, ale PHP?). Jak zacząłem się zastanawiać jak to zrobić bez regexpów, to zacząłem się bawić w zakodowanie tego ;)

Najpierw zrobiłem dość banalną wersję, przy użyciu strlen (), strpos () i substr (), i chciałem ją podać jako wersję hardcore ;) Wtedy pomyślałem sobie, że prawdziwa wersja hardcore, to byłaby bez użycia tychże funkcji… najprostsza postać tego to zastąpienie tychże funkcji swoimi ;) I o ile substr () i strpos () są dość banalne, o tyle dla mnie prawdziwym hardcorem jest strlen () ;)

Oczywiście nie są to najbardziej optymalne wydajne rozwiązania (a jeśli są to tylko przypadkiem), bo jeśli chodzi o optymalizację, to trzeba by używać wersji natywnych to trzeba by się najpierw zastanowić i sprawdzić czy jest co optymalizować… :) A całość warto potraktować stricte jako zabawę, którą dla mnie było pisanie tego :)

W całym “problemie” chodziło o zastąpienie w tekście wystąpień “[userId]ID[/userId]” tym, co zostanie wyplute przez dodatkową funkcję której podajemy zawartość tego co jest między znacznikami. Użycie preg_replace_callback () jest chyba najbardziej intuicyjnym rozwiązaniem, ale nie jedynym… :) Poniżej obydwie wersje: hardcore i bardziej hardcore – enjoy ;)

hardcore

function replace_user_id ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => strlen ($tags['start']),
        'end'   => strlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = strlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = strpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = strpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= substr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (substr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

bardziej hardcore

class __mstrlen__ErrH {
    private static $error = false;
    private function __construct () {}
    static public function errh ($errno, $errstr, $errfile = '', $errline = 0, $errctx = array ()) {
        if ($errno != E_NOTICE) {
            return false;
        }

        $expected = 'Uninitialized string offset';
        for ($i=0; $i<26; ++$i) {
            if ($expected[$i] != $errstr[$i]) {
                return false;
            }
        }

        self::$error = true;
    }
    public static function isError () {
        return self::$error;
    }
    public static function zero () {
        self::$error = false;
    }
}

function mstrlen ($str) {
    $str = (string) $str;

    $len = -1;
    __mstrlen__ErrH::zero ();
    set_error_handler (array ('__mstrlen__ErrH', 'errh'), E_NOTICE);
    while (__mstrlen__ErrH::isError () === false) {
        ++$len;
        $q = $str[$len];
    }

    restore_error_handler ();
    return $len < 0 ? 0 : $len;
}

function mstrpos ($str, $seek, $offset=0) {
    if (!is_int ($offset) || $offset < 0) {
        $offset = 0;
    }

    $str_len = mstrlen ($str);
    if ($offset > $str_len) {
        return false;
    }

    $seek_len = mstrlen ($seek);
    for ($i=$offset; $i < $str_len; ++$i) {
        for ($j=0; $j < $seek_len; ++$j) {
            if ($str[$i + $j] != $seek[$j]) {
                break;
            }
        }

        if ($j == $seek_len) {
            return $i;
        }
    }
    return false;
}

function msubstr ($str, $start, $length = null) {
    $str_len = mstrlen ($str);
    if (!is_int ($start)) {
        trigger_error ('Incorrect offset');
    }
    else if ($start >= $str_len) {
        return false;
    }
    else if ($start < 0) {
        $start = $str_len + $start;
    }

    if (!is_int ($length)) {
        $length = $str_len - $start;
    }
    else if ($length < 0) {
        $length = $str_len + $length - $start;
    }
    else if ($length + $start > $str_len) {
        $length = $str_len - $start;
    }

    $ret = '';
    for ($i=0; $i < $length; ++$i) {
        $ret .= $str[$i + $start];
    }

    return $ret;
}

function replace_user_id2 ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => mstrlen ($tags['start']),
        'end'   => mstrlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = mstrlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = mstrpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = mstrpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= msubstr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (msubstr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

wwwshell.php to skrypt napisany w php, pozwalający obejść część ograniczeń związanych z brakiem shella na hostingu. Jako że w home.pl takowego nie ma, musiałem jakiś czas temu ratować się takim wynalazkiem ;)

Założeniem które przyświecało od początku jego istnienia była kompaktowość (wszystko w jednym pliku), używalność, wygoda. Wydaje mi się że jak na razie spełnia wszystkie wymienione ;) Ograniczeniami są PHP >= 4.3.0 i nie zablokowane wykonywanie funkcji proc_open () i proc_close ().

Zalety (z mojego punku widzenia ;) ):

  • wszystko w jednym pliku (biblioteki jQuery pobierane są bezpośrednio z serwera jQuery.com
  • obsługa aliasów
  • prostota użytkowania
  • historia poleceń

Wady:

  • no cóż, to jednak nie prawdziwy shell…
  • brak uzupełniania
  • uprzyjemniacze typu historia wymagają połączenia z netem lub modyfikacji skryptu i używania lokalnych kopii bibioteki jQuery

Znane błędy:

  • nie zapamiętuje ustawionego rozmiaru czcionki w okienku wyjścia
  • czasem z jakiegoś powodu historia nie działa, trzeba np. otworzyć okienko konsoli w ff i je zamknąć, wtedy jest ok :/

Nie sprawdzałem też (ani nawet nie zamierzam jak na razie) sprawdzać jak wygląda i działa pod IE. Może się coś sypać :)

Jeśli ktoś jest zainteresowany tą zabawką, to zapraszam do pobierania na GoogleCode, i komentowania/krytykowania pod tą notką ;)


Mały bugfix release (zgłoszony przez WPNinja): W przypadku gdy nie można zapisać pliku z cache do katalogu ustawionego jako zmienna $wp_blip_cacheroot, próbuje zapisać do systemowego katalogu tymczasowego (o ile się uda takowy znaleźć). Gdy także i ta operacja się nie powiedzie, zostanie rzucony E_USER_NOTICE z informacją o problemie, a wtyczka po prostu nie będzie korzystała z funkcji cacheowania wpisów.

Do pobrania z GoogleCode. Jak zawsze proszę o informacje i uwagi nt działania wtyczki, a także ucieszyłbym się z informacji że ktoś gdzieś moich wypocin używa :)


Strona 1 z 15