>> wybierz styl >> es :: ns :: bs

Weblog Tomasza Przechlewskiego [Zdjęcie T. Przechlewskiego] [[Ikona]]

random image [Photo gallery]
Zestawienie tagów
1-wire | 18b20 | 1wire | 2140 | 3rz | alsamixer | amazon | anniversary | antypis | apache | api | arm | armenia | astronomy | asus | atom.xml | awk | aws | bakłażan | balcerowicz | balta | bash | berlin | bibtex | bieszczady | biznes | blogger | blogging | blosxom | borne-sulinowo | breugel | bt747 | budapeszt | canon | cedewu | chello | chown | chujowetaśmy | cmentarz | contour | cron | css | csv | curl | d54250wykh | debian | dejavu | dhcp | dht22 | dia | docbook | dom | ds18b20 | dyndns | dynia | ebay | economy | ekonomia | elka | elm | emacs | emacs23 | english | ess | eu | excel | exif | exiftool | f11 | fc | fc11 | fc15 | fc5 | fc8 | fedora | fedora21 | fenix | ffmpeg | finepix | firefox | flickr | fontforge | fontspec | fonty | fop | foto | france | francja | fripp | fuczki | fuji | fuse | gammu | garmin | gawk | gazwyb | gdańsk | gdynia | gender | geo | georgia | gft | git | github | gmail | gnokii | gnus | google | googlecl | googleearth | googlemaps | gphoto | gphoto2 | gps | gpsbabel | gpsphoto | gpx | gpx-viewer | greasemonkey | gruzja | grzyby | haldaemon | handbrake | historia | history | hitler | holocaust | holokaust | hpmini | humour | iblue747 | ical | iiyama | ikea | imap | inkscape | inne | internet | j10i2 | javascript | jhead | k800i | kajak | kamera | kleinertest | kml | kmobiletools | knuth | kod | kolibki | komorowski | konwersja | krutynia | kuchnia | kurski | latex | latex2rtf | latex3 | lcd | legend | lenny | lesund | lewactwo | liberation | linux | lisp | lisrel | litwa | logika | ltr | lubowla | lwp | m2wś | mapsource | marvell | math | mathjax | mazury | mbank | mediolan | mencoder | mh17 | michalak | microsoft | monitor | mp4box | mplayer | ms | msc | msw | mtkbabel | museum | muzyka | mymaps | mysql | nanopi | natbib | navin | neo | neopi | netbook | niemcy | niemieckie zbrodnie | nikon | nmea | nowazelandia | nuc | nxml | oauth | oauth2 | obituary | okular | olympus | ooffice | ooxml | opera | otf | otftotfm | other | overclocking | panoramio | pdf | pdfpages | pdftex | pdftk | perl | photo | photography | picasa | picasaweb | pim | pine | pit | plotly | pls | plugin | po | politics | polityka | polsat | postęp | powerpoint | prelink | problem | propaganda | pstoedit | putin | python | r | radio | random | raspberry pi | refugees | relaxng | ridley | router | rower | rowery | rpi | rsync | rtf | ruby | rugby | russia | rwc | rwc2007 | rwc2011 | rzym | samba | sem | sheevaplug | sienkiewicz | signature | sks | skype | skytraq | smoleńsk | sqlite | srtm | ssl | statistics | stats | statystyka | stix | suwałki | svg | svn | swornegacie | szwajcaria | słowacja | tbilisi | terrorism | tex | texgyre | texlive | thunderbird | tomato | tourism | tramp | trang | truetype | ttf | turystyka | tusk | tv | tv5monde | twitter | typetools | ubuntu | uchodźcy | udev | umap | unix | upc | updmap | ups | utf8 | varia | video | vienna | virb edit | vostro | wammu | wdc | wdfs | webcam | webdav | wh2080 | wiedeń | wikicommons | wilno | windows | windows8 | wine | wioślarstwo | word | wordpress | wrt54gl | ws1080 | wtyczka | ww2 | www | wybory | wybory2015 | włochy | węgry | xemex | xetex | xft | xhtml | xine | xml | xmllint | xsd | xslt | xvidtune | youtube | yum | zakopane | zakupy | zdf | łeba | świdnica
Pobrania via google: [[Ikona]]
Inne blogi
N. Walsh | Morten H. Frederiksen | B. Clementson | prawo.vagla.pl | F. Hecker | M. Olson | J. Tennison | J. Clark | M. Nottingham | M. Shuttleworth | T. Isakowicz-Zalewski | J. Anglim | José A. Ortega Ruiz Modern Perl
Inne tematyczne
Ashwin Amanna | wiesia.nets.pl | Wojt | rwm.org.pl | DataBlog | Revolutions | Learning R | A. Gelman | C. Nel | J. Vogelgesang | ubl.xml.org/ | J.D. Long |
O stronie
wykorzystywany jest blosxom plus następujące wtyczki: tagging, flatarchives, rss10, lastbuilddatexhtmlmime. Niektóre musiałem dopasować nieco do swoich potrzeb. Więcej o blosxom jest tutaj
RSS 1.0
Chancellor Merkel victory for a visual person

