poniedziałek, 30 czerwca 2008

Nowe obiektywy

Kupiłem do E-510 lepsze obiektywy, konkretnie używane na ebay.com. Na allegro mało jest ofert sprzedaży obiektywów Olympusa. Są wprawdzie w ciągłej sprzedaży z przemytu z USA, ale w ten biznes nie chciałem wchodzić. Nowy Zuiko 14-54 ED kosztuje wg. ceneo minimum 1700 zł, z przemytu via Allegro ca 1300--1400 zł. Ja kupiłem za 950 zł na ebay.co.uk. Jeszcze taniej jest na ebay.com ale później kłopot pn. urząd celny. Założyłem, że nie ma sensu aż tak bardzo oszczędzać:-) Do tego 14-54 dokupiłem jeszcze drugi, większy 50-200 ED. To jest starszy model, bez napędu SWD.

Nowe obiektywy są dużo jaśniejsze niż te standardowe, dołączane ,,w promocji'' do aparatu. Są też znacząco cięższe. Różnicę widać patrząc na średnicę soczewek (cf. zdjęcie obok).

poniedziałek, 23 czerwca 2008

TBL o bogactwie

Pro memoria wyjątek z książki sir Tima Bernersa-Lee (s. 107, podkreślenie moje): People have sometimes asked me whether I am upset that I have not made a lot of money from the Web. In fact, I made some quite conscious decisions about which way to take my life. These I would not change -- though I am making no comment on what I might do in the future. What does distress me, though, is how important a question it seems to be to some. This happens mostly in America, not Europe. What is maddening is the terrible notion that a person's value depends on how important and financially successful they are, and that that is measured in terms of money. That suggests disrespect for the researchers across the globe developing ideas for the next leaps in science and technology. Core in my upbringing was a value system that put monetary gain well in its place, behind things like doing what I really want to do. To use net worth as a criterion by which to judge people is to set our children's sights on cash rather than on things that will actually make them happy.
-- Tim Berners Lee with Mark Fischetti, Weaving the WEB. The original design and ultimate destiny of the World Wide Web, by its inventor, ISBN-13: 978-0062515872, Harper Collins 2000.

niedziela, 22 czerwca 2008

Ebay REST API

