wtorek, 9 grudnia 2014

Afera madrycka: taka tam analiza wyjazdów posłów 7 kadencji

UWAGA: Ten tekst nie jest o polityce ale o [elementarnej] statystyce.

Media informowały, że posłowie PiS Adam Hofman, Mariusz A. Kamiński i Adam Rogacki wzięli na podróż do Madrytu na posiedzenie komisji Zgromadzenia Parlamentarnego Rady Europy po kilkanaście tysięcy złotych zaliczki, zgłaszając wyjazd samochodem; w rzeczywistości polecieli tanimi liniami lotniczymi. Ponieważ kontrola wydatków posłów jest iluzoryczna różnica pomiędzy kosztem podróży samochodem a samolotem [za dużo mniejsze pieniądze] miała stanowić dodatkowy przychód wyżej wymienionych. Według prokuratury, która wszczęła śledztwo, zachodzi podejrzenie popełnienia oszustwa.

Łapiąc wiatr w żagle [sprawa się upubliczniła tuż przed ostatnimi wyborami samorządowymi] koalicja rządząca w osobie Marszałka Sejmu RP Sikorskiego zarządziła audyt, którego efektem było udostępnienie m.in. dokumentu pn. Wyjazdy zagraniczne posłów VII kadencja (kopia jest tutaj).

Jak przystało na kraj, w którym od lat działa Ministerstwo cyfryzacji zestawienie jest w formacie PDF, zatem pierwszym ruchem była zamiana na coś przetwarzalnego. Wpisanie w google PDF+Excel+conversion skutkuje ogromną listą potencjalnych konwerterów. Bagatelizując skalę problemu spróbowałem dokonać konwersji narzędziami dostępnymi on-line, ale z marnym rezultatem (za duży dokument przykładowo; serwis za free jest tylko dla PDFów mniejszych niż 50 stron). W przypadku Convert PDF to EXCEL online & free coś tam skonwertował, nawet wyglądało toto na pierwszy rzut oka OK ale na drugi już nie: dokument niekompletny oraz nieprawidłowo zamienione niektóre liczby (przykładowo zamiast 837,50 zł w arkuszu jest 83750 -- 100 razy więcej!).

Ostatecznie skończyło się na ściągnięciu 30 dniowej wersji Adobe Acrobata Pro XI, który faktycznie sprawdził się w roli konwertera PDF→XLSX. Do konwersji wykorzystałem służbowego laptopa Elki wyposażonego w legalny Office 2010, na którym zainstalowałem ww. AA Pro XI. OOffice niby czyta XLSX, ale z koszmarnymi błędami, więc żeby dalej móc obrabiać arkusz w Linuksie wczytałem wynikowy XLSX do Excela 2010 po czym zapisałem go w (starszym) formacie XLS. Ten plik wyświetlił się w OO Calcu bez problemu.

Arkusz jest tak sformatowany, że 4 pierwsze komórki oraz są często wielowierszowe i scalone, zawierają bowiem liczbę porządkową, datę, miejsce i cel wyjazdu delegacji posłów. Po zamianie na plik CSV zawartość komórek scalonych pojawi się w pierwszym wierszu, a pozostałe będą puste. Prostym skryptem Perlowym mogę wypełnić puste komórki wg. algorytmu: jeżeli cztery pierwsze pola są puste, to skopiuj wartości ostatnich niepustych:


if ($tmp[0] eq '' && $tmp[1] eq '' && $tmp[2] eq '' && $tmp[3] eq '' ) { ... }

Pierwszy problem: wielowierszowe komórki z kolumn 1--4 nie zawsze są scalone. Czasem tekst jest podzielony na wiersze co psuje konwersję. Ręcznie scalam niescalone komórki (trochę to trwa). Przed scaleniem usuwam z kolumn 1--4 końce wiersza.

Drugi problem: część liczb nie jest liczbami z uwagi na użycie separatora tysięcy, który się zamienił w PDFie na odstęp (spację). Zatem zaznaczam kolumny zawierające różne pozycje kosztów po czym:

Edytuj→Znajdź i zamień
usuwam odstępy, tj. zamieniam spację na pusty napis
Format→Komórki
wybieram numer z dwoma miejscami po przecinku.

Po uporządkowaniu arkusza, zapisuję go w formacie CSV. Następnie prostym skryptem Perlowym zamieniam na taki plik CSV, w którym puste komórki są wypełniane zawartością z poprzednich wierszy. Kolumna Państwo - miasto jest kopiowana. Kopia jest zmieniana na jednoznaczne: Państwo, miasto (pierwszy-kraj, przecinek, pierwsze miasto z listy celów podróży -- żeby geokoderowi było łatwiej.)

Innym skryptem Perlowym dodaję do pliku CSV 3 kolumny, które zawierają:

  1. współrzędne celu podróży (w tym celu zamieniam adres Państwo, miasto na współrzędne geograficzne korzystając z geokodera Google);

  2. odległość w kilometrach pomiędzy punktem o współrzędnych 21.028075/52.225208 (W-wa, Wiejska 1) a celem podróży (obliczoną przy wykorzystaniu pakietu GIS::Distance);

  3. linię zdefiniowana w formacie KML o końcach 21.028075/52.225208--współrzędne-celu-podróży (do ewentualnego wykorzystania z Google Fusion Tables).


#!/usr/bin/perl
#
use Storable;
use Google::GeoCoder::Smart;
use GIS::Distance;

$geo = Google::GeoCoder::Smart->new();

my $gis = GIS::Distance->new();

my $GeoCodeCacheName = 'geocode.cache';
my $NewCoordinatesFetched=0; # global flag
my $SLEEP_TIME = 2 ;
my $coords_okr = "21.028075,52.225208"; # Warszawa = środek świata