Change in number of seats won by party (AfD is brown of course regardless official party colors :-):-)


df <- read.csv("de.csv", sep = ';', header=T, na.string="NA");

ggplot(df, aes(x=party, y=diff, fill=party )) +
geom_bar(stat="identity") +
geom_text(aes(label=diff), vjust=-0.5) +
labs(x = "", y="change") +

ggtitle("German elections results (#MP change)") +

## AfD is brown regardless official party colors :-)
scale_fill_manual(values=c("#8B4513", "#56B4E9",
"yellow", "green", "red", "#ff6666") )
url | Mon, 25/09/2017 08:43 | tagi: , ,
Visiting WW2 Museum in Gdańsk

Museum of the Second World War (Muzeum II Wojny Światowej) was opened in March 2017 midst open dispute between the Museum director (a former director now) and deputy PM/culture minister Gliński. Officially the dispute concerns the political message (the government insists on more patriotic education and more attention to suffering and heroism of Poles/Poland while the former director wanted a more universal message of horrendous sufferings of all involved nations.)

While generally I agree with the line of the former director I do not like/recommend the museum at all. It is very, very poor. And it is poor as it lacks interesting exhibits---which is more than visible from the very beginning (cf. photos). Lot of empty rooms, or huge showcases with almost nothing inside or boring stuff (everyday objects: spoons, plates, bicycles etc...). Many replicas/models, very often ridiculously small (ship 30cm long or a tank even smaller). Some stuff not particularly relevant (replica of pre-war Warsaw street or drawings from children competition "How you imagine a war")

In my opinion for a person with a decent knowledge of the subject visiting the museum would be a pure waste of time (and money---less important as the tickets are pretty cheap).

url | Tue, 18/04/2017 04:58 | tagi: , , ,
Installing Ubuntu in Asus X205TA

Ubuntu 16.04 @ X205TA

MS Windows broke down making the box unusable (no keybord/mouse/WiFi etc...) and as Google says it is not easy to recover the system on this particular machine I try Ubuntu, which was installed within 30 minutes (including 20 minutes for copying the files)

Sound is not working, but I suppose it is just a problem of installing proper drivers. After intalling the system 21Gb of 30Gb memory is free, while it was only 10Gb left on Windows (due to 10Gb non-removable recovery partition).

Still any doubts which system is better?

url | Fri, 31/03/2017 09:35 | tagi: , , , ,
Weight of RWC players

Scrapping various Web pages I managed to gather data on players participating in last 4 Rugby World Cups. Is there a trend in body mass of rugby players participating in RWC tournaments?

Using Plotly API via Perl script (described here Box-plot chart with plot.ly and Perl API) I can quickly plot series of boxplots:

# cpan install WebService::Plotly in case  WebService::Plotly is not installed
plotly_boxplot.pl -col=5 -by=0 -title='RWC players by weight' -sep=';' rwc1999-2015.csv

Resulting boxplots and data can be viewed here.