`Na szybko' zrobiłem trzy skrypty wykorzystujące Ebay REST API. Skrypty mają ułatwić wyszukiwanie oraz archiwizowanie interesujących mnie aukcji. Próbowałem wykorzystać do ww. celu gotowe narzędzie ale jakoś nic interesującego nie znalazłem. Bibioteka Net::eBay jakaś taka słabo udokumentowana i nieporęczna mi się wydała podobnie jak WWW::Search::Ebay. (Por. skrypt opisany np. tutaj.)

Najbardziej skomplikowany z moich skryptów wykorzystuje metodę FindItemsAdvanced do wyszukania aukcji. Metoda FindItemsAdvanced ma parametr MaxEntries określający liczbę zwracanych aukcji. Parametr ten ma domyślną wartość 20 a maksymalną akceptowaną wartością jest 200 (jeżeli podamy 0 to metoda zwróci liczbę pasujących do zapytania aukcji). Jeżeli aukcji jest więcej niż wynosi wartość MaxEntries, to aby ściągnąć kolejne aukcje metodę FindItemsAdvanced trzeba wykonać wielokrotnie, podając odpowiednią wartość parametru PageNumber. Przykładowo jeżeli aukcji jest 121, a wartość MaxEntries wynosi 40, to trzeba FindItemsAdvanced wykonać 4 razy.

Parametr ItemSort ustala porządek sortowania. Wartość StartDate tego parametru powoduje, że aukcje są posortowane według daty wstawienia na ebay (daty/czasy są definiowane w GMT oczywiście).

W związku z takim działaniem metody FindItemsAdvanced skrypt ebay_rest_search.pl najpierw ustala liczbę pasujących aukcji, a następnie pobiera kolejno strony w pętli do momentu aż znajdzie aukcję już pobraną (aukcje są przechowywane w haszu %IdxLog, który jest przechowywany na dysku przy wykorzystaniu funkcji store/retrieve modułu Storable). Nowe aukcje są dodawane do hasza %IdxLog:


## Uproszczony fragment skryptu:
while ( ($current_page >= 0) && ($current_page <= $last_page ) ) {
$current_page++;
$xml = make_call('search_text' => $search_text, 'per_page' => $MAX_PER_PAGE,
'site_id' => "$this_site_id", 'page' => $current_page);

my $xm = $xmlp->XMLin($xml, ForceArray => 0);
my $list = $xm ->{'SearchResult'}->{ItemArray}->{Item} ;

foreach $item ( @{$list} ) {
$item_id = $item->{'ItemID'};

if ( exists $IdxLog{ $item_id } ) {## zakończ
$current_page = -99; last ; }
else { $new_items++;
$IdxLog{ $item_id } = [ $item->{'Title'}, $item->{'StartTime'}, $item->{'EndTime'},
$item->{'GalleryURL'}, $item->{'ListingStatus'},
$item->{'ViewItemURLForNaturalSearch'}, $day_added ];
}
}
}

Metoda XMLin jest z modułu XML::Simple. Moduł ten definiuje prosty interfejs do dokumentów XML. Po wykonaniu XMLin, zawartość dokumentu jest dostępna w postaci elementów zagnieżdżonych list/haszy. Można oczywiście analizować dokument XML w inny sposób, nie upieram się że XML::Simple jest najlepszym pomysłem.

Uwaga: metoda FindItemsAdvanced nie umożliwia przeszukania całej bazy eBay (odpowiednik wyszukiwanie zaawansowane->preferowana lokalizacja->cały świat). Parametr siteid określa, który serwis eBay ma być przeszukany. Jeżeli podamy id=0 to zapytanie dotyczyć będzie ebay.com, a jeżeli id=212, to ebay.com.pl, itd. Aby przeszukać cały ebay to trzeba wykonać FindItemsAdvanced wielokrotnie.

Następnie hasz %IdxLog jest przeglądany w pętli celem archiwizacji aukcji, które się zakończyły:


for $id (sort { $IdxLog{$a}[2] cmp $IdxLog{$b}[2] } keys %IdxLog) {
$end_time = $IdxLog{$id}[2]; # drugi element listy to czas zakończenia
$time_to_end = $now_in_seconds - ebaydate2seconds( $end_time );

if ($time_to_end > 0 && $status =~ /Active/) {# Aukcja zakończona
$result = `ebay_rest_item.pl -i $id`; ## ściągnij innym skryptem

if ($? > 0 ) { warn "Problems backuping $id\n"; } else {
$IdxLog{$id}[4] = 'Completed'; # zmień status na zakończoną
$completed_items++; }
}
}

Zmienna $now_in_seconds, to liczba sekund od epoch a funkcja ebaydate2seconds zmienia napis zawierający czas w formacie zwracanym w dokumencie XML na liczbę sekund od epoch. Jeżeli różnica czasu bieżącego a czasu zakończenia aukcji wskazuje, ze aukcja się zakończyła jest ona ściągana za pomocą skryptu ebay_rest_item:


#!/usr/bin/perl
use LWP::Simple;
use Getopt::Long;

my $verbose = 1;
use lib "$ENV{HOME}/.ebay"; ## configuration files

GetOptions('item=s' => \$ebay_item_id, 'help' => \$print_help, );
unless ($ebay_item_id) { die "Usage: $0 -i <item_id>\n"; }

our $netebay_rc;
require("netebay.rc");

my $url = "http://open.api.ebay.com/shopping?callname=GetSingleItem" .
"&responseencoding=XML" .
"&appid=$EBayRC{p_appid}" .
"&siteid=0" .
"&version=525" .
"&ItemID=$ebay_item_id" .
"&IncludeSelector=Description,Details";

my $xml = get $url ;

## In a scalar context m//g iterates through the string, returning true each time
## it matches. If you modify the string in any way, the match position is reset.
my %Pics;
while ($xml =~ /<PictureURL>([^<>]+)<\/PictureURL>/mg) { $Pics{$1} = 1; }

my $pic, $ori_pic;

for $pic (keys %Pics ) {
$ori_pic = $pic; $ori_pic =~ s/\?/\\\?/g; # zmieniamy meta znaki: ?
$pic =~ s/\?[^\?]+$//g;
my ($content_type, $document_length, $modified_time, $expires, $server) = head($pic);

$pic_no++;

if ( $content_type =~ /image/ ) { $content_type =~ m/\/(.+)$/;
$local_file = "${ebay_item_id}_${pic_no}.$1"; }
else { $local_file = "${ebay_item_id}_${pic_no}.JPG?"; } ## problems with content_type

warn "Storing $pic in $ARCH_DIR/$local_file ... \n";
getstore($pic, "$ARCH_DIR/$local_file");

## zapisz lokalną nazwę jako atrybut
## Uwaga na metaznaki (? już jest obezwładniony):
$xml =~ s/<PictureURL>$ori_pic/<PictureURL local='$local_file'>$ori_pic/;

}

open (LOG, ">$ARCH_DIR/$ebay_item_id.xml" ) ||
die " ** cannot open $ARCH_DIR/$ebay_item_id.xml **";

print LOG "$xml\n";

Ten skrypt zapisuje po prostu dokument XML zwrócony przez metodę GetSingleItem. Argumentem skryptu jest id aukcji. Jedyne utrudnienie związane jest z pobraniem zdjęć. Adresy URL do zdjęć są zdefiniowane wewnątrz elementów PictureURL. Aby uprościć skrypt elementy te są wyszukiwane przy pomocy prostego wyrażenia regularnego. Konstrukcja:


while ($napis =~ /wzorzec/mg) { ## $1 zawiera dopasowany do wzorca napis }

Będzie dopasowywać wzorzec do $napisu iteracyjnie. W każdej iteracji zmienna $1 będzie zawierała kolejny napis pasujący do wzorca. Aby powyższe działało prawidłowo $napis nie może być modyfikowany wewnątrz pętli (i nie jest). Adresy URL są składowane w haszu %Pics.

Teraz hasz %Pics jest przeglądany w pętli. Zdjęcia są ściągane a dodatkowo dokument XML jest modyfikowany -- też za pomocą wyrażeń regularnych -- w taki sposób, że do elementu dodawana jest informacja o nazwie lokalnej zdjęcia. Nazwa lokalna jest tworzona automatycznie jako: ${ebay_item_id}_${pic_no}.$1, gdzie ${pic_no} jest kolejnym numerem zdjęcia dla aukcji o numerze ${ebay_item_id}.

Ostatni skrypt jest najprostszy i drukuje fragment drzewa kategorii eBay (konkretnie podkategorie dla kategorii, której id podano jako argument skryptu). Korzeń drzewa ma id równe -1.


#!/usr/bin/perl
use LWP::Simple;
use Getopt::Long;

use lib "$ENV{HOME}/.ebay"; ## configuration files
use $ebay_site_id = 'US'; ## 0 is US ebay

GetOptions( 'site=s' => \$ebay_site_id, 'category=i' => \$ebay_cat_id,
'help' => \$print_help, );
unless ($ebay_cat_id) {$ebay_cat_id = -1 } ## top-level

our $netebay_rc;
require("netebay.rc");

my $site_id_code = $Sites_Ids{$ebay_site_id};

my $url = "http://open.api.ebay.com/Shopping?callname=GetCategoryInfo" .
"&appid=$EBayRC{p_appid}" .
"&version=533" .
"&siteid=$site_id_code" .
"&CategoryID=$ebay_cat_id" .
"&IncludeSelector=ChildCategories";

print (get $url) . "\n" ;

Ten skrypt przyda się do udoskonalenia działania ebay_rest_search, tak żeby przeszukiwania dotyczyły tylko wybranych kategorii. Niestety eBay nie ma jednolitej hierarchii kategorii. Ten sam przedmiot może być różnie klasyfikowany.

No i tyle. Pozostaje umieścić ebay_rest_search w crontabie. Skrypty są tutaj.

niedziela, 8 czerwca 2008

Przed wielkim meczem

Śmieszy mnie powszechna histeria przed meczem piłkarskim z Niemcami, objawiająca się masowym jeżdżeniem z flagami przyczepionymi do samochodów. A szczególnie śmiesznie jest jak się widzi tak oflagowanego 30 letniego Golfa, Mercedesa lub inny dobry niemiecki samochód, kupiony w swoim czasie na szrocie (org. Schrott). Dziś uwieczniłem tę histerię kilkoma fotkami, ale umieszczę je dopiero po meczu. Aha premier Tusk nie wywiesił żadnej flagi w oknach swojej Sopockiej rezydencji -- sprawdzałem dziś osobiście około godziny 17.00:-)

Przy okazji napstrykałem też trochę fotek z uroczystego przejazdu z okazji otwarcia tunelu budowanego na skrzyżowaniu ul. Bohaterów Monte Cassino i Powstańców Warszawy (tj. tuż przed wejściem na Molo).

A co do szans Polski w wspomnianym wyżej meczu. To jestem prawie pewny, że skończy się jak zwykle. Czyli bańki będą... I to mimo że Niemcy wydają się słabi, o czym np. świadczą straszne baty jakie zebrał Bayern Monachium w meczu Zenit St. Petersburg. BTW mecz ten miałem okazję oglądać w Kilonii wśród wiwatujących autochtonów (ewidentnie nie lubią tego Bayernu na północy Niemiec, nie lubią:-)

Dopisane 9 czerwca 2008 (The Day After): Przegrali, oczywiście, że przegrali. Ale z drugiej strony wygrał Kubica, i to na torze w Montrealu, gdzie 12 miesięcy temu mało się nie zabił (cf. notka na ten temat).

Dopisane 15 lipca 2008: A ten pan w samochodzie na drugim zdjęciu od prawej to słynny od bodajże 3 dni pan prez. Karnowski z Sopotu. Oczywiście nie wiem o co w tym wszystkim chodzi ale dostrzegam pewne podobieństwa do słynnej sprawy sprzed lat, gdzie p. premier Tusk to Miller, p. Julke to Michnik a prez. Karnowskiemu przypadła w tym dramacie rola producenta Rywina.

Dopisane 31 lipca 2008: A afera się rozwija. Znane i cenione Duo Sopot ma teraz konkurecję: S. Julke (dictafone, voc) i J. Karnowski (voc). Żart oczywiście.