my %GeoCodeCache = %{ retrieve("$GeoCodeCacheName") } if ( -f "$GeoCodeCacheName" ) ;
my ($wwa_lng, $wwa_lat) = split (",", $coords_okr);
my $linesNo = 0 ;
my $GCtotaluse = 1; # laczna liczba wywolan geocodera

while (<>) {
$linesNo++;
chomp(); $_ =~ s/[ \t]+;[ \t]+/;/g; ## usuń ew. niepotrzebne spacje

@line = split ";", $_; print STDERR "**$linesNo = $line[3] ... ";

# geokodowanie (uwaga na limit)
# Poprawki dla miejsc, których nie zna Google:
$line[3] =~ s/Erewań/Erywań/; ##
$line[3] =~ s/Sowayma/Madaba/; ## najbliższe miasto
$line[3] =~ s/Bołszowce/Iwano-Frankiwsk/; ## najbliższe miasto

my $coords = addr2coords( $line[3] );

($tmp_lat, $tmp_lng, $gcuse) = split " ", $coords;
if ($gcuse > 0) {$GCtotaluse++ ; }

$distance = $gis->distance($tmp_lat,$tmp_lng => $wwa_lat,$wwa_lng );
$distance_t = sprintf ("%.1f", $distance);

my $kml_line = "<LineString><coordinates>$tmp_lng,$tmp_lat $coords_okr</coordinates></LineString>";
print "$_;\"$coords\";$distance_t;\"$kml_line\"\n";
print STDERR "\n";

if ($GCtotaluse % 100 == 0 ) {# store every 100 geocoder calls
store(\%GeoCodeCache, "$GeoCodeCacheName");
print STDERR "\n... Cache stored. ***\n";
}
}

##
store(\%GeoCodeCache, "$GeoCodeCacheName");

## ## ## ####
sub addr2coords {
my $a = shift ;
my $r = shift || 'n';
my ($lat, $lng) ;
my $GCuse = 0;

##consult cache first
if (exists $GeoCodeCache{"$a"} ) {
print STDERR "Coordinates catched ... $a ";
($lat,$lng) = split (" ", $GeoCodeCache{"$a"} );
}
else {
print STDERR "Geocoding ... $a ";
my ($resultnum, $error, @results, $returncontent) = $geo->geocode("address" => "$a");
$GCuse = 1;
sleep $SLEEP_TIME; ## make short pause

$resultnum--;
$resultNo=$resultnum ;

if (resultNo > 0) { print STDERR "** Location $a occured more than once! **" }
if ($error eq 'OK') {
$NewCoordinatesFetched=1;
for $num(0 .. $resultnum) {
$lat = $results[$num]{geometry}{location}{lat};
$lng = $results[$num]{geometry}{location}{lng};
##print "*** LAT/LNG:$lat $lng ERROR: $error RES: $resultNo ***\n";
}

$GeoCodeCache{"$a"} = "$lat $lng"; ## store in cache

} else { print STDERR "** Location $a not found! due to $error **" }
}


if ($r eq 'r' ) { return "$lng,$lat,$GCuse"; } # w formacie KML
else { return "$lat $lng $GCuse"; }
}

Gotowy plik CSV zawierający zestawienie podróży jest dostępny tutaj.

Na podstawie zestawienia i z użyciem pakietu ggplot2 generują się takie oto śliczne wykresy.

Wszystkie podróże z zestawienie (N=1874; odpowiednio: koszt łączny, koszt transportu, długość w tys km):

Tylko podróże dla których koszt transportu był niezerowy (N=1423; odpowiednio: koszt łączny, koszt transportu, długość w tys km):

Poniższy skrypt R sumuje i drukuje wszystkie podróże każdego posła:


require(plyr)

d <- read.csv("W7RR_podroze_by_podroz1.csv", sep = ';', dec = ",", header=T, na.string="NA");

# Dodaj kolumnę której wartości to konkatenacja: "Poseł|Klub"
d[,"PosKlub"] <- do.call(paste, c(d[c("Posel", "Klub")], sep = "|"));

# Usuń wszystko za wyjątkiem tego co potrzeba:
d <- d[ c("PosKlub", "Klacznie", "Ktransp", "Dist") ];

# Sumowanie po PosKlub
PSums <- as.data.frame ( ddply(d, .(PosKlub), numcolwise(sum)) );

# Z powrotem rozdziel kolumnę "Poseł|Klub" na dwie
PSums <- as.data.frame ( within(PSums, PosKlub <-data.frame( do.call('rbind',
strsplit(as.character(PosKlub), '|', fixed=TRUE)))) )

# Drukuj
PSums;

Z pliku .Rout kopiuję zestawienie łącznych wydatków posłów oraz łącznej pokonanej przez nich odległości:


PosKlub.X1 PosKlub.X2 KlacznieT KtranspT DistT
1 Adam Abramowicz PiS 4.02599 2.64595 1.3153
2 Adam Hofman PiS 119.55271 59.53315 26.1716
3 Adam Kępiński SLD 10.15754 7.93882 3.8069
4 Adam Kępiński TR 12.63098 8.02327 2.2107
...

Uwaga: kilkanaście nazwisk się powtarza ponieważ posłowie zmienili przynależność klubową w czasie trwania kadencji [Aby uwzględnić takich posłów sumowanie odbywało się po wartościach zmiennej zawierającej połączone napisy Poseł|Klub.]

Na podstawie takiego z kolei zestawienia i znowu z użyciem ggplot2 generują inne śliczne wykresy.

Uwaga: sumowane tylko podróże, dla których koszt transportu był niezerowy (N=1423; odpowiednio: koszt łączny, koszt transportu, długość w tys km):