url | Tue, 29/09/2015 16:53 | tagi: , , , , ,
There is a cold summer this year in Sopot
Temperature in Sopot in July 2015
Temp in Sopot/July 2015

The following CSV (on-demand generated from raw data with simple Perl script) file contains outdoor temperature registred every hour starting from 2010 (with DS18B20 sensor):


dayhr is a label and day30 denotes number of seconds from the beginning od the period (for the first observation day30 equals 0, for the second 3600 etc.) The chart was produced with the following custom R script:

number_ticks <- function(n) {function(limits) pretty(limits, n)}

d <- read.csv("july-by-day.csv", sep = ';',  header=T, na.string="NA");

datestart <- ISOdate(2015, 7, 1, tz = "");
d30 <- datestart + d$day30;
d[,"d30"]  <- d30;

ggplot(d, aes(x = d30)) +
  geom_line(aes(y = y2015, colour = 'y2015'), size=.3) +
  geom_line(aes(y = y2014, colour = 'y2014'), size=.3) +
  geom_smooth(aes(y = y2015, colour = 'y2015'), size=1) +
  geom_smooth(aes(y = y2014, colour = "y2014"), size=1) +
  ylab(label="Temp [C]") +
  xlab(label="Observation") +
  scale_y_continuous(breaks=number_ticks(15)) +
  scale_x_datetime(breaks = date_breaks("5 days")) +
  theme(legend.title=element_blank()) +
  ggtitle("Temperature in July in Sopot") +
  theme(legend.position=c(.6, .9)) +

ggsave(file="Temp-M7-2015.pdf", width=15, height=8)

url | Fri, 31/07/2015 14:34 | tagi: , ,
Uploading pictures to Picasaweb with Perl/LWP::UserAgent

Previously described bash script allows for uploading a file to PicasaWeb only. With the following (simplified) Perl script one can upload pictures as well as upload with metadata (title description and tags) or create/list albums:


use strict;

use LWP::UserAgent;
use Getopt::Long;
use File::MimeInfo;
use XML::LibXML;

my $AlbumId ="6170354040646469009";
my $profileID="default";

my $Action = 'u'; ## x| u | c | l (default action is Upload)
my $entryTitle = ''; my $entryDescription = '';
my $entryKeywords = '';
my $ActionUpload =''; my $ActionList = '';
my $ActionCreate = ''; my $ActionXload = '';
my $ImageFile = '';
my $dummyReq='';

GetOptions("xload" => \$ActionXload, "upload" => \$ActionUpload,
  "list" => \$ActionList, "create" => \$ActionCreate,
  "title=s" => \$entryTitle, "description=s" => \$entryDescription,
  "keywords=s" => \$entryKeywords,
  "file=s" => \$ImageFile,
  "album=s" => \$AlbumId, ## UploadFile to Album
) ;

## Determine action:
if ( $ActionUpload ) {$Action = 'u'} elsif ( $ActionList ) { $Action = 'l'}
elsif ( $ActionCreate ) { $Action = 'c'}
elsif ( $ActionXload ) { $Action = 'x'}

OAuth 2.0 authorization is handled with Python script oauth2picasa.py. The script is an adapted/copy-pasted fragment of code borrowd from picasawebsync:

### Authenticate with external script (oauth2picasa.py):
my $ACCESS_TOKEN=`oauth2picasa.py`;
print STDERR "*** AccessToken: $ACCESS_TOKEN [AlbumId: $AlbumId]\n";

my $req ; my $blog_entry ;

my $picasawebURL = "https://picasaweb.google.com/data/feed/api/user/$profileID";