Link do tabeli zawierającej zestawienie podróży w formacie Google Fusion Tables jest tutaj.

Dane + skrypty dostępne są także w: github.com/hrpunio/Data.

piątek, 5 września 2014

Trip to Georgia

I have just returned from a week-long trip to Georgia. We have visited Borjomi, Tbilisi, Kazbegi (Stepancminda) and Kutaisi (click the map to see journey track and photos).

On arriving to Kutaisi airport we went straight to the famous Borjomi resort where Russian Emperors once rested. We walked in the park tasting Borjomi mineral spring water, and swimming in hot water pool. From Borjomi we visited cave-city and monastery ensemble Vardzia where there was other hot water pool (with even hotter water). After 2 days in Borjomi we went to Tbilisi where we stayed 1 day (walking in old town). Next morning we drove to Caucasus mountains along Georgian military road via ancient Capital of Georgia -- Mtskheta (unfortunately we did not stop there). We stayed 2 days in Kazbegi where we hiked to Gergeti Trinity Church at 2170m and attended rugby union game Kazbegi vs Tbilisi Crusaiders (among other things:-). Finally we returned to Kutaisi where we visited Gelati and Motsameta Monastyrs as well as Sataplia caves...

We stayed in Leo's Homestay/Guesthouse in Borjomi, Why Not? Legend Hostel in Tbilisi and Hostel Kutaisi by Kote in Kutaisi. We recommend all of them.

The guesthouse we stayed in Kazbegi is not recommended so we do not mention it:-(

More details later...

środa, 23 lipca 2014

Batch upload to Picasa

The problem: upload photos to Picasa (trivial); 2) scale them if neccessary before upload; 3) if photos contains some EXIF tags (geotags in particular) copy these tags to Picasa as well.

To achieve the above I use: googleCL (upload), convert (from ImageMagick bundle for scaling) exiftool (for metadata extraction/manipulation).

Using convert the script below (jpgresize.sh) scale picture to 2048 pixels along longest side:


#!/bin/bash
# Scale pictures to 2048 pixels along longest side for upload to Picasa
# Photos below 2048 x 2048 pixels do not count towards storage limit
# (cf. https://support.google.com/picasa/answer/6558?hl=en )
#
PICASA_FREE_LIMIT=2048

while test $# -gt 0; do
case "$1" in
-o) shift; OUT_FILE="$1";;
-o*) OUT_FILE="`echo :$1 | sed 's/^:-o//'`";;
*) FILE="$1";;
esac
shift
done

if [ -z "$OUT_FILE" ] ; then
my_pic="${FILE%.*}_s.${FILE#*.}"
else
my_pic="$OUT_FILE";
fi

if [ -f "$FILE" ] ; then

echo "** converting $FILE to $my_pic ***"

SIZE="2048x"

my_pic_width=`exiftool -ImageWidth "$FILE" | awk '{print $NF}'`
my_pic_height=`exiftool -ImageHeight "$FILE" | awk '{print $NF}'`

if [[ ( -z "$my_pic_width" ) || ( -z "$my_pic_height" ) ]] ; then
echo "*** $FILE has 0 width and/or height ***"; exit ;
fi

## http://www.imagemagick.org/Usage/resize/#resize
if [[ ( "$my_pic_width" -gt "$PICASA_FREE_LIMIT" ) || \
( "$my_pic_height" -gt "$PICASA_FREE_LIMIT" ) ]] ; then
if [ "$my_pic_width" -gt "$my_pic_height" ] ; then
SIZE="${PICASA_FREE_LIMIT}x>"
echo "*** $FILE width: $my_pic_width ; converting to $SIZE"
convert "$FILE" -geometry $SIZE "$my_pic"
else
SIZE="x$PICASA_FREE_LIMIT>"
echo "*** $FILE height: $my_pic_height ; converting to $SIZE"
convert "$FILE" -geometry $SIZE "$my_pic"
fi
else
## File is too small copy the original:
echo "*** $FILE has $my_pic_width in width; COPYING"
cp "$FILE" "$my_pic"
fi
else
echo "*** FILE $FILE not found! ***"
fi

Upload one picture to picasa with 1photo2picasa.sh


#!/bin/bash
#
# Upload photo to Picasa with googleCL
# It is assumed the photo contains UserComment GPSLatitude GPSLongitude GPSAltitude
# Exif tags which are copied to Picasa (see below for more details)
#
# Default album title:
ALBUMTITLE="???"

echo "$0 -a AlbumTitle FILE-2-UPLOAD"

while test $# -gt 0; do
case "$1" in
-a) shift; ALBUMTITLE="$1";;
-a*) ALBUMTITLE="`echo :$1 | sed 's/^:-a//'`";;
*) FILE="$1";;
esac
shift
done

AUTHOR=`exiftool -S -Artist $FILE`

if [ -z "$AUTHOR" ] ; then
# It there is no Artist tag it is assumed photo was not tagged properly
echo "*** ERROR: $FILE lacks Artist EXIF tag"
exit;
else
## Some tags are edited:
TAGS=`exiftool -S -UserComment $FILE | awk '{ $1=""; for (i=1;i<=NF;i++) { if ($i ~ /http/) { $i=""}}; \
gsub (/, +/, ",", $0); gsub (/ +,/, ",", $0); gsub (/^ +| +$/, "", $0); print $0}'`
GPSLat=`exiftool -S -c '%+.6f' -GPSLatitude $FILE | awk '{ print $2}'`
GPSLon=`exiftool -S -c '%+.6f' -GPSLongitude $FILE | awk '{ print $2}'`
GPSAlt=`exiftool -GPSAltitude $FILE -S -c "%.1f" | awk '{ if ($0 ~ /Below/) { print -$2} else {print $2}}'`