if ( $Action eq 'c' ) {## Action: create album
  $req = HTTP::Request->new(POST => $picasawebURL );
  $req->header( 'Content-Type' => 'application/atom+xml' );

  $blog_entry = "<entry xmlns='http://www.w3.org/2005/Atom'
  . "<title type='text'>$entryTitle</title>"
  . "<summary type='text'>$entryDescription</summary>"
  . "<media:group><media:keywords>$entryKeywords</media:keywords></media:group>"
  . "<category scheme='http://schemas.google.com/g/2005#kind'

elsif ( $Action eq 'l' ) {## Action: list albums
  $req = HTTP::Request->new(GET => $picasawebURL );

elsif ( $Action eq 'u' ) {## Action: Upload 1 photo w/o metadata
  my $mimeType = mimetype($ImageFile);

  ## https://developers.google.com/picasa-web/docs/2.0/developers_guide_protocol
  $req = HTTP::Request->new(POST => "$picasawebURL/albumid/$AlbumId" );
  $req->header( 'Content-Type' => "$mimeType" );
  $req->header( 'Slug' => "$ImageFile" );

  ## http://www.perlmonks.org/?node_id=131584
  open(FILE, $ImageFile);

To upload the binary image data along with its metadata, use MIME content type "multipart/related"; send photo metadata in one part of the POST body (Content-Type: application/atom+xml), and binary-encoded image data in another part. This is the preferred approach according to Picasa Web Albums Data API Picasa Web Albums Data API

elsif ( $Action eq 'x' ) {## Action: Upload 1 photo with metadata
  # https://groups.google.com/forum/#!topic/google-picasa-data-api/2qRfP0EIFhk
  my $mimeType = mimetype($ImageFile);

  $req = HTTP::Request->new(POST => "$picasawebURL/albumid/$AlbumId" );
  $req->header( 'Content-Type' => "multipart/related" );

  open(FILE, $ImageFile);
  my $add_photo_metadata = "<entry xmlns='http://www.w3.org/2005/Atom' 
  . "<title type='text'>$entryTitle</title>"
  . "<summary type='text'>$entryDescription</summary>"
  . "<media:group><media:keywords>$entryKeywords</media:keywords></media:group>"
  . "<category scheme='http://schemas.google.com/g/2005#kind' 

  my $add_photo_data = join('',<FILE>); close(FILE);

  ## http://www.perlmonks.org/?node_id=131584
      => 'application/atom+xml'], $add_photo_metadata));
      => "$mimeType"], $add_photo_data));

$req->header( 'Authorization' => "Bearer $ACCESS_TOKEN" );
$req->header( 'GData-Version' => '2' );

## ### ###
my $res ;
my $ua = LWP::UserAgent->new;

$res = $ua->request($req);

if ($res->is_success) {
   my $decoded_response = $res->decoded_content;
   print "*** OK *** $decoded_response\n";


Upload with metadata

picasaweb.pl -xload -title PICTURE-TITLE -descr DESCRIPTION \
  -keywords 'TAG1,TAG2' -file FILE.jpg -album ALBUMID

Upload w/o metadata:

picasaweb.pl -upload -file FILE.jpg -album 12345

Create album:

picasaweb.pl -create -title ALBUM-TITLE -descr DESCRIPTION \
   -keywords 'TAG1,TAG2'

List album:

picasaweb.pl -list

Source code: picasaweb.pl

url | Thu, 30/07/2015 09:48 | tagi: , , , ,
Uploading pictures to Picasaweb with Curl

My (simplified) old bash script for uploading images to Picasaweb (cf. Using cURL to interact with Google Data services and PicasaUploader):

USERNAME=SomeUsername # GoogleAccountUsername
PASSWORD=SomePasswd # GoogleAccountPasswd
ALBUM_ID=6008849823888405298 # ID of picasaweb album

MY_PIC="$1" ## filename of the picture to upload ##
PIC_TITLE=`basename $MY_PIC` # filename w/o extension
PIC_TYPE=`file -b --mime-type "$MY_PIC"`

AUTH_KEY=$( curl -s https://www.google.com/accounts/ClientLogin -d Email="$USERNAME"@gmail.com \
  -d Passwd="$PASSWORD" -d accountType=GOOGLE \
  -d source=Google-cURL-Example -d service=lh2 | awk -F\= '/^Auth=/{print $2}' )

URL=`curl -s --request POST --data-binary "@$MY_PIC" --header "Slug: $PIC_TITLE" \
 --header "Content-Type: $PIC_TYPE" \
 --header "Authorization: GoogleLogin auth=$AUTH_KEY" "$ALBUM_XML" | \
sed 's/.*media:content url='"'"'\([^'"'"']*\).*media:thumbnail url='"'"'\([^'"'"']*\).*/\1/'`

URL contains url of uploaded picture (obtained with piping curl's output via sed).

This script stoped working recently as Google no longer supports OAuth 1.0 (cf. Google Identity Platform). Fortunately it was pretty easy to modify it to support OAuth 2.0:

ACCESS_TOKEN=$(oauth2picasa.py) ## Acces token is managed with Python's script now
## Note that ALBUM_XML URL starts now from https:// now

URL=`curl -s --request POST --data-binary "@$MY_PIC" \
--header "GData-Version: 2" --header "Slug: $PIC_TITLE" \
--header "Content-Type: $PIC_TYPE" -H "Authorization: Bearer $ACCESS_TOKEN" $ALBUM_XML |  \
sed 's/.*media:content url='"'"'\([^'"'"']*\).*media:thumbnail url='"'"'\([^'"'"']*\).*/\1/'`

NOTE: OAuth 2.0 authorization is handled with tiny Python script oauth2picasa.py. The script is an adapted/copy-pasted fragment of code borrowd from picasawebsync:


import os
import time
import httplib2
## https://github.com/google/oauth2client
## installed with pip install --upgrade oauth2client (or some other way)
from oauth2client import client

def oauthLogin():
        # using http://stackoverflow.com/questions/20248555/list-of-spreadsheets-gdata-oauth2/29157967#29157967
        from oauth2client.file import Storage

        filename = os.path.join(os.path.expanduser('~'), ".picasawebsync")
        client_secrets = os.path.join(os.path.expanduser('~'), ".config", "picasawebsync.json")

	storage = Storage(filename)
        credentials = storage.get()
        if credentials is None or credentials.invalid:  
	        flow = client.flow_from_clientsecrets(client_secrets,
                auth_uri = flow.step1_get_authorize_url()       
                print 'Authorization URL: %s' % auth_uri
                auth_code = raw_input('Enter the auth code: ')
                credentials = flow.step2_exchange(auth_code)
        if credentials.access_token_expired:
        return credentials.access_token

# start of the program

gd_client = oauthLogin()

print '%s' % gd_client

How to create an OAuth 2.0 client ID in the Google Developers Console is described here. Choose Client ID for native application. Next download JSON file, rename it to picasawebsync.json and move it to .config directory in your HOME directory (or modify the script).

First time used oauth2picasa.py prompts to sign on to google and paste the link back to authenticate.

Source code: picasa_upld.sh and oauth2picasa.py.

url | Mon, 22/06/2015 11:40 | tagi: , , , , ,
My old Canon LIDE 25 scanner works only once

My old Canon CanoScan LIDE 25 scanner is not working properly with my new hardware (Intel NUC) and Fedora 21.

I suspected Fedora 21 bug, but the problem is with the hardware, exactly as describe here. Works once and got stuck when scanning next.

It is claimed problem is solved in version 1.025 of Sane. To compile Sane one has to install libusb-devel package first:

yum install libusb-devel


git clone git://git.debian.org/sane/sane-backends.git
cd sane-backends

# I would like to install whole stuff in /usr/local
# without removing original fedora package
./configure --prefix=/usr/local --sysconfdir=/usr/local/etc \
    --localstatedir=/var BACKENDS=plustek
make install

Sane works now.

I would like to avoid mixing original Sane files with the new ones, so I use --prefix and --sysconfdir options with appropriate values. New Sane will be installed in /usr/local and it will be run by default--no need to remove original Fedora packages.

url | Thu, 28/05/2015 08:33 | tagi: , , ,
Sorry, Charlie Hebdo

It seems Charlie Hebdo massacre is a big surprise in France but what shock me even more is that the plain fact that France is at war with ISIS (cf French planes carry out air strikes on Isis targets in Iraq) was so efficiently obliterated from the awarness of the french populations, that the attack is met with naive incredulity and the reaction to it is so infantile.

The victims are presented now as defenders of freedom of speech which is not the case. They just produced stupid pictures, went to war with religion and (to their surprise) the religion retaliated. True free speach hero is (among many others) Norman Finkelstein who comments Charlie Hebdo massacre with the picture reprinted here.

url | Tue, 13/01/2015 18:34 | tagi: , , , ,
New Year in Vienna

With ZK and his family we have spent 3 days in Vienna. If you are interested click the map below to see journey GPX track and photos.

We visited Schönbrunn Palace (a former imperial summer residence), Stephansdom, and Kunsthistorisches museum (where one can see Pieter Bruegel's famous paintings including: The Tower of Babel, The Fight Between Carnival and Lent, and The Hunters in the Snow).

We also visited Flak Towers which are enormous concrete bunkers constructed during 2nd world war. FLAK stands for Flug Abwehr Kanone (or Flugzeugabwehrkanone) and Flak Towers were a part (not particularly effective--mobile system is always better for obvious reason) of German air defence system intended to protect cities and residential areas from Allied air raids. Their construction was planned in September 1942 and Vienna was the third city after Berlin and Hamburg that got them.

The Flak Towers fulfilled two purposes (cf. Flak-Türme Towers, Vienna: Nazi concrete heritage at Vienna's heart): They held cannons and spotlights that should fight airplanes from the ground; and they were important bunkers with an autonomous electricity, air and water supply system. They were built in pairs, comprising of larger Gefechtsturm (Combat Tower) and a smaller Leitturm (Fire-control tower). The three pairs of Vienna can be found in the Augarten in the second district, the Arenberg Park in the third district and one each in the Esterhazypark in the sixth and the Stiftskaserne in the seventh.

We visited Augarten and Arenberg towers.

url | Tue, 06/01/2015 11:49 | tagi: , , , , , ,
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...

url | Fri, 05/09/2014 13:13 | tagi: , , , , ,
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:

# 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 )

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

if [ -z "$OUT_FILE" ] ; then

if [ -f "$FILE" ] ; then

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


  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 ;

  ## 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
	echo "*** $FILE width: $my_pic_width ; converting to $SIZE"
	convert "$FILE" -geometry $SIZE "$my_pic"
	echo "*** $FILE height: $my_pic_height ; converting to $SIZE"
	convert "$FILE" -geometry $SIZE "$my_pic"
      ## File is too small copy the original:
      echo "*** $FILE has $my_pic_width in width; COPYING"
      cp "$FILE" "$my_pic"
   echo "*** FILE $FILE not found! ***"

Upload one picture to picasa with 1photo2picasa.sh

# 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:

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";;

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"
   ## 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}}'`

   ## 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"

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

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


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

for file in *.jpg; do

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


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

url | Wed, 23/07/2014 21:34 | tagi: , , ,
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

url | Mon, 21/07/2014 15:29 | tagi: , , , , , , ,
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.

url | Sun, 29/06/2014 13:50 | tagi: , ,
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.

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/

url | Mon, 07/04/2014 14:01 | tagi: , , ,
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):

# Check if Internet connection is still alive *** 
# Insert into crontab at *.16

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

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:  Bcast:  Mask:

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:  Bcast:  Mask:

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

url | Sun, 09/02/2014 17:38 | tagi: , , ,
Temperature statistics 2010--2013

Average monthly outdoor temperature for Sopot, Abrahama in 2010--2013 (recorded with DS18B20 sensor). Average monthly temperature computed as $t_a = \sum_i^n t_i/n$, where: $t_i$ denotes measurement recorded in month $i$ (the temperature is recorded every hour BTW).

Average monthly outdoor temperature for Sopot

Click to see interactive version and data at plot.ly

The data shows (among other things:-) that December 2013 was really hot.

url | Tue, 31/12/2013 18:00 | tagi: , , ,
A newer version of the Raspberry Pi

I am using Raspberry Pi version A (256 Mb) for more than a year and now I bought one Pi more--model B (512 Mb) this time. I bought a TP-Link WiFi card (TL-WN725N) and a camera as well. The plan is:

Attaching everything to one single Pi is not an option--I want the camera-equipped Pi to be more portable.

Also I did not want to install a new system but just to use what I use so far (ie the system used on the old Pi):

Raspberrystar.pinkaccordions.org Linux 3.2.27 + # 174 PREEMPT ... 

Simple inserting the card from the old Pi into the new one did not work (the system did not start). An upgrade is needed probably:

sudo apt-get update 
sudo rpi-update 
Raspberrystar.pinkaccordions.org Linux 3.10.18 + 

Now 1-Wire bus stopped working. I also can not start the WiFi adapter TP-Link TL-WN725N. Inspecting Internet forums I discovered that version 3.6.11+ of the kernel may be less problematic in this respect. Therefore, I try to downgrade:

sudo rpi-update 8234d5148aded657760e9ecd622f324d140ae891 

The above means to downgrade to the latest of 3.6.11+ versions:

pi @ raspberrystar ~ $ uname-a 
Linux 3.6.11 + raspberrystar.pinkaccordions.org # 557 PREEMPT 

Now the 1-Wire bus magically started to work. Sensors DHT-22 also work. The program I have used to read data from pressure sensor BMP085 required minor modifications and recompilation (as GPIO layout is different on Pi model B).

WiFi card also works, but require to download an appropriate driver. This one works for me (a copy is here). Other drivers, such as available here or here do not work. Compilation from sources as described here (in Polish is here) ends with an error as well.

Module 8188eu.ko can be installed as follows:

wget http://www.mendrugox.net/downloads/13 -O 818188eu.ko
## albo https://dl.dropboxusercontent.com/u/61315145/PiStuff/8188eu.ko.gz
## after download: gunzip 8188eu.ko.gz

sudo install -p -m 644 8188eu.ko /lib/modules/`uname -r`/kernel/drivers/net/wireless
sudo depmod -a
sudo modprobe 8188eu

The contents of the file /etc/network/interfaces should look like:

auto lo 

iface lo inet loopback 
iface eth0 inet dhcp 

allow-hotplug wlan0 
auto wlan0 
iface wlan0 inet dhcp 
wpa-ssid "NAME OF-NETWORK" 
wpa-psk "PASSWORD" 

One have to provide correct values for the NAME-NET and PASSWORD of course. The above settings will automatically establish a connection when the system starts.

Changing the host name

Minor thing, but I want to know easily which Pi is which:

## in the last line of /etc/hosts change host name
sudo vi /etc/hosts 

## insert host name (this file contains only 1 line with a host name:)
sudo vi /etc/hostname

sudo /etc/init.d/hostname.sh
sudo reboot

The file /etc/hosts looks something like this: localhost 
:: 1 localhost ip6-localhost ip6-loopback 
fe00 :: 0 ip6-localnet 
ff00 :: 0 ip6-mcastprefix 
ff02 :: 1 ip6-allnodes 
ff02 :: 2 ip6-allrouters blackberrystar 


Updated system was cloned on a second card (Btw. for years I use Toshiba SDHC 8GB Class 10. This card is advertised as SLC but on card packaging/casing there is no word about it. SLC or not SLC I had never any problem with this card.)

Pi + kamera
Pi + camera

First picture

How to connect a camera to the Pi can be seen at one of the many videos on YouTube.

I followed instructions from How to set up the camera hardware.

Since I have not done this before:

pi@blackberrystar ~ $ sudo apt-get update
pi@blackberrystar ~ $ sudo apt-get upgrade


pi@blackberrystar ~ $ sudo raspi-config

I Choose Enable/Disable camera addon support and Memory split. I have not decided on the suggested 128 Mb for the GPU, bearing in mind that all the memory in my Pi is 256 Mb. Perhaps I am wrong and recommended 128MBs is better.

Test if it works:

pi@blackberrystar ~ $ mkdir picam
pi@blackberrystar ~ $ cd picam 
pi@blackberrystar ~ $ raspistill -o image.jpg

The result (the first picture taken) is shown on the picture.

url | Tue, 10/12/2013 10:58 | tagi: , ,
3rd anniversary of pinkaccordions.homelinux.org

Three years from now pinkaccordions.homelinux.org was created. It runs for 3 years on sheevaplug Arm-based server running Debian installed on SDHC 8Gb card (details here).

url | Sun, 19/05/2013 20:05 | tagi: , , ,
Time lapse: end of first experiment

Because my tomatoes are growing unexpectedly fast I had to stop capturing pictures quicker than I have planned as they do not fit in the frame.

So 2664 pictures was taken from 16.03 to 23.04 at 20 minutes interval. The video size is about 715 Mb and the video length is 3min 43 seconds (at 12 fps or 1:47 at 25 fps).

The videos are available at YouTube: 25 fps | 12 fps

url | Wed, 24/04/2013 16:35 | tagi: , , , , , , , , ,
Augmenting video files with GPS data

This post describes in detail how to add GPS data to video file using `visual correlation' (see also: Video geocoding with gpsbabel).

Zebra crossing at Osowa
Crossing at Osowa

There is an easy way to augment video files with GPS data using GPSbabel. Since version 1.4 of GPSBabel is able to create a subtitle file from a GPS tracklog. The subtitle contains latitude/longitude/altitude as well as the time. With a simple Perl scripts I have added current speed (not particularly accurate however).

To convert GPX file to subtitles one have to execute:

gpsbabel -i gpx -f FILE.gpx -o subrip,video_time=hhmmss,gps_time=hhmmss,gps_date=YYYYMMDD -F FILE.srt

Where: video_time -- video position (relative to beginning of video) for which exact corresponding GPS timestamp is known. gps_time -- the time part of the GPS timestamp which corresponds to a known position in the video. gps_date -- the date part of the GPS timestamp which corresponds to a known position in the video.

On a video (see below) you can see that in 34 second I passed the zebra crossing. The zebra's crossing coordinates can be easily identified at Google Maps (cf. picture Crossing at Osowa). Now one have to search the GPX track for the point which is nearest to 54.429591/18.477973. I developed a simple Perl script for that purpose:

$ perl My_GPX_nearest_timestamp.pl   -c 54.429591:18.477973 20130420.gpx
*** USAGE: My_GPX_nearest_timestamp.pl -c latitude:longitude GPX-file
*** Looking for 20 points near: 54.429591:18.477973 (lat/lon) ***
> 15.3758195746663 2013-04-20T10:27:09Z  54.429509640:18.477780819
> 22.0617273294607 2013-04-20T09:05:15Z  54.429701502:18.478256240
> 32.6458959467509 2013-04-20T10:27:15Z  54.429787332:18.478348190
> 43.3771684316959 2013-04-20T09:05:24Z  54.429531014:18.477310427
> 47.7727043140018 2013-04-20T09:05:11Z  54.429905936:18.478475260
> 63.903936892351 2013-04-20T10:27:00Z  54.429627573:18.476987137
> 70.171200323179 2013-04-20T09:05:28Z  54.429655485:18.476893930

One can stipulate from the above output that I passed a point 15,4 meters away from 54.429591/18.477973 at 10:27:09 GMT as well as I passed onother point which is 22 meters away from 54.429591/18.477973 at 09:05:15. As I cycled back and forth along the same route the second point is valid, the first is accidentally closer but as the time is almost one and half hours later it is clear that I was there on returning home. So gpsbabel should be executed as follows (20130420.gpx contains GPX track):

gpsbabel -i gpx -f 20130420.gpx -o subrip,video_time=000034,gps_time=090515,gps_date=20130420 -F 20130420_1.srt

Speed is added with another very simple Perl script:

perl add_speed_2_srt.pl 20130420_1.srt > 20130420_1_S.srt

Just to remind: internally all GPS units record time/date using Coordinated Universal Time aka Greenwich Mean Time vel Zulu time (for army enthusiasts). What the unit displays is another matter (usually it displays local time).

url | Sun, 21/04/2013 14:42 | tagi: , , ,