PICASA_TAGS=""
## Concatenate all tags
if [ -n "$TAGS" ] ; then PICASA_TAGS="$TAGS"; fi
if [ -n "$GPSLat" ] ; then PICASA_TAGS="$PICASA_TAGS,geo:lat=$GPSLat"; fi
if [ -n "$GPSLon" ] ; then PICASA_TAGS="$PICASA_TAGS,geo:lon=$GPSLon"; fi
if [ -n "$GPSAlt" ] ; then PICASA_TAGS="$PICASA_TAGS,geo:alt=$GPSAlt"; fi

# Upload to picasa:
google picasa post --title "$ALBUMTITLE" --src="$FILE" --photo="$FILE" --tags="$PICASA_TAGS"
fi

Finally simple bash script upload2picassa.sh uses jpgresize.sh and 1photo2picasa.sh to upload all .jpg files from the current directory to picasa:


#!/bin/bash
# Upload all .jpg files (scaled tp 2048) to picasa
#
echo "Uploading all .jpg files to album: $albumtitle"

albumtitle=$1

if [ -z "$albumtitle" ] ; then
echo "Podaj ID albumu!"; exit 1
fi

for file in *.jpg; do

echo "Uploading $file to $albumtitle album..."

outfile="${file%.*}_s.${file#*.}"

jpgresize.sh -p -o $outfile $file && 1photo2picasa.sh -a $albumtitle $outfile
done

wtorek, 22 lipca 2014

Flickr zmienił API

Wycieczka do Swornychgaci spowodowała m.in. konieczność dopasowania moich starych skryptów Perla służących do obsługi Flickra.

Flickr zmienił bowiem niedawno API przechodząc na SSL. Zapewne nowa wersja modułu Flickr-API tą zmianę uwzględnia, ale można też rozwiązać sprawę dodając stosowny parametr do starych skryptów. Konkretnie poniższy wiersz:


my $api = new Flickr::API({'key' => $api_key, 'secret' => $shared_secret, });

należy uzupełnić o parametr rest_uri, tj:


my $api = new Flickr::API({'key' => $api_key, 'secret' => $shared_secret,
'rest_uri' => 'https://api.flickr.com/services/rest/' });

Podobnie niewielkich modyfikacji wymaga skrypt służący do wysyłania zdjęć (moduł Flickr-Upload):


my $ua = Flickr::Upload->new( {'key' => $api_key, 'secret' => $shared_secret,
'uri' => 'https://up.flickr.com/services/upload/' } );

W tzw. międzyczasie zmieniła się też nieco metoda flickr.photos.geo.setLocation:


#if ( $response->{success} ) { ## przestało działać
unless ( $response->{error_code} > 0 ) {

W dokumentacji jest napisane: This method has no specific response -- It returns an empty success response if it completes without error.. No to faktycznie jak jest empty to if (EMPTY) { zwraca fałsz i warunek jest źle interpertowany. Poza tą jedną poprawką wszystko inne działa.

Wycieczka do Swornychgaci

We piątek (18.07.2014) przepłynęliśmy z rodziną kolegi ZK rzeką Chociną, konkretnie od Chocińskiego Młyna do jeziora Karsińskiego (ca 12 km na GPSie). Spływ zaczęliśmy w Chocińskim Młynie około 14:30 a do Swornychgaci dotarliśmy po 18:00.

Rzeczka jest płytka i wąska, ale nie ma w niej żadnych przeszkód. Spływ odbył się zatem bezproblemowo. Chcieliśmy także popłynąć kajakami w niedzielę, niestety, wszystkie okoliczne wypożyczalnie kajaków miały cały swój tabor zarezerwowany.

Miłym rozczarowaniem jest sieć pierwszorzędnych dróg rowerowych w okolicy Chojnic, o istnieniu których nie miałem świadomości. Drogi rowerowe są wytyczone obok drogi dla samochodów, wydają się dobrze oznakowane i mają utwardzoną nawierzchnię (niekoniecznie asfalt czy płytki/kostki). Do roweru szosowego nie nadają się na 100%, ale każdy inny będzie OK, a i na szosowym da się jechać. Na szybko jakieś informacje na temat tych dróg znalazłem tutaj (niekoniecznie musi to być najlepsze źródło).

Wracając wpadliśmy obejrzeć akwedukt w Fojutowie. Rozczarowująca atrakcja. Do tego tłum ludzi--nie wiem czemu akurat to miejsce jest aż tak popularne...

Ślad całej wycieczki (ze zdjęciami) jest też tutaj.

poniedziałek, 21 lipca 2014

Letter from an Idiot

Not very long ago, there was a lot of LGBT propaganda before Sochi Olympics Games related to alleged Putin's war with LGBT Russians. Opinion leader Stephen Fry's open letter to PM Cameron/IOC was a good example of hysteria created then.

IMHO the letter was extremely stupid (as stupid as its creator), namely Putin was compared to Hitler and LGBT Russians to Jews in the 3rd Reich (He is making scapegoats of gay people, just as Hitler did Jews).

Unfortunately Putin started a real war, not a war with some scapegoats.... And of course comparing 6 millions murdered Jews with `suffering gays' is pure and simple grave robbery (taniec na trumnach in Polish).

Fry's letter is here

sobota, 12 lipca 2014

Wysyłanie maila z raspberry Pi/Sheevaplug przez gmail

Dla nieuświadomionych Sheevaplug to taki dziadek RaspberryPi. Kiedy jeszcze nie sprzedawali Rpi kupiłem Sheevaplug i używam do dzisiaj. Na obu komputerach jest zainstalowany Debian, ale w różnych wersjach.

Listy mam wysyłać skryptem Perla więc rozpoczynam od zainstalowania stosowego modułu Net::SMTP::TLS:


sudo apt-cache search TLS | grep perl
libnet-smtp-tls-butmaintained-perl - Perl module for providing SMTP...
libnet-smtp-tls-perl - Perl SMTP client library supporting TLS and AUTH
libwww-curl-perl - Perl bindings to libcurl

sudo apt-get install libnet-smtp-tls-perl

W Debianie działającym na Sheevaplug (Debian Lenny) nie ma gotowego pakietu więc instaluję co trzeba za pomocą cpan:


cpan install Net::SMTP::TLS

Skrypt do wysyłania listu (mail-snd.pl):


#!/usr/bin/perl
# http://dipinkrishna.com/blog/2010/12/sending-emails-gmail-smtp-perl/
use Net::SMTP::TLS;

my $smtp = new Net::SMTP::TLS(
'smtp.gmail.com',
Port => 587,
User => 'USER1@gmail.com',
Password=> '??PASSWORD??',
Timeout => 30
);

# -- Enter email FROM below. --
$smtp->mail('USER1@gmail.com');

# -- Enter recipient mails addresses below --
my @recipients = ('USER2@gmail.com');
$smtp->recipient(@recipients);

$smtp->data();

#This part creates the SMTP headers you see
$smtp->datasend("To: USER2\@gmail.com\n");
$smtp->datasend("From: USER1\@gmail.com\n");
$smtp->datasend("Content-Type: text/html \n");
$smtp->datasend("Subject: A Test Mail");
# line break to separate headers from message body
$smtp->datasend("\n");
$smtp->datasend("This is a test mail body");
$smtp->datasend("\n");
$smtp->dataend();

$smtp->quit;

W Sheevaplug działa i wysyła, a Raspberry Pi nie:


invalid SSL_version specified at /usr/share/perl5/IO/Socket/SSL.pm line 332

Żeby było śmieszniej w Debianie Lenny z Sheevaplug jest jakaś bardzo stara wersja IO::Socket:SSL:


## sprawdź numer wersji modułu
cpan -D IO::Socket::SSL
Installed: 1.16

A na Raspberry Pi znacznie nowsza (ale nie działa):


cpan -D IO::Socket::SSL
Installed: 1.76
CPAN: 1.994 Not up to date

Aktualizuję


sudo cpan
cpan> install IO::Socket:SSL

Ale to nie pomaga:


invalid SSL_version specified at /usr/local/share/perl/5.14.2/IO/Socket/SSL.pm

Rozwiązanie jest podane tutaj. Należy:


## w pliku SSL.pm
sudo nano usr/share/perl5/IO/Socket/SSL.pm
## zmienić
m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1[12]?))$}i
## na
m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1[12]?))}i

Zamiast rzeźbienia w Perlu można zainstalować gotowe rozwiązanie pn. sendemail:


apt-get install sendemail

List wysyłamy w następujący sposób:


sendEmail -f USER1@gmail.com -t USER2@other.com \
-u "Title1" -m "this is a test message" \
-s smtp.gmail.com \
-o tls=yes \
-xu USER1 -xp '??PASSWORD??'

niedziela, 29 czerwca 2014

Great uptime of pinkaccordions.homelinux.org server

My tiny SheevaPlug ARM-based server has reached 366 days of uptime today. Proof included:

SheevaPlug is a sort of Raspberry Pi. One of the first such computers on the market, killed by Rpi a few years ago.

Przykra sprawa. Nie lekceważę jej

Polska została zaatakowana. Chodzi prawdopodobnie o zamach stanu [...]

Przykra sprawa. Nie lekceważę jej

Informacja prezesa Rady Ministrów w sprawie tzw. afery podsłuchowej z udziałem prezesa Narodowego Banku Polskiego, ministra spraw wewnętrznych oraz byłych wysokich urzędników państwowych.

[...]

Chciałbym bardzo wyraźnie podkreślić, że nie lekceważąc lekcji, jaka płynie z nagrań, lekcji, z której powinni wyciągnąć wnioski wszyscy bez wyjątku, zarówno nagrani, jak i ci obawiający się, że mogli być nagrani, lekcji, którą powinni odrobić wszyscy uczestnicy życia publicznego mający wystarczającą wyobraźnię, że jednak prawdziwym problemem politycznym jest fakt, że grupa przestępców -- z jakiego powodu, o tym za chwilę -- pozwoliła sobie na nielegalne nagrywanie i podsłuchiwanie, a następnie publikowanie materiałów, które doprowadzają do takiego wstrząsu, jakiego jesteśmy uczestnikami i świadkami.

Dlaczego uważam, że mamy do czynienia z kryzysem politycznym i z problemem o charakterze politycznym? Po pierwsze, dzisiaj znamy już kontekst i tło tych zdarzeń. Dzisiaj informacje po pierwszych zatrzymaniach wskazują jednoznacznie na to, że osoby podsłuchujące mogły kierować się tak czy inaczej złymi intencjami. Ponadto nie ulega wątpliwości, niezależnie od tego, kto ma jaki status społeczny, że nielegalne podsłuchiwanie bez wiedzy osoby podsłuchiwanej, nagrywanie i upublicznianie tego typu materiałów jest przestępstwem. To jest bezdyskusyjny fakt prawny. Po drugie, mamy do czynienia z ludźmi -- mówię o pierwszych zatrzymanych -- których intencje biznesowe lub polityczne dzisiaj wydają się dość oczywiste.

Chciałbym bardzo wyraźnie podkreślić, że w przyszłości tych wątków może pojawić się więcej. Dzisiaj nikt nie jest w stanie precyzyjnie zdefiniować, co bezpośrednio powodowało zleceniodawcami i wykonawcami tego procederu podsłuchowego. Jak wiemy z dat opublikowanych nagrań, proceder ten trwał co najmniej 1,5 roku, nie w jednym miejscu i dotyczył dziesiątków, a może setek ludzi. Wiemy, że tak czy inaczej zaangażowane w to lub kojarzone z podsłuchującymi i nagrywającymi osoby związane są także z interesami, o których państwo polskie miało swoje określone zdanie i wobec których także podejmowało określone działania.

Chciałbym podkreślić znaczenie tego tła. Przede wszystkim mówimy o osobach zaangażowanych w działalność gospodarczą ściśle związaną z energetyką. Sytuacja, z jaką mamy miejsce w ostatnich dniach, poprzedzona była dość zdecydowanymi działaniami służb państwowych wobec importerów i dystrybutorów węgla na dużą skalę. Zdajemy sobie sprawę, że ten wątek może być wątkiem pobocznym albo niewyłącznym, ale nie ulega wątpliwości, że jest on obecny w tej sprawie.

Chciałbym mocno podkreślić, że dotychczasowa wiedza o zagrożeniu interesów państwa czy jego stabilności w związku z aferą podsłuchową każe szczególnie mocno i wnikliwie badać także związki osób bezpośrednio zaangażowanych w ten proceder z przedsięwzięciami gospodarczymi i ze środowiskami, które były aktywne, także jeśli chodzi o problematykę gazową. To w tej chwili nie jest już nawet tajemnicą publiczną. Nie jestem upoważniony do epatowania informacjami, które mogą być w dyspozycji premiera, ale nie ulega wątpliwości, że ten kontekst musi budzić najwyższe zaniepokojenie.

Skala zdarzeń, z jaką mamy do czynienia -- mówię o skali procederu podsłuchiwania i nagrywania -- jest, jak sądzę, adekwatna do skali interesów. Nie mówię tutaj tylko o interesach polskich firm, dwuznacznych lub nielegalnych, jakimi służby państwowe jakiś czas temu się zajęły. To tło jest szerokie, bo dotyczy kilku zdarzeń, które państwo mieli także okazję obserwować w ostatnich kilku czy kilkunastu miesiącach. Są one związane bezpośrednio lub pośrednio z aktorami tego przedstawienia, tego dramatu, z jakim mamy do czynienia w ostatnich kilku dniach. Mają związek z osobami, które działały w dziedzinie połączeń gazowych między Polską a Rosją. Każdy na tej sali, kto interesował się problemem tzw. pieremyczki, czyli połączenia gazowego, które miało omijać Ukrainę, pamięta także zdarzania, z którymi związane są niektóre osoby pojawiające się w kontekście afery podsłuchowej. W tle jest handel węglem zza wschodniej granicy na wielką skalę. Rozpoczęliśmy bardzo energiczne działania w związku z sytuacją także w polskich kopalniach, m.in. na wniosek związkowców. Nie ma żadnego powodu, żeby twierdzić, że jest bezpośredni związek między tymi działaniami a akcją podsłuchową i ujawnianiem podsłuchów, ale nie ma też żadnego powodu, aby nie dostrzegać związku między jednym a drugim zdarzeniem. Mam nadzieję, że postępowanie, śledztwo, a następnie proces rozwieją wątpliwości, potwierdzą lub odrzucą te skojarzenia, które dzisiaj wydają się jednak dość oczywiste. W tle jest także sytuacja na Ukrainie i sytuacja w Europie.

Chcę mocno to podkreślić, dzisiaj mogę precyzyjnie zdefiniować poważne, fundamentalne interesy państwa polskiego, które mogą być zagrożone lub osłabione w związku z aferą podsłuchową, z czego nie musi wynikać bezpośredni związek afery podsłuchowej lub samego faktu jej ujawnienia w tych dniach z naruszeniem czy osłabieniem tych interesów. Zadaniem Wysokiej Izby, o tym też jestem przekonany, jest ocena skutków, wyreżyserowanych, zaplanowanych, zgodnych z intencjami sprawców tej afery albo będących rykoszetami. Te skutki są jednak bezdyskusyjne. Te skutki to osłabienie możliwości wpływania ze strony polskiego rządu na nową konstrukcję, nową architekturę personalną i instytucjonalną w Europie. Mówiąc ludzkim językiem, za dwa dni przystąpimy do pierwszych bardzo ważnych decyzji w Brukseli i będziemy decydować o dwóch kwestiach: kto będzie rządził instytucjami w Europie -- i chcę powiedzieć, że Polska nie była, moim zdaniem nadal nie jest, ale z całą pewnością nie była bez szans na bycie obecną przy tych najważniejszych rozdaniach -- i tego samego dnia będziemy także dyskutowali o unii energetycznej i o mechanizmach bezpieczeństwa energetycznego Europy w kontekście kryzysu ukraińskiego i konfliktu rosyjsko-ukraińskiego. Dobrze wszyscy państwo orientujecie się, że co do roli polskiego rządu i całego państwa polskiego w kontekście bezpieczeństwa energetycznego, rekomendacji Komisji Europejskiej, które zostały przygotowane na to najbliższe posiedzenie, sporu o to, na ile Europa ma być niezależna od wschodniego gazu, w całym tym procesie Polska, polski rząd i polskie państwo, odgrywała naprawdę kluczową rolę. Jeśli chodzi o ten element, który najbardziej bezpośrednio rzuca się w oczy po pierwszych dniach ustaleń, czyli handel węglem, sprawa jest na dużą skalę. Mówimy o bardzo poważnych pieniądzach, ale przede wszystkim mówimy o bardzo realnym wpływie obrotu węglem i tego, jaki jest to węgiel i skąd jest ten węgiel, na całą strukturę i bezpieczeństwo polskiej energetyki. To nie jest tylko mój wniosek.

[...]

Na podstawie Sprawozdanie Stenograficzne z 70. posiedzenia Sejmu Rzeczypospolitej Polskiej w dniu 25 czerwca 2014 r. (podkreślenia moje).

Jak dla mnie to tekst zawiera niespodziewanie dużo zaimków wskazujących: ten, tamten, jakiś, to, tamto, owamto...

piątek, 20 czerwca 2014

Syndrom Żorża Poniemirskiego

Mój ulubiony minister w rządzie RP dicit:

Kurcze z tym BOR-em. Ach. Kłopot polega na czymś innym. Nie polega na bieżącym zarządzaniu, ale chodzi o instytucję, której się nikt nie dotykał przez lata. Wszyscy, którzy pracują z BOR-em, mają syndrom sztokholmski Niech to zostanie między nami, ale odebrałem 15 telefonów od wszystkich możliwych najważniejszych ludzi w tym kraju, żebym, broń Boże, nie robił żadnej krzywdy BOR-owcom, więc mam wykręcone ręce. I zbieram za ewidentne wpadki formacji. Nikt się nie interesował, jak wygląda szkolenie, jak są finansowani, bo syndrom sztokholmski zapewnia bierność i symbiozę, gdzie fakty się nie liczyły. Gdybym był ministrem spraw wewnętrznych na początku czteroletnich rządów, toby to wyglądało inaczej, ale ja nie bardzo mogę sobie pozwolić na głębokie reformy w służbie, od której dyskrecji zależy wiele, he, he, istotnych decyzji w tym kraju na kwartał przed wyborami, bo to jest samobójstwo, he, he...

Ewidentny syndrom hr. Żorża Poniemirskiego, tego cierpiącego na głowę brata Niny Poniemirskiej, który w finałowej scenie okazuje się być najlepiej zorientowany wśród zebranych:

wtorek, 17 czerwca 2014

Chuj dupa i kamieni kupa

Normalnie w takiej sytuacji w tzw. demokracji się skompromitowanego usuwa dając do zrozumienia, że nowy będzie lepszy. Z jakiś względów tym razem się nie da więc Tusk i jego palatyn brną w oczywiste kłamstwa:

O próbie zamachu stanu rząd dowiedział się z mediów, które upubliczniły nagranie rozmowy szefa MSW, ale pan premier jest z pracy służb pod kierunkiem tegoż szefa MSW zadowolony.

Minister-pierdoła oświadczył(a) zaś, że był nagrywany przez lata, ale ostatnim jego zadaniem jest wykrycie nagrywającego. Hej kurcze, może lepiej nieudacznika zwolnić a zatrudnić takiego, który daje większe szanse na złapanie nagrywacza?

Po tym jak 10 maja 1941 pod Glasgow na spadochronie wyskoczył Rudolf Heß propaganda niemiecka czuła się w obowiązku wytłumaczenie jak doszło to takiej kompromitacji. Zdecydowano się na wariant Towarzysz partyjny Heß zwariował. Józef Goebbels uważał to za mało wiarygodnie i pokrętne wytłumaczenie i napisał sarkastycznie w swoich dziennikach: Uprawione jest pytanie jak idiota mógł tak długo być zastępcą Führera?. Podstawmy teraz zamiast zastępca führera słowo premier.

Wszystko już było tylko trochę inaczej....

czwartek, 12 czerwca 2014

Lista argumentów za długa

Ponieważ w przeciwieństwie do MSW w Linuksie długość wiersza poleceń jest absurdalnie duża zapomniałem, że jednak jest skończona:


system ("perl", "clickshop-delete.pl", "-items", join (',', @AllItems))

Program clickshop-delete.pl nie jest wykonywany. Żeby ustalić czemu dodaję:


system ("perl", "clickshop-delete.pl", "-items", join (',', @AllItems)) \
== 0 or warn "system failed: $? [$!]\n";

Teraz wiadomo czemu nie działa:


system failed: -1 [Lista argumentów za długa]

Poniższe ustala jak długi może być wiersz poleceń (Debian Lenny na Sheevaplug/ARM):


tomek@neptune:~$ getconf ARG_MAX
131072

Prosty sposób na zmodyfikowanie skryptu z wykorzystaniem splice:


my $max2process=6000; # każdy element @AllItems ma 12 znaków, więc 6000 jest OK
while ( my @items2process = splice @AllItems, 0, $max2process ) {
system ("perl", "clickshop-delete.pl", "-items", join (',', @items2process)) == \
0 or warn "system failed: $? [$!]\n";
}

Powinno działać.

poniedziałek, 7 kwietnia 2014

Box-plot chart with plot.ly and Perl API

The following Perl script reads data from a CSV file and draws a series of Box-Plots. Usage:


perl plotly_boxplot.pl -col=number -by=number -title=TITLE

where: -col=number -- column number containig variable to plot, -by=number -- column number containig grouping variable.


#!/usr/bin/perl
use WebService::Plotly;
use Getopt::Long;

# login to plotly script
require "$ENV{'HOME'}/bin/login2plotly.pl";

my $plotly = WebService::Plotly->new( un => $plotly_user, key => $plotly_key );

my $sep_sequence = ';';
my $col_number = -1;
my $by_col_number = -1;
my $chart_title='??Chart title??';
my $header='Y';
#my $boxpoints='outliers'; ## or all' | 'outliers' | False
my $USAGE="*** USAGE: -col=i -by=i -title=s -header=s -sep=s FILE *** \n";


# plot values from column 'col' grouped by column 'by'. If header is Y skip first row in data.
# Add title 'title'. Columns in csv data are separated by 'sep' (default ';')
GetOptions("col=i" => \$col_number, "by=i" => \$by_col_number, "title=s" => \$chart_title,
'header=s' => \$header, 'sep=s' => \$sep_sequence, );
##'boxpoints=s' => \$boxpoints ) ; ## this option not work!

if (($col_number == -1 ) || ($by_col_number == -1) ) { print $USAGE }

while (<>) { chomp ($_); $nr++;
if (($nr < 2) << ( $header eq 'Y' ) ) { next }
$_ =~ s/"//g;
my @fields = split(/$sep_sequence/, $_);
push @{$data{$fields[$by_col_number]}}, $fields[$col_number];
# http://stackoverflow.com/questions/3779213/how-do-i-push-a-value-onto-a-perl-hash-of-arrays
}

my @variants = sort keys %data;

print STDERR "*** No of rows scanned: $nr ***\n";
print STDERR "*** Groups found: @variants ($boxpoints) \n";
for $k (keys %data ) {
print "$k"; push (@boxes, { y =>$data{$k}, type => 'box', #'boxpoints' => 'none',
name => "$k" } ) }

my $layout = { 'title' => $chart_title };

my $response = $plotly->plot(\@boxes, layout => $layout );

my $url = $response->{url};
my $filename = $response->{filename};

print STDERR "*** done: filename: '$filename' url: '$url' ***\n"

Example: Age of Nobel Prize winners by discipline (grouping wariable) plot.ly/~tomasz.przechlewski/28/

niedziela, 9 lutego 2014

Ethernet connection drop on Raspberry Pi

From time to time internet connection to my Raspberry Pi disappears (AFAIK it is well known feature of Pi). Removing and reconnecting the ethernet cables did not work, so one has to reboot by pulling the plug (risking to corrupt file systems from improper shutdown).

To reconnect I use the following bash script (found here):


#!/bin/bash
# Check if Internet connection is still alive ***
# Insert into crontab at *.16
LOGLOG="/home/pi/Logs/Cron/Reboot.log"
WLAN=eth0

if /sbin/ifconfig $WLAN | grep -q "inet addr:" ; then
echo "Network connection up!"
else
echo "Attempting reconnect [`date +%Y%m%d%H%M`]" >> $LOGLOG
/usr/bin/sudo /sbin/ifup --force $WLAN
fi

Note: use ifconfig -a to identify relevant interface (WLAN):


pi@raspberryberrystar ~ $ ifconfig -a ifconfig -a
eth0 Link encap:Ethernet HWaddr b8:27:eb:f5:9a:d7
inet addr:192.168.1.146 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

My other Pi is connected to internet not through a cable but with WiFi dongle. The relevant interface is:


pi@blackberrystar ~ $ ifconfig -a
wlan2 Link encap:Ethernet HWaddr 10:fe:ed:12:ef:2c
inet addr:192.168.1.144 Bcast:192.168.1.255 Mask:255.255.255.0

The connection is checked every 20 minutes with the following crontab entry:


## Check Internet connection every 7th, 27th, 47th minute:
7,27,47 * * * * /home/pi/bin/chk_www_alive.sh > /dev/null 2>&1

wtorek, 14 stycznia 2014

WinterhilfswerkKapelle

Winterhilfswerk Kapelle = Orkiestra Zimowej Pomocy, złośliwe nawiązanie do Winterhilfswerk des Deutschen Volkes w kontekście akcji p. Owsiaka.

Minister Kamysz cyt. Nie niszczmy inicjatyw charytatywnych polską wojenką.

Otóż akcje charytatywne dzielą się na sensowne i bezsensowne. Wiele samorządów wspieranych przez organizacje pozarządowe zwalcza (niszczy powiedziałby p. Kamysz) spontaniczne wspieranie żebrzących jako dobroczynność bardziej szkodzącą niż przynoszących pożytek (np. Dając mi pieniądze nie pomagasz).

Gdyby polski system ochrony zdrowia był dobrze zarządzany WOŚP byłaby zbędna dla większości ubezpieczonych. (Dalej wszakże mogłaby by się zajmować np. ludźmi nie ubezpieczonymi lub ubezpieczonymi, których problemy nie są objęte systemem ubezpieczeń.) Stawianie sprawy tak jak się ją stawia od 22 lat: chorym potrzebującym pomocy jest szpital a nie konkretny człowiek jest zgodą na byle jakie, złe zarządzanie, na reformy obliczone tak żeby nie naruszyć interesów żadnej wpływowej grupy, itd...

Innymi słowy jest to bezsensowna akcja charytatywna. Bezsensowna, bo utrwalająca stan złego zarządzania służbą ochrony zdrowia.

Ponadto WOŚP jest w dużym stopniu wspierana przez finanse publiczne. To co ląduje w puszkach to przysłowiowy pryszcz...

Liczne samorządy upychają na aukcjach coś, co jest finansowane z pieniędzy publicznych (przyłapane na tym bezczelnie twierdzą, że absolutnie nie, że nie wiąże się to z dodatkowymi wydatkami, ale przecież there is no such a thing as a free lunch). Innym słowy podatnik zapłacił za jakiś towar/usługę (powiedzmy stadion w Gdańsku wybudowany za 800 mln) a dostanie aparat USG (kupiony za pieniądze pochodzące z wydzierżawienia loży VIP na ww. stadionie...) Czy nie prościej byłoby od razu obciążyć podatnika kosztem aparatu USG? Tak bez zbędnych pośredników (p. Jurek, pan prezydent gdańska Budyń, itp) -- być może można by kupić za te same pieniądze 3 aparaty USG? A może nawet 4?