From 650bd4c7052fe00d2ff00aba4e4ba56f663d8bd9 Mon Sep 17 00:00:00 2001 From: Marc Hoppe Date: Sun, 16 Dec 2012 18:46:30 +0100 Subject: [PATCH] diverses hinzu --- SyncPOD | 862 +++++++++++++++++++++ cd-blank | 18 + cd-burn-files | 25 + cd-burn-image | 25 + cd2mp3 | 97 +++ cda2hd | 24 + convnow.sh | 56 ++ cp_packages.sh | 28 + create_omtb_garmin_img.sh | 140 ++++ create_opkg_index.sh | 1 + createhdextlinks.sh | 9 + createhdextlinks.sh~ | 7 + dropbox.py | 821 ++++++++++++++++++++ dvd-blank | 6 + dvd-burn-files | 24 + dvd-burn-image | 15 + dvd-burn-video | 16 + dvd-check-size | 17 + dvd-createdev | 16 + dvd-format | 6 + dvd-gen-movix | 31 + dvd-rip-image | 17 + dvd2vdr | 1378 ++++++++++++++++++++++++++++++++++ dvdauthor_helperfunctions.sh | 86 +++ dvddirdel | 41 + dvdunauthor | Bin 0 -> 158013 bytes fv_html | 5 + getrecnames.sh | 18 + git-prompt.sh | 707 +++++++++++++++++ init-var-on-tmp.sh | 8 +- instapaper_epub.sh | 10 + ipad.sh | 12 +- iso2utf.sh | 10 + m4a2ogg.sh | 25 + mirrors.update | 15 + mkosm.sh | 29 + mkvdrrecdir.sh | 7 + mp32wav | 85 +++ podcastupdate.sh | 13 + podcastupdated.sh | 3 + queue | 16 + recwebradio.sh | 5 + rmdvbmodules.sh | 17 + start_dropbox.sh | 1 + sync_pod.pl | 862 +++++++++++++++++++++ syncauto.sh | 3 + taz-download.sh | 5 +- tazsync.sh | 26 + test.sh | 7 + tonas.sh | 3 + torrentcreate.sh | 1 + tvm2vdr_start | 12 + unqueue | 15 + update_garmin.sh | 15 +- vdrrecren | 199 +++++ vdrrecren.rb | 144 ++++ vdrrecren_start | 4 + zeit.sh | 12 +- 58 files changed, 6040 insertions(+), 20 deletions(-) create mode 100755 SyncPOD create mode 100755 cd-blank create mode 100755 cd-burn-files create mode 100755 cd-burn-image create mode 100755 cd2mp3 create mode 100755 cda2hd create mode 100755 convnow.sh create mode 100644 cp_packages.sh create mode 100755 create_omtb_garmin_img.sh create mode 100644 create_opkg_index.sh create mode 100644 createhdextlinks.sh create mode 100644 createhdextlinks.sh~ create mode 100755 dropbox.py create mode 100755 dvd-blank create mode 100755 dvd-burn-files create mode 100755 dvd-burn-image create mode 100755 dvd-burn-video create mode 100755 dvd-check-size create mode 100755 dvd-createdev create mode 100755 dvd-format create mode 100755 dvd-gen-movix create mode 100755 dvd-rip-image create mode 100755 dvd2vdr create mode 100755 dvdauthor_helperfunctions.sh create mode 100755 dvddirdel create mode 100755 dvdunauthor create mode 100755 fv_html create mode 100644 getrecnames.sh create mode 100755 git-prompt.sh create mode 100644 instapaper_epub.sh create mode 100755 iso2utf.sh create mode 100644 m4a2ogg.sh create mode 100644 mirrors.update create mode 100644 mkosm.sh create mode 100755 mkvdrrecdir.sh create mode 100755 mp32wav create mode 100755 podcastupdate.sh create mode 100755 podcastupdated.sh create mode 100755 queue create mode 100644 recwebradio.sh create mode 100644 rmdvbmodules.sh create mode 100644 start_dropbox.sh create mode 100755 sync_pod.pl create mode 100644 syncauto.sh create mode 100644 tazsync.sh create mode 100644 test.sh create mode 100644 tonas.sh create mode 100644 torrentcreate.sh create mode 100755 tvm2vdr_start create mode 100755 unqueue create mode 100755 vdrrecren create mode 100755 vdrrecren.rb create mode 100755 vdrrecren_start mode change 100644 => 100755 zeit.sh diff --git a/SyncPOD b/SyncPOD new file mode 100755 index 0000000..49352b5 --- /dev/null +++ b/SyncPOD @@ -0,0 +1,862 @@ +#!/usr/bin/perl -w + +# (c) 2002 Armin Obersteiner +# License: GPL v2 + +use MP3::Info; +use Unicode::String qw( latin1 utf16 ); +use Shell qw ( find gzip ); +use Getopt::Std; +use File::Copy; +use Filesys::DiskFree; + +use Data::Dumper qw (Dumper); + +use strict; + +my $version="0.68"; + +# +# options & config +# + +my %opt; +getopts("fcnh",\%opt); + +if($opt{h}) { + print <<"EOF"; +$0 [-c] [-f] [Search Pattern 1] [Search Pattern 2] ... + + -c create: create directory structure on plain ipod before syncing + (default: you get a warning if there is no ipod structure) + + -f force: rename ipod and use it with $0 before syncing + (default: an unknown ipod stays untouched) + + -n name check: checks mp3 names for possible illegal characters + + Search Patterns: for each search pattern a playlist is created + (case insensitive) +EOF + exit; +} + +my $buffer = 5*1024*1024; # leave some MB free for iTunesDB + +my @required = qw ( SYNCMODE PLAYLISTDIR IPODDIR BACKUPDIR ); + +my $rc=readrc("$ENV{HOME}/.ipod/config",\@required); + +#print Dumper($rc); + + +# +# check ipod name +# + +my ($ipod_name, $real_name, $computer_name)=get_ipodname($rc->{IPODDIR}); +unless($ipod_name) { + die "IPOD dir not found: $rc->{IPODDIR}" unless $opt{c}; +} + +# +# check ipod dirs (recreate them if necessary) +# + +mkdir "$rc->{IPODDIR}/iPod_Control",0755 unless(-d "$rc->{IPODDIR}/iPod_Control"); +mkdir "$rc->{IPODDIR}/iPod_Control/Music",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music"); +mkdir "$rc->{IPODDIR}/iPod_Control/iTunes",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/iTunes"); +mkdir "$rc->{IPODDIR}/iPod_Control/Device",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Device"); +for(0..19) { + my $d=sprintf "%.2d",$_; + mkdir "$rc->{IPODDIR}/iPod_Control/Music/F$d",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music/F$d"); +} + +unless($opt{c}) { + print STDERR "IPOD name: $ipod_name\n"; + print STDERR "Synced by: $real_name\n"; + print STDERR "Synced on: $computer_name\n"; + + if($rc->{WRITEDEVICEINFO} && !$opt{f}) { + my $exit=0; + unless($rc->{IPODNAME} eq $ipod_name) { + $exit=1; + print STDERR "Your IPOD name: $rc->{IPODNAME}\n"; + } + unless($rc->{REALNAME} eq $real_name) { + $exit=1; + print STDERR "Your real name: $rc->{REALNAME}\n"; + } + unless($rc->{COMPUTERNAME} eq $computer_name) { + $exit=1; + print STDERR "Your computer: $rc->{COMPUTERNAME}\n"; + } + die "names mismatch, use -f to override" if $exit; + } + print STDERR "\n"; +} + +# +# write ipod name +# + +if($rc->{WRITEDEVICEINFO}) { + set_ipodname( + $rc->{IPODDIR},$rc->{BACKUPDIR}, + $rc->{IPODNAME},$rc->{REALNAME},$rc->{COMPUTERNAME} + ); + $ipod_name=$rc->{IPODNAME}; +} + +# +# check for songs +# + +my %songs; +my %check; + +my $dir; +$dir=$rc->{IPODDIR}."/iPod_Control/Music"; +$dir=$rc->{SYNCDIR} if($rc->{SYNCMODE} >= 2); + +my %tosync; +if(($rc->{SYNCLIST}) && ($rc->{SYNCMODE} == 2)) { + open IN,$rc->{SYNCLIST} or die "all-playlist: $rc->{SYNCLIST} not found"; + while() { + chomp; + $tosync{$_}=1; + } + close IN; +} + +my @mp3s; +if(($rc->{SYNCMODE} == 3)) { + my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null"); + my %test; + + for my $p (@pl) { + chomp $p; + my ($n) = $p =~ /.*\/(.*?)$/; + open IN,$p or die "playlist: $p could not be opened"; + while() { + unless($test{$_}) { + push @mp3s,$_; + $test{$_}=1; + } + } + } +} else { + @mp3s=find($dir); +} + +for(@mp3s) { + chomp $_; + next unless(/\.(m|M)(p|P)3$/); + my $name=$_; + + if(keys %tosync) { + next unless($tosync{$name}); + } + + if($opt{n}) { + die "illegal character in filename [$name]\n" unless ($name =~ /^[A-Za-z0-9\.\-_\/\,]+$/); + } + + s/\://g; + s/.*\///g; + $songs{$name}{name}=$_; + if($rc->{SYNCMODE} >= 2) { + $songs{$name}{dir}="F".hash($_); + } else { + ($songs{$name}{dir}) = $name =~ /\/(F\d\d)\//; + } + + { + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) = stat($name); + $songs{$name}{size}=$size; + $songs{$name}{date}=$mtime; + } + + my $tag; + $tag = get_mp3tag($name) unless($rc->{ALWAYSTEMPLATES}); + + my ($artist,$album,$title,$order,$_dummy_); + + if($tag) { + # print Dumper($tag); + # YEAR ARTIST COMMENT TRACKNUM TITLE ALBUM GENRE + $artist=$tag->{ARTIST}; + $album=$tag->{ALBUM}; + $title=$tag->{TITLE}; + $order=$tag->{TRACKNUM}; + $order=$1 if($order =~ /(\d+)\s*\//); + + } else { + for(sort {length($b) <=> length($a)} keys %{$rc->{FILETEMPLATES}}) { + if(my @x = $name =~ /$_/) { + my $c=0; + for my $x (@x) { + #print "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";\n"; + eval "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";"; + die "eval error: $@" if($@); + $c++; + } + last; + } + } + } + + unless($title) { + die "no title found in: $name"; + } + + $title =~ s/_/ /g; + $artist =~ s/_/ /g; + $album =~ s/_/ /g; + + $songs{$name}{title}=$title; + $songs{$name}{artist}=""; + $songs{$name}{album}=""; + $songs{$name}{order}=0; + $songs{$name}{artist}=$artist if $artist; + $songs{$name}{album}=$album if $album; + $songs{$name}{order}=$order if $order; + + my $info = get_mp3info ($name); + + $songs{$name}{size}=$info->{SIZE}; + $songs{$name}{bitrate}=$info->{BITRATE}; + $songs{$name}{duration}=int($info->{SECS}*1000); + $songs{$name}{vbr}=$info->{VBR}; + + #print Dumper($info); + + my $n=$songs{$name}{dir}."/".$songs{$name}{name}; + unless($check{$n}) { + $check{$n}=1; + } else { + die "songname: $songs{$name}{name} not unique"; + } +} + +# +# deleting unwanted songs +# + +my %known; +for(keys %songs) { + $known{$songs{$_}{name}}=1; +} + +#print Dumper(\%known); + +my @ipod = find ("$rc->{IPODDIR}/iPod_Control/Music"); +my @todel; +for(@ipod) { + next unless (/\.mp3$/i); + chomp; + + my ($name) = $_ =~ /\/([^\/]+\.mp3)$/i; + unless($known{$name}) { + push @todel,$_; + } +} + +my $del; +if($rc->{DELETEASK} && @todel) { + for(@todel) { + print "del: $_\n"; + } + print "Do you really want to delete this songs? (y/N) "; + my $in=; + chomp $in; + $del=1 if($in =~ /^y$/i); +} else { + $del=1; +} + +if($del) { + for(@todel) { + print STDERR "deleting: $_\n"; + unlink($_); + } +} + +# +# copy songs +# + +my $main_sl=""; +my $main_pl=""; +my $index=500; + +#print Dumper(\%songs); + +my $df = new Filesys::DiskFree; + +SONGS: for my $song (keys %songs) { + my $attr; + my $out=""; + my $attr_c=3; + + if($rc->{SYNCMODE} >= 2) { + my $to = "$rc->{IPODDIR}/iPod_Control/Music/$songs{$song}{dir}/$songs{$song}{name}"; + #my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + # $atime,$mtime,$ctime,$blksize,$blocks) = stat($to); + #$size=0 unless $size; + #print "checking: $song [$songs{$song}{size}] -> $to [$size]\n"; + #if($size != $songs{$song}{size}) { + + unless(-e $to) { + print STDERR "syncing: $songs{$song}{name}\n"; + # cp "\"$song\" \"$to\""; + + $df->df(); + my $free=$df->avail($rc->{IPODDIR}); + + if($free-$songs{$song}{size}-$buffer>0) { + copy($song,$to); + } else { + print STDERR "no space availiable for: $songs{$song}{name} [$songs{$song}{size}]\n"; + delete $songs{$song}; + next SONGS; + } + } + } + + $songs{$song}{index}=$index; + + $out.=create_mhod($songs{$song}{title},1); + + if($songs{$song}{artist}) { + $attr_c++; + $out.=create_mhod($songs{$song}{artist},4); + } + if($songs{$song}{album}) { + $attr_c++; + $out.=create_mhod($songs{$song}{album},3); + } + + $out.=create_mhod("MPEG audio file",6); + $out.=create_mhod(":iPod_Control:Music:".$songs{$song}{dir}.":".$songs{$song}{name},2); + + $out=create_mhit( + $attr_c,length($out),$index,$songs{$song}{vbr}, + $songs{$song}{date},$songs{$song}{size}, + $songs{$song}{duration},$songs{$song}{order}, + $songs{$song}{bitrate} + ).$out; + + $main_sl.=$out; + + $main_pl.=create_mhod_mhip($songs{$song}{index}); + + $index++; +} + +#print Dumper(\%songs); + +my %playlists; +my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null"); + +for my $p (@pl) { + chomp $p; + my ($n) = $p =~ /.*\/(.*?)$/; + open IN,$p or die "playlist: $p could not be opened"; + while() { + my $song=$_; + chomp $song; + + unless($songs{$song}) { + print STDERR "ignoring song in playlist [$p], [$song] does not exist in syncdir or ipod full\n"; + } else { + $playlists{$n}{raw}.=create_mhod_mhip($songs{$song}{index}); + $playlists{$n}{count}++; + } + } + close IN; +} + +# +# creating search pattern playlists +# + +for my $pattern (@ARGV) { + my @list; + for(keys %songs) { + push @list,$songs{$_}{index} if($_ =~ /$pattern/i); + } + unless(@list) { + print STDERR "nothing for searchpattern: $pattern found\n"; + } else { + my ($name)=$pattern=~/(\S\S\S+)/; + unless(length($name)>=3) { + $name=$pattern; + $name =~ s/[^A-Za-z0-9]//g; + } + for(@list) { + $playlists{$name}{raw}.=create_mhod_mhip($_); + $playlists{$name}{count}++; + } + print STDERR @list." songs for searchpattern: $pattern found\n"; + } +} + +#print Dumper(\%playlists); + +# +# build the pieces together +# + +my $output; + +my $song_c=keys %songs; + +print STDERR "\nFound songs: $song_c\n"; + +my $tmp=create_mhlt($song_c).$main_sl; +$main_sl=create_mhsd(96+length($tmp),1).$tmp; + +print STDERR "Songlist created\n"; + +my $pl_c=keys %playlists; + +print STDERR "\nFound additional playlists: $pl_c\n"; + +$tmp=create_mhlp($pl_c+1).create_playlist_main($ipod_name,$song_c).$main_pl; +print STDERR "\nMain playlist created: $song_c songs\n\n"; + +for(keys %playlists) { + $tmp.=create_playlist($_,$playlists{$_}{count}).$playlists{$_}{raw}; + print STDERR "Playlist \"$_\" created: $playlists{$_}{count} songs\n"; +} + +$main_pl=create_mhsd(96+length($tmp),2).$tmp; + + +$output=create_mhbd(104+length($main_sl.$main_pl)).$main_sl.$main_pl; + +# backup old iTunesDB +if(-e "$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB") { + my $t=time(); + copy("$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB","$rc->{BACKUPDIR}/iTunesDB_$t"); + gzip("$rc->{BACKUPDIR}/iTunesDB_$t"); +} + +open OUT,">".$rc->{IPODDIR}."/iPod_Control/iTunes/iTunesDB" or die "cannot write iTunesDB"; +print OUT $output; +close OUT; + +print STDERR "\niTunesDB created.\n"; +exit; +# END + + +# +# internal subroutines +# + +sub create_mhbd { + my ($size) = @_; + + my $r= "mhbd"; + $r.= pack "V",104; + $r.= pack "V",$size; + $r.= pack "V",1; + $r.= pack "V",1; + $r.= pack "V",2; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhlp { + my ($count) = @_; + + my $r= "mhlp"; + $r.= pack "V",92; + $r.= pack "V",$count; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_playlist { + my ($name,$anz) = @_; + + my $ipod_name=create_mhod($name,1); + + my $r= "mhyp"; + $r.= pack "V",108; + $r.= pack "V",108+648+length($ipod_name)+$anz*(76+44); + $r.= pack "V",2; + $r.= pack "V",$anz; + $r.= pack "V",0; + $r.= pack "V",3088620292; + $r.= pack "V",2317718671; + $r.= pack "V",3655876446; + for(1..18) { + $r.= pack "V",0; + } + + $r.= "mhod"; + $r.= pack "V",24; + $r.= pack "V",648; + $r.= pack "V",100; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",12714187; # ?? 12714187 + $r.= pack "V",26215000; + $r.= pack "V",0; + $r.= pack "V",65736; + $r.= pack "V",1; # ?? 1 + $r.= pack "V",6; # ?? 6 + $r.= pack "V",0; # ?? 0 + $r.= pack "V",2555905; # ?? 2555905 + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13107202; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",3276813; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192004; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192003; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",5242888; + for(1..107) { + $r.= pack "V",0; + } + $r.= pack "V",140; + for(1..19) { + $r.= pack "V",0; + } + + return $r.$ipod_name; +} + +sub create_playlist_main { + my ($name,$anz) = @_; + + my $ipod_name=create_mhod($name,1); + + my $r= "mhyp"; + $r.= pack "V",108; + $r.= pack "V",108+648+length($ipod_name)+$anz*(76+44); + $r.= pack "V",2; + $r.= pack "V",$anz; + $r.= pack "V",1; + $r.= pack "V",3087491191; + $r.= pack "V",837788566; + $r.= pack "V",62365; + for(1..18) { + $r.= pack "V",0; + } + + $r.= "mhod"; + $r.= pack "V",24; + $r.= pack "V",648; + $r.= pack "V",100; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13172927; # ?? 12714187 + $r.= pack "V",26215000; + $r.= pack "V",0; + $r.= pack "V",65736; + $r.= pack "V",5; # ?? 1 + $r.= pack "V",6; # ?? 6 + $r.= pack "V",3; # ?? 0 + $r.= pack "V",1179649; # ?? 2555905 + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13107202; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",3276813; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192004; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192003; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",5242888; + for(1..107) { + $r.= pack "V",0; + } + $r.= pack "V",140; + for(1..19) { + $r.= pack "V",0; + } + + return $r.$ipod_name; +} + +sub create_mhod_mhip { + my ($ref) = @_; + + my $r= "mhip"; + $r.= pack "V",76; + $r.= pack "V",76; + $r.= pack "V",1; + $r.= pack "V",0; + $r.= pack "V",$ref-1; + $r.= pack "V",$ref; + $r.= pack "V",3088619525; + for(1..11) { + $r.= pack "V",0; + } + + $r.="mhod"; + $r.= pack "V",24; + $r.= pack "V",44; + $r.= pack "V",100; + $r.= pack "V",0; + $r.= pack "V",0; + $r.= pack "V",$ref-1; + for(1..4) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhsd { + my ($size,$type) = @_; + + my $r="mhsd"; + $r.= pack "V",96; + $r.= pack "V",$size; + $r.= pack "V",$type; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhlt { + my ($count) = @_; + + my $r="mhlt"; + $r.= pack "V",92; + $r.= pack "V",$count; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhit { + my ($arttr_c,$attr_s,$index,$vbr,$date,$size,$dur,$order,$bitrate) = @_; + + my $r="mhit"; + $r.= pack "V",156; + $r.= pack "V",156+$attr_s; + $r.= pack "V",$arttr_c; + $r.= pack "V",$index; + $r.= pack "V",1; + $r.= pack "V",0; + my $type=256; + $type+=1 if($vbr); + $r.= pack "V",$type; + $r.= pack "V",$date+2082844800; + $r.= pack "V",$size; + $r.= pack "V",$dur; + $r.= pack "V",$order; + $r.= pack "V",0; + $r.= pack "V",0; + $r.= pack "V",$bitrate; + $r.= pack "V",2890137600; + for(1..23) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhod { + my ($string,$type) = @_; + my $len=length($string); + + my $r="mhod"; + $r.= pack "V",24; + $r.= pack "V",(40+2*$len); + $r.= pack "V",$type; + $r.= pack "V2",0; + $r.= pack "V",1; + $r.= pack "V",(2*$len); + $r.= pack "V2",0; + + my $u=latin1($string); + $u->byteswap; + $r.= $u->utf16; + + return $r; +} + +sub set_ipodname { + my ($dev,$backup,$name,$real,$cpu)=@_; + $dev.="/iPod_Control/iTunes/DeviceInfo"; + + my $file; + + for(1..384) { + $file.=pack "V",0; + } + + my $l=length($name); + substr($file,0,2)=pack "v",$l; + my $u=latin1($name); + $u->byteswap; + substr($file,2,$l*2)=$u->utf16; + + $l=length($real); + substr($file,512,2)=pack "v",$l; + $u=latin1($real); + $u->byteswap; + substr($file,514,$l*2)=$u->utf16; + + $l=length($cpu); + substr($file,1024,2)=pack "v",$l; + $u=latin1($cpu); + $u->byteswap; + substr($file,1026,$l*2)=$u->utf16; + + if(-e $dev) { + my $t=time(); + copy($dev,"$backup/DeviceInfo_$t"); + gzip("$backup/DeviceInfo_$t"); + } + open IPOD,">$dev" or die "cannot write DeviceInfo"; + print IPOD $file; + close IPOD; +} + +sub get_ipodname { + my $dev=shift; + $dev.="/iPod_Control/iTunes/DeviceInfo"; + my $file; + my $buff; + + open IPOD,$dev or return undef; + while (read(IPOD, $buff, 8 * 2**10)) { + $file.=$buff; + } + close IPOD; + + my $l=unpack "v",substr($file,0,2); + my $s=substr($file,2,$l*2); + my $u=utf16($s); + $u->byteswap; + my $name=$u->latin1; + + $l=unpack "v",substr($file,512,2); + $s=substr($file,514,$l*2); + $u=utf16($s); + $u->byteswap; + my $realname=$u->latin1; + + $l=unpack "v",substr($file,1024,2); + $s=substr($file,1026,$l*2); + $u=utf16($s); + $u->byteswap; + my $computername=$u->latin1; + + return ($name,$realname,$computername); +} + +sub hash { + my $string=shift; + my $key; + + my $len=length($string); + + for(my $j=$len-1 ; $j>1 ; $j--) { + $key+=ord(substr($string,$j,1)); + } + + return sprintf "%.2d",(substr($key,length($key)-2,2) % 20); +} + +sub readrc { + my $file = shift; + my $req = shift; + my $rc; + + my $sub; + + open IN,$file or die "cannot open rc file: $file"; + while() { + next if /^\s*$/; + next if /^\s*#/; + + if(/^\s*(\S+)\s*=\s*(.*?)\s*$/) { + my $k=$1; + my $n=$2; + ($n) = $n =~ /^\"(.*?)\"$/ if($n =~ /\"/); + unless($sub) { + $rc->{$k}=$n; + } else { + ($k) = $k =~ /^\"(.*?)\"$/ if($k =~ /\"/); + my @n=split /,/,$n; + for(@n) { + s/^\s+//g; + s/\s+$//g; + s/^\"//; + s/\"$//; + } + $rc->{$sub}->{$k}=\@n; + } + } elsif (/^\s*(\S+)\s*\{/) { + $sub=$1; + } elsif (/^\s*}/) { + $sub=undef; + } + } + + if($rc->{SYNCMODE} == 2) { + push @$req,"SYNCDIR"; + } + if($rc->{WRITEDEVICEINFO} == 1) { + push @$req,("IPODNAME","REALNAME","COMPUTERNAME"); + } + if($rc->{ALWAYSTEMPLATES} == 1) { + push @$req,"FILETEMPLATES"; + } + + for my $d (keys %$rc) { + if($d =~ /DIR$/) { + $rc->{$d} =~ s/\~/$ENV{HOME}/; + } + } + $rc->{SYNCLIST} =~ s/\~/$ENV{HOME}/ if $rc->{SYNCLIST}; + + for(@$req) { + die "RC PARAMETER: $_ not found" unless($rc->{$_}); + } + return $rc; +} diff --git a/cd-blank b/cd-blank new file mode 100755 index 0000000..8541a72 --- /dev/null +++ b/cd-blank @@ -0,0 +1,18 @@ +#!/bin/sh + +set -x + +echo +echo "Löschen einer CD-RW" +echo + +. /etc/dvd-scripts.env +if [ "$1" == "all" ] +then + echo "Die CD-RW wird gründlich gelöscht..." + cdrecord -v dev="$CD_DEVICE" -blank=all +else + echo "Die CD-RW wird schnell gelöscht..." + cdrecord -v dev="$CD_DEVICE" -blank=fast + +fi diff --git a/cd-burn-files b/cd-burn-files new file mode 100755 index 0000000..ad1eaa1 --- /dev/null +++ b/cd-burn-files @@ -0,0 +1,25 @@ +#!/bin/sh + +set -x + +echo +echo "Brennen eins Verzeichnisses" +echo + +. /etc/dvd-scripts.env + +CD_IMAGE=$CD_IMAGE_TEMP +DATA_DIR=$1 + +label=`date '+%Y-%m-%d'` + +echo "Das Image für das Verzeichnis $DATA_DIR wird erzeugt..." +mkisofs -D -J -L -r -v -V "$label" -o "$CD_IMAGE" "$DATA_DIR" + +if [ $? -eq 0 ] +then + cd-burn-image "$CD_IMAGE" + rm "$CD_IMAGE" +else + echo "Fehler beim erzeugen des Image." +fi diff --git a/cd-burn-image b/cd-burn-image new file mode 100755 index 0000000..71c597d --- /dev/null +++ b/cd-burn-image @@ -0,0 +1,25 @@ +#!/bin/sh + +#set -x + +echo +echo "Brennen eines CD-Images" +echo + +. /etc/dvd-scripts.env + +CD_IMAGE=$1 + +hdparm -u1 -d1 $CD_DEVICE_SCSI +if [ "$CD_IMAGE" == "" ] +then + echo "Usage: $0 image-file-to-burn" +elif [ -s "$CD_IMAGE" ] +then + echo "Das Image $CD_IMAGE wird gebrannt..." + cdrecord -v -eject dev="$CD_DEVICE_SCSI" -data "$CD_IMAGE" + +else + echo "Das Image $CD_IMAGE existiert nicht !" +fi +echo diff --git a/cd2mp3 b/cd2mp3 new file mode 100755 index 0000000..2e39700 --- /dev/null +++ b/cd2mp3 @@ -0,0 +1,97 @@ +#!/bin/bash +# +# /usr/local/bin/cdtomp3 -- CD rippen +# +#set -x + +[ -f ~/.cd2mp3.conf ] && . ~/.cd2mp3.conf + +[ -z $cdreader ] && cdreader="/dev/cdrom" +[ -z $bitrate ] && bitrate=192 +[ -z $cddbdata ] && cddbdata=/tmp/cdtomp3.cddb +[ -z $grabber ] && grabber='cdparanoia -q -w $(expr $i + 1) -d $cdreader -' +[ -z $destdir ] && destdir=/dat/mp3Neu +[ -z $prio ] && prio=10 +[ -z $SVDSVDRPSEND ] && SVDRPSEND=svdrpsend.pl +[ -z $LOGFILE ] && LOGFILE=/tmp/cd2mp3.log + +if test -f $LOGFILE; then + rm $LOGFILE +fi +if test -s $cddbdata; then + rm $cddbdata +fi + +#internetverbindung in de gänge bringen +#ping -c 2 www.heise.de +#sleep 15 + +cddb=$(echo $(disc-cover -t cddb -D $cdreader -o "$cddbdata") | awk -F'"' '{print $2}') +if test -s "$cddbdata"; then + subdir=$(grep "DTITLE" "$cddbdata" | awk -F= '{print $2}' | sed "s/ /_/g" | sed "s/[^[:alnum:]_-]//g") + echo "CDDB Eintrag gefunden: $subdir" + $SVDRPSEND MESG "CDDB Eintrag gefunden: $subdir" +else + subdir="UnbekannteCd" +fi + +if ! test -d "$destdir/$subdir"; then + mkdir $destdir/$subdir +fi +cd $destdir/$subdir + +if ! test -a fifo; then + mkfifo fifo +fi +## Jetzt geht's los, maximal 100 Titel auf einer CD + +for(( i=0; i<=99; i++)) +do + ## Erst den Dateinamen des Tracks ermitteln + if test -s "$cddbdata"; then + trackname=$(grep "TITLE$(echo $(expr $i + 0))=" $cddbdata | awk -F= '{print $2}' | sed "s/ /_/g" | sed "s/[^[:alnum:]_-]//g") + if ! test "$trackname"; then + trackname="track" + fi + else + trackname="track" + fi + ## Index hinzu; moegliche Namensgleichheiten beseitigen + let "i2 = $i + 1" + if [ $i2 -le 9 ] ; then + index=0$i2 + else + index=$i2 + fi + trackname=$index"-$trackname" + echo $trackname + + ## Get names for ID-Tags ################# + titlename=$(grep "TITLE$(echo $(expr $i + 0))=" $cddbdata | awk -F= '{print $2}') + year=$(grep "DYEAR=" $cddbdata | awk -F= '{print $2}') + disktitle=$(grep "DTITLE=" $cddbdata | awk -F[=/] '{print $3}' | sed "s/^ *//") + diskartist=$(grep "DTITLE=" $cddbdata | awk -F[=/] '{print $2}') + #echo Jahr:$year + #echo Titel:$titlename + #echo Album:$disktitle + #echo Interpret:$diskartist + $SVDRPSEND MESG "'$trackname' wird gerippt" + ## Grabber und Kodierer anwerfen ############ + # Codieren beginnt sobald das erste Byte eintrifft ... + nice -n $prio lame --quiet --tt "$titlename" --ta "$diskartist" --tl "$disktitle" --ty "$year" --tn "$i2" --disptime 2 -b $bitrate -m s -h fifo "$trackname".mp3 > $LOGFILE & + eval "nice -n $prio $grabber" > fifo + + # das ist der Fall, wenn der angegebene Track existiert ... + if test "$?" -ne 0; then + sleep 5 + # Fehlercode des Grabbers -> reale Trackzahl ueberschritten + # oder Fehler des CD Laufwerks + #echo "FEHLER" + #echo "$trackname".mp3 + rm "$trackname".mp3 + break + fi +done +rm fifo +$SVDRPSEND MESG "Rippen fertig" +echo "Fertig !" \ No newline at end of file diff --git a/cda2hd b/cda2hd new file mode 100755 index 0000000..7db21e4 --- /dev/null +++ b/cda2hd @@ -0,0 +1,24 @@ +#!/bin/sh +# +# +set -x + +#scsidev="0,0,0" +cdreader="/dev/cdrom" +destdir=/dat/tmp/audio +driver=generic-mmc +logfile=/tmp/cda2hd.log +nicelevel=15 + +[ -d $destdir ] || mkdir -p $destdir +cd $destdir + + +# Datei cd.toc erzeugen +[ -f cd.toc ] && rm cd.toc +nice -n $nicelevel cdrdao read-toc --with-cddb --datafile data.raw --device $cdreader --driver $driver cd.toc > $logfile +# Grabben (cdparanoia hat eine bessere Kratzererkennung) +[ -f data.raw ] && rm data.raw +nice -n $nicelevel cdparanoia -v 1- -p data.raw -d $cdreader > $logfile +#cdrdao write --eject --speed $speed --device $scsidev --driver $driver cd.toc +eject $cdreader diff --git a/convnow.sh b/convnow.sh new file mode 100755 index 0000000..963ab89 --- /dev/null +++ b/convnow.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +log=/tmp/convnow.log +#echo 0:$0 >> $log +#echo 1:$1 >> $log +#echo 2:$2 >> $log + +viddir=\\/var\\/lib\\/video.00\\/ +recdir=$2 + +recpath=$(echo $recdir | sed "s/$viddir//g") +#echo recpath: $recpath >> $log +#echo "2" >> $log + +function cmd2nas { + local cmd=$1 + local nasaddr=nas@nas + local naskey=nas + + echo ssh -i ~/.ssh/$naskey $nasaddr "$cmd" >> $log + ssh -i ~/.ssh/$naskey $nasaddr "$cmd" +} + +#echo recpath2: $recpath >> $log + +for par in "$@"; do + #echo "xxx:$par" >> $log + case $par in + vdr2mp3) + #echo "vdr2mp3" >> $log + cmd2nas "nohup ruby ~/bin/vdr2mp3.rb '$recpath' >/tmp/test.log 2>&1 & " + + ;; + *) + ;; + esac +done + +#1:vdr2mp3dd +#2:/var/lib/video.00/%Dok_5_-_Das_Feature/2012-08-05.11.00.124-0.rec +exit + + +ssh -i /home/marc/.ssh/nas nas@nas "nohup ruby ~/bin/vdr2mp3.rb '%Dok_5_-_Das_Feature/2012-08-05.11.00.124-0.rec' > /tmp/test.log 2>&1 &" + +set -x + +. /etc/vdr/vdrconvert.env + +if [ ! -z "$SERVER" ] +then + ssh $SERVER $0 $1 "'$2'" +else + printf "%s\n" "$2" >> $VCOQUEUEDIR/$1 +fi + diff --git a/cp_packages.sh b/cp_packages.sh new file mode 100644 index 0000000..372d64a --- /dev/null +++ b/cp_packages.sh @@ -0,0 +1,28 @@ + +#scripts/feeds update +#make + +cd ../ipk/ar71xx + + +#cp ../../base/bin/ar71xx/packages/fhem-enocean_eo_ar71xx.ipk . +#cp ../../base/bin/ar71xx/packages/fhem-trunk_trunk_ar71xx.ipk . +#cp ../../base/bin/ar71xx/packages/fhem-trunk_trunk_ar71xx.ipk . +cp ../../base/bin/ar71xx/packages/fhem*.ipk . + +#perl-device-serialport_1.04-2_ar71xx.ipk +cp ../../base/bin/ar71xx/packages/perl-device-serialport_*.ipk . +#perl-weather_0.5.5-1_ar71xx.ipk +cp ../../base/bin/ar71xx/packages/perl-weather_*.ipk . +cp ../../base/bin/ar71xx/packages/eibd*.ipk . +cp ../../base/bin/ar71xx/packages/linknx*.ipk . + +cp ../../base/bin/ar71xx/*.bin /home/marc/Dropbox-ipad/Public/ +cp ../../base/bin/ar71xx/md5sums /home/marc/Dropbox-ipad/Public/ + + +../../base/scripts/ipkg-make-index.sh . > Packages ; gzip -c Packages > Packages.gz +cp *.ipk /home/marc/Dropbox-ipad/Public/ipk/ar71xx/ +cp Packages.gz /home/marc/Dropbox-ipad/Public/ipk/ar71xx/ + +cd - diff --git a/create_omtb_garmin_img.sh b/create_omtb_garmin_img.sh new file mode 100755 index 0000000..70ca0c7 --- /dev/null +++ b/create_omtb_garmin_img.sh @@ -0,0 +1,140 @@ +#!/bin/zsh +# License: Creative Commons Share Alive 3.0 +# Copyright: 2012, Bernhard Tittelbach +# Thanks to malenki on #osm-de@oftc.net for constructive input and nagging me into making this thing useable in the first place + +# Required software: +# - zsh (obviously) +# - 7z +# - mkgmap (preferred) [http://www.mkgmap.org.uk/snapshots/] OR wine +# - gmt linux version [ http://www.anpo.republika.pl/download.html ] OR wine +# + +setopt extendedglob +setopt cshnullglob +SCRIPT_NAME=${0:t} +usage() +{ + print "\nUsage: $SCRIPT_NAME [options] " > /dev/stderr + print " as TYP-style you can choose:" > /dev/stderr + print " clas: classic layout - optimized for Vista/Legend series" > /dev/stderr + print " thin: thinner tracks and pathes - optimized for Gpsmap60/76 series" > /dev/stderr + print " wide: high contrast layout, like classic but with white forest - optimized for Oregon/Colorado dull displays" > /dev/stderr + print " hike: like classic layout - but optimized for hiking (does not show mtb/bicycle informations)" > /dev/stderr + print " easy: similar to classic layout - but focussed on easy readability hence not showing mtb/bicycle information except routes" > /dev/stderr + print " velo: (comes with velomap files) Layout optimized for small GPS screen" > /dev/stderr + print " or give the path to your own .TYP style file" > /dev/stderr + print "\nOptions:" > /dev/stderr + print " -m " > /dev/stderr + print " -o \n" > /dev/stderr + exit 1 + # descriptions taken from openmtbmap.org batch files +} + +zparseopts -A ARGS_A -D -E -- "m:" "o:" +OMTB_EXE="$1" +TYPFILE="$2" +GMT_CMD==gmt +MKGMAP=( ${ARGS_A[-m]}(.N,@-.) /usr/share/mkgmap/mkgmap.jar(.N,@-.) /usr/local/share/mkgmap/mkgmap.jar(.N,@-.) ${^path}/mkgmap.jar(.N,@-.) ) +MKGMAP="${MKGMAP[1]}" + +if ! [[ -x $GMT_CMD ]] ; then + if ! [[ -x =wine ]] ; then + print "ERROR: You need to either install wine or the gmt linux binary !" > /dev/stderr + exit 3 + fi + # use supplied gmt.exe with wine + GMT_CMD="wine ./gmt.exe" +fi + +if ! [[ -x =7z ]]; then + print "\nERROR: 7z is not installed, but needed to extract openmtbmap downloads !" + exit 3 +fi + +[[ -z $TYPFILE || ! -f $OMTB_EXE ]] && usage + +if [[ ${OMTB_EXE:t} == mtb* ]]; then + OMTBORVELO=openmtbmap + OMTB_NAME="${OMTB_EXE:t:r:s/mtb/}" +elif [[ ${OMTB_EXE:t} == velo* ]]; then + OMTBORVELO=openvelomap + OMTB_NAME="${OMTB_EXE:t:r:s/velo/}" +else + print "\nERROR: not a openmtbmap.org or openvelomap.org file ?" + usage +fi +DESC="${OMTBORVELO}_${OMTB_NAME}" +if [[ -d ${ARGS_A[-o]} ]]; then + DSTFILENAME="${ARGS_A[-o]:A}/${DESC}.img" + TMPDIR=${ARGS_A[-o]:A}/OMTB_tmp +else + DSTFILENAME="${OMTB_EXE:A:h}/${DESC}.img" + TMPDIR=${OMTB_EXE:A:h}/OMTB_tmp + [[ -n $ARGS_A[-o] ]] && {print "\nWarning: -o given but ${ARGS_A[-o]} is not a directory.\n Using ${OMTB_EXE:A:h} instead..\n"} +fi + +if [[ -e $DSTFILENAME ]]; then + print "\nWarning: the script will create (overwrite) $DSTFILENAME" + print " but $DSTFILENAME already exists." + read -q "?Continue and overwrite ? [y/N] " || exit 0 + print "" +fi + +if [[ -e $TMPDIR ]] ; then + print "\nWarning: the script want's to create directory $TMPDIR, but it already exists." + if [[ -d $TMPDIR ]] ; then + print " If you press [y], $OMTB_EXE will be extracted" + print " to $TMPDIR regardless of it's contents." + print " That's fine if it was created during a previous abortet run of this script." + print " Otherwise you should say [n] and move $OMTB_EXE into a clean directory." + read -q "?Continue ? [y/N] " || exit 0 + print "" + else + print " Please use another output directory and try again." + exit 1 + fi +else + mkdir $TMPDIR || exit 1 +fi + +FIMG_a=(${TMPDIR}/6<000-999>0000.img(N)) +if [[ -z $FIMG_a ]] ; then + print "Extracting $OMTB_EXE ..." + 7z x -y -o$TMPDIR ${OMTB_EXE} &>/dev/null || exit 1 + FIMG_a=(${TMPDIR}/6<000-999>0000.img(N[1])) + [[ -z $FIMG_a ]] && {print "\nERROR, could not find 6*.img file after extracting $OMTB_EXE" >/dev/stderr ; exit 1} +fi +if [[ -f $TYPFILE ]] ; then + TYPFILE="${TYPFILE:A}" +else + TYPFILE=( "${TMPDIR}/"(#i)${TYPFILE}*.typ(.N:A)) + TYPFILE="${TYPFILE[1]}" +fi + +trap "cd '$PWD'" EXIT +cd $TMPDIR || exit 5 + +if [[ -z $TYPFILE ]] ; then + print "\nERROR: TYP-file or -style not found" > /dev/stderr + print " please choose your own file or one of these styles: " *.(#l)TYP(.N:r) > /dev/stderr + exit 2 +fi + +print "using display-TYP-file: $TYPFILE" +cp $TYPFILE 01002468.TYP || exit 4 +FID=${${FIMG_a:t}[1][1,4]} +print using FID $FID + +$GMT_CMD -wy $FID 01002468.TYP +if [[ -n $MKGMAP ]]; then + print "using mkgmap, building address search index..." + #java -Xmx1000M -jar mkgmap.jar --family-id=$FID --index --description="$DESC" --series-name="$DESC" --family-name="$DESC" --show-profiles=1 --product-id=1 --gmapsupp 6*.img 7*.img 01002468.TYP + java -Xmx3000M -jar "$MKGMAP" --family-id=$FID --index --description="$DESC" --series-name="$DESC" --family-name="$DESC" --show-profiles=1 --product-id=1 --gmapsupp [67]*.img 01002468.TYP || exit 7 + mv (#i)gmapsupp.img "${DSTFILENAME}" || exit 7 +else + print "mkgmap not found, using gmt..." + $GMT_CMD -j -o "${DSTFILENAME}" -f $FID -m "$DESC" 6*.img 7*.img 01002468.TYP || exit 7 +fi +rm -R "$TMPDIR" +print "\nSuccessfully created ${DSTFILENAME}" diff --git a/create_opkg_index.sh b/create_opkg_index.sh new file mode 100644 index 0000000..f3efea6 --- /dev/null +++ b/create_opkg_index.sh @@ -0,0 +1 @@ +../../base/scripts/ipkg-make-index.sh . > Packages ; gzip -c Packages > Packages.gz diff --git a/createhdextlinks.sh b/createhdextlinks.sh new file mode 100644 index 0000000..4e3e8fb --- /dev/null +++ b/createhdextlinks.sh @@ -0,0 +1,9 @@ + + +#dirs=$(find .. -maxdepth 1 -type d ! -name "*.rec" -exec find {} -maxdepth 1 -name "*.rec" \;) +dirs=$(find .. -maxdepth 1 -type d -name "*.rec") +for i in $dirs; do + ln -s $i + echo $i +done + \ No newline at end of file diff --git a/createhdextlinks.sh~ b/createhdextlinks.sh~ new file mode 100644 index 0000000..a4d571f --- /dev/null +++ b/createhdextlinks.sh~ @@ -0,0 +1,7 @@ + + +dirs=§(find .. -type d -maxdepth 1 ! -name "*.rec" -exec find {} -maxdepth 1 -name "*.rec"} +for i in $dirs do + echo $i +done + \ No newline at end of file diff --git a/dropbox.py b/dropbox.py new file mode 100755 index 0000000..bd4ead5 --- /dev/null +++ b/dropbox.py @@ -0,0 +1,821 @@ +#!/usr/bin/python +# +# Copyright 2008 Evenflow, Inc. +# +# dropbox.py +# Dropbox frontend script +# +# dropbox.py is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# dropbox.py is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with dropbox.py. If not, see . +# + +from __future__ import with_statement + +import sys +import optparse +import socket +import os +import time +import platform +import tarfile +import threading +import urllib +import subprocess +import fcntl +import errno +import locale +from contextlib import closing + +INFO = u"Dropbox is the easiest way to share and store your files online. Want to learn more? Head to" +LINK = u"http://www.getdropbox.com/" +WARNING = u"In order to use Dropbox, you must download the proprietary daemon." + +DOWNLOADING = u"Downloading Dropbox... %d%%" +UNPACKING = u"Unpacking Dropbox... %d%%" + +PARENT_DIR = os.path.expanduser("~") +DROPBOXD_PATH = "%s/.dropbox-dist/dropboxd" % PARENT_DIR + +enc = locale.getpreferredencoding() +def console_print(st=u"", f=sys.stdout, linebreak=True): + global enc + assert type(st) is unicode + f.write(st.encode(enc)) + if linebreak: f.write(os.linesep) + +def console_flush(f=sys.stdout): + f.flush() + +def yes_no_question(question): + while True: + console_print(question, linebreak=False) + console_print(u" [y/n] ", linebreak=False) + console_flush() + text = raw_input() + if text.lower().startswith("y"): + return True + elif text.lower().startswith("n"): + return False + else: + console_print(u"Sorry, I didn't understand that. Please type yes or no.") + +def plat(): + if sys.platform.lower().startswith('linux'): + arch = platform.machine() + if (arch[0] == 'i' and + arch[1].isdigit() and + arch[2:4] == '86'): + plat = "x86" + elif arch == 'x86_64': + plat = arch + else: + FatalVisibleError("Platform not supported") + return "lnx.%s" % plat + else: + FatalVisibleError("Platform not supported") + +def is_dropbox_running(): + pidfile = os.path.expanduser("~/.dropbox/dropbox.pid") + + try: + with open(pidfile, "r") as f: + pid = int(f.read()) + with open("/proc/%d/cmdline" % pid, "r") as f: + cmdline = f.read().lower() + except: + cmdline = "" + + return "dropbox" in cmdline + +def unicode_abspath(path): + global enc + assert type(path) is unicode + # shouldn't pass unicode to this craphead, it appends with os.getcwd() which is always a str + return os.path.abspath(path.encode(sys.getfilesystemencoding())).decode(sys.getfilesystemencoding()) + +# This sets a custom User-Agent +class DropboxURLopener(urllib.FancyURLopener): + version = "DropboxLinuxDownloader/0.6.1" +urllib._urlopener = DropboxURLopener() + +class DownloadState(object): + def __init__(self): + try: + self.file = urllib.urlopen("http://www.getdropbox.com/download?plat=%s" % plat()) + except IOError: + FatalVisibleError("Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable.") + + fcntl.fcntl(self.file, fcntl.F_SETFL, os.O_NONBLOCK) + + self.size = int(self.file.info()['content-length']) + self.progress = 0 + + self.local_path = "%s/dropbox.tar.gz" % PARENT_DIR + self.local_file = open(self.local_path, 'wb') + + def copy_data(self): + while True: + try: + chunk = os.read(self.file.fileno(), 4096) + self.progress += len(chunk) + self.local_file.write(chunk) + yield True + if self.progress == self.size: + break + except OSError, e: + if hasattr(e, 'errno') and e.errno == errno.EAGAIN: + # nothing left to read + yield False + else: + raise + + self.file.close() + + def unpack(self): + self.local_file.close() + archive = tarfile.open(self.local_path, 'r:gz') + total_members = len(archive.getmembers()) + for i, member in enumerate(archive.getmembers()): + archive.extract(member, PARENT_DIR) + yield member.name, i, total_members + archive.close() + os.remove(self.local_path) + + def cancel(self): + if not self.local_file.closed: + self.local_file.close() + if os.path.exists(self.local_path): + os.remove(self.local_path) + +def load_serialized_images(): + global box_logo_pixbuf, window_icon + import gtk + box_logo_pixbuf = gtk.gdk.pixbuf_new_from_data('\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x08\x00\\\x9ef\x00\\\x9ej\x00\\\x9e\x04\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eZ\x00[\x9er\x00\\\x9e\x14\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e8\x00Y\x9c\xc2\x00X\x9b\xff\x00X\x9b\xff\x00[\x9d\xaa\x00\\\x9e\r\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x02\x00\\\x9e\x8e\x00Y\x9b\xff\x00Y\x9b\xff\x00Y\x9b\xd5\x00\\\x9eM\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x12\x00[\x9d\x8b\x00U\x99\xfa\x0fe\xa5\xff]\xa2\xd3\xffM\x95\xc9\xff\x00X\x9b\xff\x00Y\x9c\xc9\x00\\\x9e\x1e\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0f\x00[\x9d\xb1\x00V\x99\xff4\x85\xc1\xffZ\xa3\xda\xff\x17m\xab\xff\x00V\x99\xff\x00Z\x9d\xa2\x00\\\x9e \x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\\\x00W\x9a\xde\x00Y\x9c\xff:\x87\xbf\xff\x83\xbf\xeb\xff\x98\xce\xf6\xff\x9b\xd0\xf6\xffa\xa3\xd3\xff\x05]\x9e\xff\x00X\x9b\xda\x00\\\x9e/\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x1c\x00Z\x9c\xc5\x01Y\x9b\xff?\x90\xca\xff|\xc1\xf4\xff\x82\xc4\xf6\xff}\xbf\xf0\xffD\x90\xc8\xff\x05]\x9e\xff\x00V\x9a\xed\x00\\\x9es\x00\\\x9e\x07\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e4\x00Z\x9c\xba\x00V\x99\xff\x1dq\xae\xffd\xaa\xdd\xff\x8e\xc9\xf5\xff\x8e\xc7\xf3\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\xa1\xd2\xf6\xffw\xb3\xde\xff\x0fd\xa3\xff\x00V\x9a\xed\x00\\\x9eL\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e4\x00X\x9b\xdd\x05^\x9f\xffM\x9d\xd6\xffy\xc1\xf6\xffw\xbe\xf2\xffz\xbe\xf1\xff\x80\xc1\xf2\xff\x89\xc8\xf6\xffq\xb3\xe3\xff*z\xb5\xff\x00W\x9a\xff\x00X\x9b\xcd\x00\\\x9eG\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0e\x00[\x9d\x86\x00V\x99\xfa\x0cc\xa4\xffK\x96\xce\xff\x81\xc2\xf2\xff\x89\xc7\xf5\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\xa4\xd3\xf6\xff\x85\xbb\xe4\xff\x18k\xa8\xff\x00U\x99\xfc\x00\\\x9en\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eS\x00W\x9a\xf1\x0bb\xa3\xffT\xa3\xdd\xffv\xc0\xf7\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x8a\xc7\xf4\xff\x8f\xc9\xf4\xff`\xa3\xd5\xff\x15i\xa8\xff\x00U\x98\xff\x00[\x9d\x9c\x00\\\x9e\x1a\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eU\x00X\x9b\xd9\x00Z\x9c\xff1\x83\xbf\xffp\xb6\xea\xff\x84\xc5\xf6\xff\x80\xc2\xf2\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\xa6\xd3\xf5\xff\x96\xc7\xeb\xff*y\xb2\xff\x00T\x98\xff\x00\\\x9e\x90\x00\\\x9e\x02\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eu\x00V\x99\xfe\x14k\xac\xff\\\xac\xe6\xffr\xbd\xf6\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8b\xc5\xf1\xff\x95\xcc\xf6\xff\x8c\xc5\xee\xffH\x90\xc5\xff\x04]\x9e\xff\x00V\x9a\xe7\x00\\\x9ej\x00\\\x9e\x03\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e.\x00Z\x9c\xb3\x00V\x99\xff\x17m\xad\xffV\xa3\xdc\xff{\xc2\xf6\xff|\xbf\xf3\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa6\xd3\xf4\xff\xa4\xd1\xf1\xff@\x88\xbd\xff\x00U\x99\xff\x00[\x9d\xb0\x00\\\x9e\x0c\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x02\x00[\x9d\x97\x00V\x98\xff\x1fv\xb6\xffa\xb1\xed\xffl\xbb\xf4\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x93\xcb\xf2\xff\x9e\xd1\xf6\xff|\xb7\xe1\xff(w\xb2\xff\x00U\x99\xff\x00Y\x9c\xc6\x00\\\x9e?\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0b\x00[\x9e\x86\x00V\x99\xf6\ta\xa2\xff=\x8f\xcc\xffm\xb9\xf1\xffu\xbf\xf5\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa8\xd3\xf3\xff\xae\xd8\xf4\xffX\x99\xc9\xff\x00X\x9b\xff\x00Y\x9c\xc2\x00\\\x9e\x1b\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\r\x00[\x9d\xab\x00W\x99\xff,\x82\xc1\xffe\xb5\xf2\xffh\xb7\xf3\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x9f\xd1\xf5\xff\xa0\xcf\xf3\xffe\xa3\xd1\xff\x12f\xa5\xff\x00U\x98\xff\x00[\x9d\x9b\x00\\\x9e\x16\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eN\x00Y\x9b\xd3\x00Y\x9c\xff\'}\xbc\xff]\xad\xe8\xffp\xbe\xf6\xffn\xba\xf2\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa9\xd4\xf2\xff\xb5\xdb\xf6\xffq\xaa\xd4\xff\x04[\x9e\xff\x00X\x9b\xdc\x00\\\x9e>\x00\\\x9e0\x00Z\x9c\xc9\x00Z\x9b\xff8\x8d\xcd\xffe\xb7\xf5\xffc\xb4\xf2\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9d\xce\xf2\xff\xa9\xd5\xf6\xff\x99\xc9\xec\xffI\x8e\xc1\xff\x03[\x9d\xff\x00V\x9a\xe1\x00\\\x9ea\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e(\x00[\x9d\xab\x00V\x98\xff\x13j\xab\xffK\x9e\xdc\xffi\xb9\xf6\xffj\xb8\xf3\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa7\xd3\xf1\xff\xaa\xd4\xf1\xff\xb9\xdc\xf6\xff\x80\xb5\xda\xff\rb\xa2\xff\x00W\x9a\xff\x00Y\x9b\xfe\x04]\x9f\xff>\x94\xd4\xffd\xb6\xf6\xff`\xb3\xf1\xffb\xb3\xf1\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa6\xd2\xf3\xff\xb0\xd9\xf6\xff\x87\xbb\xe0\xff\'u\xaf\xff\x00T\x98\xff\x00Y\x9c\xbd\x00\\\x9e7\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x08\x00\\\x9e~\x00W\x99\xf2\x05^\x9f\xff3\x89\xc9\xff^\xb1\xf0\xffe\xb7\xf5\xffd\xb4\xf1\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa7\xd3\xf1\xff\xaa\xd4\xf1\xff\xad\xd4\xf1\xff\xbb\xdd\xf6\xff\x96\xc3\xe4\xff\x18i\xa7\xff\x01]\xa2\xffH\x9e\xde\xffa\xb6\xf6\xff^\xb1\xf1\xff`\xb3\xf1\xffb\xb3\xf1\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xb0\xd8\xf5\xff\xad\xd5\xf1\xfff\xa2\xce\xff\rb\xa2\xff\x00U\x99\xfb\x00\\\x9e\x92\x00\\\x9e\x11\x00\\\x9e\x9b\x02\\\x9e\xff\x1ct\xb5\xffM\xa3\xe3\xffb\xb7\xf6\xff`\xb3\xf2\xffa\xb3\xf1\xffd\xb4\xf1\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa7\xd3\xf1\xff\xaa\xd4\xf1\xff\xad\xd4\xf1\xff\xae\xd5\xf1\xff\xb7\xdb\xf4\xff\xaa\xcf\xe8\xffm\xb3\xe6\xffX\xb2\xf4\xffX\xae\xf1\xff^\xb1\xf1\xff`\xb3\xf1\xffb\xb3\xf1\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xae\xd5\xf2\xff\xba\xdd\xf7\xff\x9b\xc7\xe6\xff<\x83\xb8\xff\x06^\x9f\xff\x00[\x9d\xb6\x00Z\x9c\xdd\x0cd\xa6\xffR\xa9\xe9\xffb\xb7\xf8\xff\\\xb1\xf1\xff_\xb2\xf1\xffa\xb3\xf1\xffd\xb4\xf1\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa7\xd3\xf1\xff\xaa\xd4\xf1\xff\xaa\xd2\xf0\xff\xb2\xd7\xf1\xff\xce\xe5\xf6\xff\xe9\xf5\xfd\xff\xd0\xeb\xfe\xff\xa1\xd2\xf7\xffg\xb6\xf2\xffW\xad\xf0\xff_\xb2\xf1\xffb\xb3\xf1\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xac\xd4\xf1\xff\xae\xd4\xf1\xff\xbf\xe0\xf7\xff\xac\xd2\xee\xff\x1eo\xaa\xff\x00X\x9b\xeb\x00\\\x9eR\x00Y\x9b\xf6\x0ce\xa6\xffH\x9e\xde\xffb\xb6\xf6\xff_\xb2\xf1\xffa\xb3\xf1\xffd\xb4\xf1\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa1\xcf\xf1\xff\xa5\xd1\xf1\xff\xa5\xd2\xf1\xff\xa8\xd2\xf0\xff\xbe\xdd\xf4\xff\xdd\xee\xfa\xff\xe9\xf3\xfc\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xce\xe8\xfb\xff\xc3\xe2\xfa\xff\x89\xc6\xf5\xff]\xb1\xf1\xff]\xb1\xf0\xffe\xb5\xf1\xffh\xb7\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xac\xd4\xf1\xff\xba\xdd\xf6\xff\x93\xc1\xe3\xff\x1fo\xaa\xff\x00W\x9b\xff\x00\\\x9eo\x00\\\x9e\x00\x00\\\x9e;\x00Y\x9b\xdf\x03\\\x9e\xff;\x90\xd0\xffd\xb6\xf5\xffb\xb4\xf2\xffd\xb4\xf1\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9e\xcd\xf1\xff\xa0\xcf\xf1\xff\xa1\xcf\xf0\xff\xae\xd6\xf2\xff\xcf\xe6\xf8\xff\xe4\xf2\xfb\xff\xe5\xf2\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xcb\xe7\xfb\xff\xd1\xe9\xfb\xff\xb3\xda\xf9\xffx\xbe\xf3\xff^\xb1\xf0\xfff\xb6\xf1\xffl\xb8\xf1\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xaa\xd4\xf2\xff\xb7\xdb\xf6\xffx\xaf\xd6\xff\x0b`\xa1\xff\x00V\x9a\xed\x00\\\x9eR\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x1c\x00Z\x9c\xbe\x00X\x99\xff-\x83\xc2\xffe\xb6\xf3\xfff\xb6\xf3\xffg\xb6\xf1\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x97\xcb\xf1\xff\x9b\xcc\xf1\xff\x9b\xcc\xf0\xff\xa1\xcf\xf1\xff\xbf\xde\xf6\xff\xdc\xee\xfa\xff\xe3\xf1\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xd2\xe8\xfb\xff\xd0\xe9\xfb\xff\xa2\xd2\xf7\xffm\xb9\xf1\xffe\xb5\xf0\xffo\xba\xf1\xffr\xbb\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa9\xd4\xf2\xff\xb1\xd9\xf5\xff[\x9b\xc9\xff\x00X\x9b\xff\x00Y\x9c\xd3\x00\\\x9e-\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x06\x00[\x9d\x96\x00V\x99\xff"x\xb8\xffa\xb1\xee\xffk\xba\xf4\xffj\xb8\xf1\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x92\xc9\xf1\xff\x96\xca\xf1\xff\x97\xca\xf0\xff\xac\xd5\xf3\xff\xd0\xe7\xf9\xff\xe0\xef\xfb\xff\xdf\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xd0\xea\xfb\xff\xd8\xec\xfb\xff\xc8\xe5\xfa\xff\x8f\xc9\xf4\xffi\xb7\xf0\xffo\xb9\xf1\xffv\xbd\xf1\xffz\xbe\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa8\xd4\xf4\xff\xa6\xd2\xf1\xffE\x8c\xbf\xff\x00U\x99\xff\x00Z\x9d\xaf\x00\\\x9e\x12\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9en\x00V\x98\xfe\x14k\xac\xffY\xaa\xe5\xffp\xbd\xf6\xffm\xb9\xf1\xffp\xba\xf1\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x8b\xc5\xf1\xff\x8f\xc7\xf1\xff\x8e\xc7\xf0\xff\x9a\xcc\xf1\xff\xbd\xde\xf7\xff\xd8\xec\xfb\xff\xdc\xed\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd6\xec\xfb\xff\xda\xed\xfb\xff\xb6\xdc\xf8\xff\x80\xc1\xf2\xffo\xb9\xf0\xffy\xbd\xf1\xff~\xc0\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\xa7\xd4\xf5\xff\x95\xc7\xea\xff+y\xb2\xff\x00T\x98\xff\x00[\x9e\x88\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eQ\x00W\x9a\xee\x08a\xa2\xffL\x9d\xd8\xfft\xbf\xf6\xffq\xbb\xf2\xfft\xbc\xf1\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x83\xc2\xf1\xff\x87\xc4\xf1\xff\x88\xc4\xf1\xff\x8d\xc6\xf0\xff\xaa\xd5\xf4\xff\xcd\xe7\xfa\xff\xd8\xed\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xdd\xef\xfc\xff\xd7\xeb\xfb\xff\xa6\xd4\xf5\xff{\xbe\xf1\xffy\xbd\xf1\xff\x81\xc2\xf1\xff\x85\xc3\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\xa6\xd4\xf6\xff~\xb6\xdf\xff\x15h\xa7\xff\x00U\x99\xf9\x00\\\x9ek\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e-\x00Y\x9c\xd2\x01Y\x9c\xff<\x8e\xca\xffu\xbe\xf4\xffv\xbe\xf2\xffy\xbd\xf1\xff|\xbf\xf1\xff\x7f\xc1\xf1\xff\x82\xc1\xf1\xff\x83\xc1\xf0\xff\x97\xcb\xf3\xff\xbe\xe0\xf8\xff\xd4\xeb\xfb\xff\xd5\xeb\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xdc\xee\xfb\xff\xe3\xf0\xfc\xff\xcd\xe7\xf9\xff\x98\xcc\xf3\xff|\xbf\xf0\xff\x82\xc2\xf1\xff\x8a\xc5\xf1\xff\x8d\xc6\xf1\xff\x90\xc9\xf1\xff\x96\xcb\xf2\xff\xa1\xd2\xf5\xffc\xa3\xd2\xff\x06]\x9f\xff\x00W\x9b\xe5\x00\\\x9eC\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x12\x00[\x9d\xaf\x00V\x98\xff.\x81\xbe\xffv\xbd\xf2\xff|\xc0\xf4\xff|\xbf\xf1\xff{\xbf\xf0\xff\x83\xc2\xf1\xff\xaa\xd5\xf6\xff\xcc\xe6\xfb\xff\xd1\xea\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xed\xfb\xff\xdc\xed\xfb\xff\xe2\xf1\xfb\xff\xe3\xf2\xfb\xff\xbe\xdf\xf7\xff\x8b\xc6\xf1\xff\x84\xc2\xf0\xff\x8c\xc5\xf1\xff\x94\xcb\xf3\xff\x9b\xcf\xf4\xffK\x92\xc6\xff\x00W\x9a\xff\x00Y\x9c\xc7\x00\\\x9e#\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x8c\x00V\x98\xfd u\xb3\xffn\xb4\xe8\xff~\xc0\xf3\xff\x94\xca\xf4\xff\xbe\xe0\xf9\xff\xcf\xe8\xfb\xff\xcd\xe6\xfb\xff\xce\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xed\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe1\xf0\xfb\xff\xe8\xf3\xfb\xff\xdb\xed\xfa\xff\xac\xd5\xf4\xff\x8f\xc7\xf2\xff\x89\xc3\xed\xff6\x83\xbb\xff\x00U\x99\xff\x00[\x9d\xa9\x00\\\x9e\n\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x07\x00\\\x9e\xf1\x00Q\x95\xff\x18p\xb0\xff\x98\xcd\xf5\xff\xd4\xeb\xfd\xff\xce\xe8\xfb\xff\xcb\xe6\xfb\xff\xcc\xe6\xfb\xff\xce\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xed\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe6\xf3\xfb\xff\xf2\xf8\xfd\xff\xc9\xe5\xf9\xff1\x81\xba\xff\x00O\x94\xff\x00\\\x9e\xff\x00\\\x9e\'\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e}\x00V\x99\xfc\x1ap\xae\xffc\xad\xe4\xffM\xa8\xef\xff\x83\xc2\xf3\xff\xc6\xe4\xfb\xff\xd1\xe9\xfc\xff\xcc\xe6\xfb\xff\xce\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xed\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe7\xf4\xfc\xff\xe7\xf3\xfb\xff\xb6\xd8\xf4\xff{\xbc\xee\xff\x7f\xbd\xe9\xff/}\xb7\xff\x00U\x99\xff\x00[\x9d\x9d\x00\\\x9e\x06\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0b\x00[\x9d\xa2\x00U\x98\xff\'{\xb9\xffs\xbb\xef\xff{\xc0\xf4\xff@\xa1\xed\xff3\x99\xeb\xffW\xac\xee\xff\xa7\xd4\xf7\xff\xd3\xe9\xfc\xff\xd1\xeb\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xed\xfb\xff\xdc\xed\xfb\xff\xe0\xf0\xfb\xff\xea\xf5\xfc\xff\xcc\xe5\xf8\xff~\xbe\xee\xffX\xaa\xe9\xffc\xb0\xe9\xff\x92\xca\xf3\xff\x9a\xcd\xf3\xffC\x8d\xc2\xff\x00U\x99\xff\x00Z\x9c\xbd\x00\\\x9e\x1c\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e%\x00Z\x9c\xc9\x00X\x9b\xff6\x8a\xc6\xffs\xbd\xf3\xffw\xbe\xf3\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xff>\x9f\xeb\xffE\xa2\xeb\xff}\xbf\xf1\xff\xc3\xe3\xfa\xff\xd8\xed\xfc\xff\xd4\xeb\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xd7\xec\xfb\xff\xdb\xed\xfb\xff\xe4\xf1\xfc\xff\xda\xed\xfb\xff\x97\xca\xf2\xffV\xa9\xea\xffS\xa7\xe9\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x97\xcc\xf2\xff\xa1\xd1\xf5\xff\\\x9e\xcf\xff\x03[\x9d\xff\x00X\x9b\xdf\x00\\\x9e<\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eH\x00X\x9a\xe8\x06_\xa0\xffH\x99\xd5\xffs\xbf\xf6\xffq\xbb\xf2\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffH\xa4\xec\xffG\xa4\xeb\xff\\\xad\xed\xff\x9e\xcf\xf5\xff\xd4\xea\xfb\xff\xda\xee\xfc\xff\xd7\xec\xfb\xff\xda\xec\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd3\xea\xfb\xff\xd5\xeb\xfb\xff\xdd\xef\xfc\xff\xe1\xf0\xfc\xff\xac\xd5\xf5\xff\\\xad\xec\xffB\xa0\xe9\xffQ\xa7\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x9a\xcc\xf1\xff\xa6\xd4\xf6\xffy\xb2\xdd\xff\x11f\xa5\xff\x00V\x99\xf6\x00\\\x9ed\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9ef\x00V\x99\xfc\x11h\xa9\xffV\xa7\xe2\xffp\xbd\xf6\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffR\xa9\xec\xffS\xa9\xeb\xffx\xbb\xef\xff\xba\xdd\xf7\xff\xdd\xef\xfc\xff\xdc\xed\xfb\xff\xdc\xed\xfb\xff\xde\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd1\xe9\xfb\xff\xd5\xeb\xfb\xff\xdf\xf0\xfc\xff\xc1\xe1\xf9\xffk\xb5\xef\xff8\x9b\xe9\xff@\xa0\xe9\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\xa8\xd5\xf5\xff\x91\xc4\xe8\xff\'u\xb0\xff\x00T\x98\xff\x00\\\x9e\x83\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x04\x00[\x9d\x90\x00W\x98\xff\x1fv\xb6\xff_\xaf\xec\xffk\xba\xf5\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xff\\\xad\xeb\xffc\xb1\xeb\xff\x99\xcc\xf2\xff\xd4\xe9\xfa\xff\xe2\xf0\xfc\xff\xdf\xef\xfb\xff\xe0\xf0\xfb\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe4\xf2\xfb\xff\xca\xe7\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xcd\xe6\xfb\xff\xcf\xe9\xfb\xff\xd9\xed\xfc\xff\xd4\xea\xfb\xff\x87\xc4\xf3\xff6\x9b\xea\xff/\x98\xe9\xff>\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa9\xd4\xf4\xff\xa5\xd1\xf0\xffB\x89\xbd\xff\x00U\x99\xff\x00[\x9d\xab\x00\\\x9e\x10\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x19\x00Z\x9d\xb9\x00W\x99\xff*\x81\xc0\xffc\xb5\xf2\xfff\xb6\xf3\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xffe\xb2\xec\xfff\xb2\xeb\xff}\xbd\xed\xff\xb8\xda\xf5\xff\xe1\xf0\xfb\xff\xe4\xf2\xfc\xff\xe2\xf1\xfb\xff\xe3\xf1\xfb\xff\xe5\xf1\xfb\xff\xe3\xf2\xfb\xff\xc8\xe6\xfb\xff\xc8\xe5\xfb\xff\xc9\xe6\xfb\xff\xcb\xe6\xfb\xff\xd2\xe8\xfb\xff\xd8\xee\xfc\xff\xa5\xd2\xf7\xffG\xa2\xed\xff!\x90\xe9\xff0\x98\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa9\xd4\xf2\xff\xb0\xd9\xf5\xffX\x99\xc8\xff\x00W\x9b\xff\x00Y\x9c\xd1\x00\\\x9e,\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e9\x00Y\x9b\xdc\x03\\\x9d\xff9\x8f\xce\xffd\xb6\xf5\xffb\xb4\xf2\xffc\xb4\xf1\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xfff\xb2\xec\xffm\xb5\xec\xffp\xb7\xeb\xfft\xb7\xeb\xff\x97\xc9\xf0\xff\xcf\xe7\xf8\xff\xe7\xf4\xfc\xff\xe4\xf2\xfb\xff\xe3\xf0\xfb\xff\xe9\xf4\xfb\xff\xd6\xec\xfc\xff\xc5\xe3\xfb\xff\xca\xe6\xfb\xff\xd7\xec\xfc\xff\xbb\xdd\xf9\xff]\xaf\xf0\xff\x1b\x8d\xe9\xff\x1f\x8e\xe9\xff,\x96\xea\xff3\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xaa\xd4\xf2\xff\xb7\xdb\xf6\xffv\xae\xd6\xff\n`\xa0\xff\x00W\x9a\xed\x00\\\x9eQ\x00\\\x9e\x00\x00\\\x9eP\x00Y\x9b\xf5\x0cd\xa6\xffF\x9c\xdc\xffb\xb6\xf6\xff_\xb2\xf1\xffa\xb3\xf1\xffc\xb4\xf1\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xfff\xb2\xec\xffm\xb5\xec\xffs\xb8\xec\xffy\xba\xec\xffy\xba\xeb\xff\x83\xbf\xec\xff\xb0\xd6\xf2\xff\xe1\xf0\xfa\xff\xf5\xfa\xfe\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xf1\xf8\xfe\xff\xd2\xe9\xfb\xffz\xbd\xf4\xff \x90\xeb\xff\x10\x87\xe9\xff \x8e\xea\xff&\x92\xea\xff,\x96\xea\xff3\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xac\xd4\xf1\xff\xba\xdd\xf6\xff\x93\xc1\xe3\xff\x1eo\xaa\xff\x00X\x9b\xff\x00\\\x9ep\x00Z\x9c\xd6\x0bc\xa4\xffQ\xa7\xe7\xffb\xb8\xf9\xff\\\xb1\xf1\xff_\xb2\xf1\xffa\xb3\xf1\xffc\xb4\xf1\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xfff\xb2\xec\xffm\xb5\xec\xffs\xb8\xec\xffy\xba\xec\xff~\xbd\xec\xff\x82\xbe\xec\xff\x84\xbf\xeb\xff\xa1\xce\xef\xff\xdf\xee\xf9\xff\xff\xff\xff\xff\xff\xff\xff\xff\xce\xe7\xfb\xffJ\xa5\xee\xff\x08\x83\xe9\xff\x12\x89\xea\xff\x1b\x8d\xea\xff!\x8f\xea\xff&\x92\xea\xff,\x96\xea\xff3\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xac\xd4\xf1\xff\xae\xd5\xf1\xff\xbf\xe0\xf7\xff\xab\xd2\xed\xff\x1en\xaa\xff\x00X\x9b\xeb\x00[\x9d\x90\x02\\\x9e\xff\x1bs\xb4\xffM\xa2\xe2\xffb\xb7\xf6\xff`\xb3\xf2\xffa\xb3\xf1\xffc\xb4\xf1\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xfff\xb2\xec\xffm\xb5\xec\xffs\xb8\xec\xffy\xba\xec\xff\x7f\xbd\xec\xff\x89\xc1\xed\xff\x92\xc6\xed\xff\x93\xc7\xed\xff\x95\xc7\xec\xff\xc0\xde\xf3\xff\x7f\xbf\xf4\xff\x0f\x87\xe9\xff\r\x87\xe9\xff\x1c\x8e\xea\xff\x1d\x8e\xea\xff\x1d\x8e\xea\xff \x8f\xea\xff&\x92\xea\xff,\x96\xea\xff3\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xa9\xd3\xf1\xff\xad\xd5\xf2\xff\xba\xdd\xf6\xff\x9b\xc7\xe7\xff=\x84\xb9\xff\x05]\x9f\xff\x00[\x9d\xb1\x00\\\x9e\x03\x00\\\x9ey\x00X\x9a\xf3\x05^\x9f\xff6\x8c\xcc\xff`\xb3\xf2\xffe\xb7\xf5\xffc\xb4\xf1\xfff\xb6\xf1\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xfff\xb2\xec\xffm\xb5\xec\xffr\xb8\xec\xff|\xbb\xec\xff\x87\xc1\xed\xff\x8e\xc4\xed\xff\x92\xc6\xed\xff\x94\xc7\xed\xff\x9d\xcb\xed\xff\xb7\xd9\xf3\xffP\xaa\xf0\xff\x18\x8c\xea\xff\x13\x89\xea\xff\x1b\x8e\xea\xff \x90\xea\xff$\x92\xea\xff$\x91\xea\xff&\x92\xea\xff,\x96\xea\xff3\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa3\xd0\xf1\xff\xa6\xd2\xf1\xff\xaf\xd7\xf4\xff\xb1\xd8\xf4\xffn\xa8\xd2\xff\x0ec\xa2\xff\x00U\x99\xfd\x00\\\x9e\x91\x00\\\x9e\r\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e)\x00Z\x9c\xb2\x00V\x99\xff\x18o\xb0\xffR\xa4\xe2\xffj\xb9\xf6\xffg\xb7\xf2\xffi\xb8\xf1\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xff[\xad\xec\xffa\xb0\xec\xffe\xb2\xec\xffm\xb5\xec\xffz\xbb\xed\xff\x84\xc0\xed\xff\x89\xc2\xed\xff\x8d\xc4\xed\xff\x8f\xc4\xec\xff\x9c\xcc\xee\xff\xc5\xe1\xf5\xff\xca\xe4\xf7\xffi\xb7\xf2\xffS\xac\xf0\xff(\x94\xeb\xff\x16\x8b\xea\xff \x90\xea\xff$\x92\xea\xff*\x95\xea\xff,\x96\xea\xff-\x97\xea\xff2\x99\xea\xff9\x9d\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\x9f\xce\xf1\xff\xa5\xd1\xf2\xff\xb1\xd9\xf6\xff\x94\xc4\xe7\xff2}\xb5\xff\x00U\x99\xff\x00Y\x9c\xc6\x00\\\x9e;\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e[\x00X\x9a\xe1\x04]\x9e\xff3\x87\xc5\xffd\xb4\xef\xffo\xbd\xf5\xffl\xb9\xf1\xffp\xba\xf1\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffU\xaa\xec\xffZ\xad\xec\xff`\xaf\xec\xffj\xb5\xec\xffx\xba\xed\xff\x80\xbe\xed\xff\x83\xc0\xed\xff\x89\xc2\xed\xff\x8a\xc2\xec\xff\x9b\xcb\xef\xff\xc4\xe0\xf6\xff\xd0\xe7\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xff[\xb0\xf1\xff^\xb1\xf1\xff2\x9a\xec\xff\x1b\x8d\xea\xff#\x92\xea\xff)\x95\xea\xff/\x98\xea\xff4\x9a\xea\xff6\x9b\xea\xff9\x9c\xea\xff?\x9f\xea\xffF\xa3\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x99\xcc\xf1\xff\x9c\xcd\xf1\xff\xa6\xd3\xf5\xff\xa4\xd1\xf2\xff^\x9e\xcc\xff\x0b`\xa1\xff\x00V\x99\xef\x00\\\x9er\x00\\\x9e\x04\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x17\x00[\x9d\xa0\x00V\x98\xff\x12i\xaa\xffM\x9e\xd9\xffr\xbe\xf5\xffs\xbc\xf3\xffu\xbc\xf1\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffI\xa4\xec\xffO\xa8\xec\xffT\xa9\xec\xff\\\xad\xec\xffi\xb4\xed\xffs\xba\xed\xffy\xbb\xed\xff\x7f\xbe\xed\xff\x83\xc0\xed\xff\x85\xc0\xec\xff\x9e\xcd\xf0\xff\xc3\xe1\xf7\xff\xcb\xe4\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xffa\xb3\xf1\xfff\xb5\xf1\xffA\xa2\xed\xff \x90\xea\xff(\x94\xea\xff.\x98\xea\xff4\x9a\xea\xff;\x9d\xea\xff?\x9f\xea\xffA\xa0\xea\xffE\xa2\xea\xffL\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x95\xca\xf1\xff\x9c\xce\xf3\xff\xa5\xd4\xf6\xff~\xb6\xdf\xff%t\xaf\xff\x00U\x99\xff\x00Z\x9c\xb6\x00\\\x9e&\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eI\x00X\x9b\xd3\x00X\x9b\xff)}\xbb\xffg\xb2\xea\xff|\xc2\xf6\xffv\xbc\xf1\xffC\xa2\xed\xff<\x9e\xec\xffC\xa2\xec\xffH\xa4\xec\xffO\xa7\xec\xff[\xae\xec\xffh\xb3\xed\xffn\xb7\xed\xffs\xba\xed\xffy\xbb\xed\xff~\xbd\xed\xff\x80\xbf\xec\xff\xa1\xcf\xf1\xff\xc3\xe1\xf7\xff\xc6\xe3\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffe\xb5\xf1\xffm\xb9\xf1\xffQ\xaa\xee\xff)\x94\xea\xff,\x97\xea\xff4\x9a\xea\xff:\x9d\xea\xffA\xa0\xea\xffG\xa3\xea\xffJ\xa5\xea\xffM\xa5\xea\xffS\xa8\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xea\xff\x8d\xc7\xf1\xff\x9d\xd0\xf6\xff\x93\xc7\xed\xffF\x8d\xc2\xff\x02Z\x9d\xff\x00W\x9a\xe4\x00\\\x9e`\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\n\x00\\\x9e\x81\x00V\x99\xf6\x0cc\xa4\xffM\x9a\xd3\xffz\xbf\xf3\xffD\xa3\xee\xff;\x9e\xec\xffB\xa2\xec\xffM\xa6\xec\xff[\xae\xed\xffd\xb2\xed\xffh\xb4\xed\xffm\xb6\xed\xffs\xba\xed\xffw\xba\xed\xff~\xbd\xed\xff\xa5\xd2\xf3\xff\xc1\xe0\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffs\xbb\xf1\xffa\xb2\xef\xff3\x9a\xeb\xff0\x98\xea\xff:\x9d\xea\xffA\xa0\xea\xffG\xa3\xea\xffM\xa6\xea\xffR\xa8\xea\xffV\xa9\xea\xffZ\xab\xea\xff_\xad\xea\xffg\xb2\xeb\xff\x94\xcc\xf5\xffn\xad\xda\xff\x18k\xa9\xff\x00T\x98\xff\x00[\x9d\x9b\x00\\\x9e\x18\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e/\x00Y\x9c\xbd\x00W\x99\xff%z\xb7\xffB\xa0\xea\xff;\x9e\xec\xffK\xa6\xed\xffY\xad\xed\xff_\xaf\xed\xffc\xb2\xed\xffh\xb4\xed\xffm\xb6\xed\xffp\xb8\xec\xff}\xbd\xee\xff\xa8\xd4\xf4\xff\xbe\xdf\xf8\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xffx\xbe\xf1\xffq\xb9\xf0\xff@\xa0\xeb\xff5\x9b\xea\xffA\xa0\xea\xffG\xa3\xea\xffM\xa6\xea\xffS\xa9\xea\xffZ\xab\xea\xff]\xae\xea\xff]\xac\xea\xffk\xb3\xeb\xff:\x87\xbf\xff\x00X\x9a\xff\x00X\x9b\xd1\x00\\\x9eD\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x03\x00[\x9d\xb6\x00[\x9e\xffi\xb2\xe8\xffq\xbc\xf4\xffT\xaa\xed\xffV\xaa\xed\xff^\xaf\xed\xffc\xb2\xed\xffh\xb4\xed\xffj\xb5\xec\xffz\xbd\xee\xff\xa9\xd5\xf5\xff\xb9\xdd\xf8\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff~\xbf\xf1\xff|\xbe\xf0\xffM\xa6\xeb\xff;\x9d\xea\xffG\xa3\xea\xffM\xa6\xea\xffS\xa9\xea\xffW\xaa\xea\xff]\xae\xea\xff\x84\xc1\xee\xff\x9c\xc9\xea\xff\ta\xa1\xff\x00Y\x9b\xcd\x00\\\x9e\x0e\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00[\x9d\x8c\x04_\xa1\xff~\xbc\xea\xff\x9c\xd2\xfa\xff\x8a\xc7\xf5\xffg\xb4\xef\xffY\xad\xec\xffa\xb1\xed\xffd\xb2\xec\xff|\xbe\xef\xff\xa9\xd4\xf6\xff\xb3\xda\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x83\xc2\xf1\xff\x88\xc4\xf1\xff^\xae\xed\xffB\xa0\xea\xffK\xa5\xea\xffN\xa6\xea\xffd\xb0\xeb\xff\x97\xca\xef\xff\xb7\xda\xf3\xff\xa9\xd0\xeb\xff\x0ef\xa4\xff\x00Z\x9c\xa7\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00[\x9d\x92\x04_\xa1\xff\x82\xbf\xee\xff\x98\xd0\xfb\xff\x99\xce\xf7\xff\x9a\xce\xf7\xff\x81\xc1\xf2\xffd\xb2\xed\xff~\xbf\xf0\xff\xa8\xd5\xf7\xff\xae\xd8\xf7\xff\xb1\xd9\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x81\xc1\xf1\xff\x89\xc5\xf1\xff\x91\xc9\xf1\xffo\xb7\xed\xffN\xa6\xea\xffu\xb9\xed\xff\xa3\xd0\xf0\xff\xaf\xd6\xf1\xff\xb5\xda\xf4\xff\xaf\xd5\xef\xff\x0ef\xa4\xff\x00Z\x9c\xaa\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9em\x01[\x9d\xffT\x9c\xd1\xff\x98\xd0\xfb\xff\x9b\xd1\xfa\xff\x99\xce\xf7\xff\x9f\xd2\xf7\xff\x9a\xcf\xf6\xff\xa4\xd4\xf7\xff\xa9\xd6\xf7\xff\xac\xd7\xf7\xff\xb1\xd9\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x81\xc1\xf1\xff\x88\xc4\xf1\xff\x8e\xc7\xf1\xff\x96\xcb\xf1\xff\x93\xc8\xf0\xff\xa3\xd0\xf1\xff\xa7\xd3\xf1\xff\xb3\xd9\xf5\xff\xae\xd4\xf0\xffZ\x98\xc7\xff\x03\\\x9d\xff\x00[\x9d{\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x16\x00[\x9d\xcd\x00W\x99\xff*z\xb6\xff\x85\xc0\xec\xff\xa3\xd6\xfd\xff\x9d\xd1\xf8\xff\xa0\xd3\xf7\xff\xa4\xd4\xf7\xff\xa8\xd5\xf7\xff\xac\xd7\xf7\xff\xb1\xd9\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x81\xc1\xf1\xff\x88\xc4\xf1\xff\x8e\xc7\xf1\xff\x94\xca\xf1\xff\x9c\xcd\xf1\xff\xa3\xd1\xf2\xff\xb1\xd9\xf6\xff\x87\xba\xdf\xff!p\xac\xff\x00T\x99\xff\x00[\x9e\xb9\x00\\\x9e\x13\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0b\x00\\\x9e\x81\x00V\x99\xf5\na\xa2\xff\\\x9f\xd2\xff\xa0\xd3\xf9\xff\xa6\xd7\xfb\xff\xa4\xd4\xf7\xff\xa8\xd5\xf7\xff\xac\xd7\xf7\xff\xb1\xd9\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x81\xc1\xf1\xff\x88\xc4\xf1\xff\x8e\xc7\xf1\xff\x94\xca\xf1\xff\xa3\xd2\xf5\xff\x9e\xcd\xf0\xffQ\x95\xc6\xff\x03[\x9d\xff\x00W\x9a\xe9\x00\\\x9ei\x00\\\x9e\x01\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e.\x00Z\x9c\xb6\x00U\x99\xff(x\xb3\xff\x81\xbc\xe6\xff\xae\xdb\xfc\xff\xab\xd7\xf9\xff\xac\xd7\xf7\xff\xb1\xd9\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x81\xc1\xf1\xff\x88\xc4\xf1\xff\x92\xca\xf3\xff\x9c\xd0\xf5\xffr\xae\xda\xff\x1dn\xab\xff\x00U\x99\xff\x00[\x9d\x9f\x00\\\x9e\x1d\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9ed\x00V\x99\xe9\x03[\x9e\xffL\x92\xc6\xff\xa1\xd0\xf3\xff\xb6\xde\xfc\xff\xb2\xda\xf7\xff\xb6\xdb\xf7\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff{\xbe\xf1\xff\x82\xc2\xf2\xff\x90\xca\xf6\xff\x82\xbe\xe9\xff8\x84\xbc\xff\x00X\x9b\xff\x00W\x9b\xd9\x00\\\x9eO\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x1c\x00[\x9d\x9f\x00T\x98\xff\x18j\xa8\xfft\xaf\xd9\xff\xb8\xde\xfa\xff\xbb\xdf\xfa\xff\xba\xdd\xf7\xff\xbd\xde\xf7\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffn\xb9\xf1\xfft\xbc\xf1\xff\x80\xc2\xf4\xff\x85\xc4\xf3\xffR\x9a\xcf\xff\rc\xa3\xff\x00U\x99\xf9\x00[\x9e\x88\x00\\\x9e\x0f\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eG\x00X\x9b\xd0\x00V\x9a\xff=\x85\xbb\xff\xa3\xce\xee\xff\xc6\xe5\xfd\xff\xbf\xdf\xf8\xff\xc2\xe0\xf7\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffi\xb7\xf1\xffo\xba\xf2\xff|\xc2\xf6\xffj\xb0\xe4\xff%w\xb4\xff\x00U\x99\xff\x00Z\x9c\xbc\x00\\\x9e3\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x08\x00\\\x9e{\x00T\x99\xf5\rb\xa2\xffk\xa5\xd0\xff\xbe\xdf\xf7\xff\xcb\xe6\xfb\xff\xc5\xe2\xf7\xff\xc9\xe3\xf7\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xff_\xb2\xf1\xffd\xb4\xf1\xffn\xbc\xf5\xffm\xb8\xf0\xff=\x8d\xc8\xff\x06^\x9f\xff\x00W\x99\xe9\x00\\\x9ed\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e0\x00Y\x9c\xbc\x00T\x98\xff*v\xb0\xff\x95\xc2\xe2\xff\xd0\xea\xfc\xff\xcd\xe6\xf9\xff\xcd\xe6\xf7\xff\xc8\xe3\xf7\xffe\xb5\xf2\xffY\xaf\xf1\xffa\xb4\xf3\xffj\xb9\xf5\xffN\x9f\xda\xff\x15k\xab\xff\x00V\x98\xff\x00Z\x9d\xa7\x00\\\x9e \x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9ec\x00V\x9a\xe4\x01Y\x9c\xffS\x93\xc2\xff\xbf\xdd\xf2\xff\xd9\xee\xfc\xff\xc9\xe3\xf7\xffe\xb5\xf2\xff^\xb4\xf6\xffZ\xad\xeb\xff(}\xbc\xff\x00Y\x9b\xff\x00X\x9b\xd7\x00\\\x9eO\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x18\x00[\x9d\x9a\x00S\x98\xff\x1cl\xa8\xff\x8d\xb9\xda\xff\xd1\xe9\xfb\xffk\xba\xf5\xff;\x92\xd3\xff\x0cd\xa5\xff\x00V\x99\xf7\x00[\x9d\x85\x00\\\x9e\r\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9eA\x00X\x9b\xd2\x00V\x9a\xff?\x87\xbb\xff&z\xb8\xff\x00W\x99\xff\x00Y\x9c\xc3\x00\\\x9e1\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0b\x00\\\x9e\x81\x00V\x9a\xf0\x00X\x9a\xf2\x00\\\x9eu\x00\\\x9e\x03\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x0f\x00[\x9et\x00\\\x9ex\x00\\\x9e\x0b\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff\x00', gtk.gdk.COLORSPACE_RGB, True, 8, 64, 64, 256) + window_icon = gtk.gdk.pixbuf_new_from_data('\x00\\\x9e\x00\x00\\\x9e\x00\x00^\xa0\x00\x00V\x99\x00\x00L\x91g\x00N\x93q\x00X\x9c\x00\x00^\x9f\x00\x00]\x9f\x00\x00Y\x9c\x00\x00P\x94o\x00M\x92i\x00V\x99\x00\x00^\xa0\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00^\xa0\x00\x00T\x97\x00\x00F\x8c_1\x81\xba\xff+|\xb6\xff\x00F\x8e?\x00\\\x9e\x00\x00\\\x9e\x00\x00J\x8e;$y\xb6\xff-\x7f\xbc\xff\x00E\x8cb\x00R\x97\x00\x00^\xa0\x00\x00\\\x9e\x00\x00[\x9d\x00\x00I\x8c*\x05X\x9b\xc0P\x9b\xd5\xff\xa7\xdd\xff\xff\xbb\xe5\xff\xff@\x86\xbb\xff\x00>\x89D\x00D\x89B\'{\xbb\xff\x89\xcf\xff\xff\xa2\xdb\xff\xffg\xa6\xd5\xff\x07Y\x9b\xc3\x00C\x8c,\x00[\x9d\x00\x05\\\x9e\x971\x84\xc5\xffk\xbb\xf6\xff\x8e\xd0\xff\xff\x86\xc3\xf0\xff\xa2\xd2\xf5\xff\xc4\xe7\xff\xffP\x90\xc0\xff\x15u\xbf\xfff\xbf\xff\xffx\xc1\xf6\xff\x80\xc0\xf0\xff\xb0\xdf\xff\xff\xa9\xd7\xf6\xff\\\x97\xc5\xff\x0b]\x9e\x98\x08[\x9e\xdcX\xb0\xf0\xff\x84\xd0\xff\xffx\xbc\xf0\xff\x83\xc2\xf0\xff\x88\xc3\xee\xff\xb1\xd7\xf3\xff\xf9\xff\xff\xff\xca\xec\xff\xffm\xba\xf3\xffX\xae\xee\xff{\xbe\xf0\xff\x91\xc7\xf0\xff\xd2\xf2\xff\xff\xa6\xd4\xf0\xff\x11]\x9e\xde\x00T\x96\x00\x00N\x91\x9eD\x98\xd5\xff\x84\xc9\xfc\xff\x85\xc3\xf1\xff\xb7\xdb\xf6\xff\xe9\xf4\xfc\xff\xe9\xf5\xfd\xff\xdb\xee\xfd\xff\xdf\xef\xfc\xff\xa8\xd5\xf6\xff|\xbf\xf1\xff\xa3\xd6\xfc\xffl\xaa\xd6\xff\x00J\x91\xa1\x00Q\x96\x00\x00^\xa0\x00\x00T\x97\x00\x008\x7f\x9eC\x94\xd1\xff\xde\xf6\xff\xff\xf5\xfc\xff\xff\xe0\xef\xfb\xff\xe0\xf0\xfb\xff\xc8\xe5\xfb\xff\xcf\xe7\xfb\xff\xff\xff\xff\xff\xfe\xff\xff\xffV\x9d\xd2\xff\x002\x80\xa2\x00Q\x96\x00\x00_\xa0\x00\x00W\x99\x00\x00I\x8cq9\x89\xc3\xf1Y\xb0\xf2\xffR\xaa\xef\xff\xbc\xde\xf7\xff\xf9\xfc\xfe\xff\xe3\xf2\xfb\xff\xd3\xea\xfc\xff\xf5\xfb\xff\xff\xb7\xdb\xf7\xffd\xb1\xed\xff\x86\xc3\xf2\xffR\x93\xc4\xf3\x00D\x8du\x00T\x99\x00\x06Z\x9d\xb3I\xa0\xe0\xff\x8a\xd2\xff\xffe\xb5\xf2\xff/\x97\xe8\xffK\xa4\xe9\xff\x9c\xcd\xf0\xff\xf6\xf9\xfc\xff\xd6\xec\xfc\xffX\xab\xf0\xff\x15\x8a\xe6\xff9\x9b\xe6\xff\x8c\xc6\xf1\xff\xd1\xf0\xff\xff\x8b\xbe\xe1\xff\x0e\\\x9d\xb6\x07]\x9f\xc1D\x98\xd9\xff\x85\xcd\xff\xffm\xbc\xf9\xff;\x9d\xe9\xff^\xae\xec\xffl\xb3\xe8\xff\xb7\xd9\xf2\xffC\xa2\xef\xff\x00s\xe5\xff3\x99\xea\xffL\xa3\xe7\xff\x96\xce\xf9\xff\xc7\xeb\xff\xff\x81\xb3\xd9\xff\x10_\x9f\xc4\x00X\x9a\x00\x00H\x8bU\x1eq\xad\xeeR\xa8\xe8\xffA\xa4\xf1\xff`\xae\xea\xff\xa9\xd3\xf2\xff\xc8\xe4\xf8\xffh\xb7\xf2\xff@\xa2\xed\xff,\x95\xe8\xffQ\xaa\xef\xff|\xba\xe9\xff*u\xae\xf1\x00A\x8bX\x00V\x9a\x00\x00\\\x9e\x00\x00]\x9f\x00\x00>\x84\x0c"v\xb3\xff\x9b\xdb\xff\xff\x97\xcf\xf8\xff\xce\xe6\xf8\xff\xc5\xe1\xf7\xffe\xb5\xf1\xfft\xbc\xf0\xffu\xbe\xf5\xff\xa9\xde\xff\xff0{\xb0\xff\x00:\x85\x0f\x00]\x9f\x00\x00]\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00Y\x9c\x00\x02S\x97zH\x89\xbf\xff\xb8\xe3\xfd\xff\xe8\xfb\xff\xff\xc2\xdf\xf7\xff`\xb3\xf1\xff\x82\xcb\xff\xff\xa1\xd3\xf7\xffJ\x88\xb8\xff\x00S\x96r\x00Z\x9d\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00]\x9f\x00\x00[\x9d\x00\x00C\x8b*\x08W\x9b\xc5\x8c\xb9\xda\xff\xea\xfd\xff\xff\x80\xcb\xff\xffG\x97\xd4\xff\x03W\x99\xbc\x00E\x8d"\x00[\x9e\x00\x00]\x9f\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00_\xa0\x00\x00Q\x96\x00\x00C\x8di>\x88\xbd\xff,\x7f\xbb\xff\x00G\x8c`\x00T\x98\x00\x00^\xa0\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00_\xa0\x00\x00R\x98\x00\x00I\x92r\x00P\x92n\x00V\x99\x00\x00^\xa0\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00\x00\\\x9e\x00', gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16, 64) + +GUI_AVAILABLE = os.environ.get("DISPLAY", '') + +if GUI_AVAILABLE: + def download(): + import pygtk + pygtk.require("2.0") + import gtk + import gobject + import pango + import webbrowser + + load_serialized_images() + + global FatalVisibleError + def FatalVisibleError(s): + error = gtk.MessageDialog(parent = None, + flags = gtk.DIALOG_MODAL, + type = gtk.MESSAGE_ERROR, + buttons = gtk.BUTTONS_OK, + message_format = s) + error.set_title("Error") + error.run() + gtk.main_quit() + sys.exit(-1) + + def gtk_flush_events(): + while gtk.events_pending(): + gtk.main_iteration() + + class DownloadDialog(gtk.Dialog): + def handle_delete_event(self, wid, ev, data=None): + self.handle_cancel(wid) + + def handle_cancel(self, button): + if self.watch: + gobject.source_remove(self.watch) + if self.download: + self.download.cancel() + gtk.main_quit() + self.user_cancelled = True + + def handle_ok(self, button): + # begin download + self.ok.hide() + self.download = DownloadState() + self.one_chunk = self.download.copy_data() + self.watch = gobject.io_add_watch(self.download.file, + gobject.IO_IN | + gobject.IO_PRI | + gobject.IO_ERR | + gobject.IO_HUP, + self.handle_data_waiting) + self.label.hide() + self.progress.show() + + def update_progress(self, text, fraction): + self.progress.set_text(text % int(fraction*100)) + self.progress.set_fraction(fraction) + gtk_flush_events() + + def handle_data_waiting(self, fd, condition): + if condition == gobject.IO_HUP: + FatalVisibleError("Connection to server unexpectedly closed.") + elif condition == gobject.IO_ERR: + FatalVisibleError("Unexpected error occurred with download.") + try: + while self.one_chunk.next(): + self.update_progress(DOWNLOADING, float(self.download.progress)/self.download.size) + except StopIteration: + self.update_progress(DOWNLOADING, 1.0) + self.unpack_dropbox() + return False + else: + self.update_progress(DOWNLOADING, float(self.download.progress)/self.download.size) + return True + + def unpack_dropbox(self): + one_member = self.download.unpack() + try: + while True: + name, i, total = one_member.next() + self.update_progress(UNPACKING, float(i)/total) + except StopIteration: + self.update_progress(UNPACKING, 1.0) + gtk.main_quit() + + def mouse_down(self, widget, event): + if self.hovering: + self.clicked_link = True + + def mouse_up(self, widget, event): + if self.clicked_link: + webbrowser.open(LINK) + self.clicked_link = False + + def label_motion(self, widget, event): + offx, offy = self.label.get_layout_offsets() + layout = self.label.get_layout() + index = layout.xy_to_index(int((offx+event.x)*pango.SCALE), + int((offy+event.y)*pango.SCALE))[0] + link_index = layout.get_text().find(LINK) + if index >= link_index and index < link_index+len(LINK): + self.hovering = True + self.label_box.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2)) + else: + self.hovering = False + self.label_box.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW)) + + + def __init__(self): + super(DownloadDialog, self).__init__(parent = None, + title = "Dropbox Installation") + + self.download = None + self.watch = None + self.hovering = False + self.clicked_link = False + self.user_cancelled = False + + self.ok = ok = gtk.Button(stock=gtk.STOCK_OK) + ok.connect('clicked', self.handle_ok) + self.action_area.add(ok) + ok.show() + + cancel = gtk.Button(stock=gtk.STOCK_CANCEL) + cancel.connect('clicked', self.handle_cancel) + self.action_area.add(cancel) + cancel.show() + + self.connect('delete_event', self.handle_delete_event) + + self.box_logo = gtk.image_new_from_pixbuf(box_logo_pixbuf) + self.box_logo.show() + + self.set_icon(window_icon) + + self.progress = gtk.ProgressBar() + self.progress.set_property('width-request', 300) + + self.label = gtk.Label() + self.label.set_markup('%s %s\n\n%s' % (INFO, LINK, WARNING)) + self.label.set_line_wrap(True) + self.label.set_property('width-request', 300) + self.label.show() + + self.label_box = gtk.EventBox() + self.label_box.add(self.label) + self.label_box.connect("button-release-event", self.mouse_up) + self.label_box.connect("button-press-event", self.mouse_down) + self.label_box.connect("motion-notify-event", self.label_motion) + self.label_box.show() + def on_realize(widget): + self.label_box.add_events(gtk.gdk.POINTER_MOTION_MASK) + self.label_box.connect("realize", on_realize) + + self.hbox = gtk.HBox(spacing=10) + self.hbox.set_property('border-width',10) + self.hbox.pack_start(self.box_logo, False, False) + self.hbox.pack_start(self.label_box, False, False) + self.hbox.pack_start(self.progress, False, False) + self.hbox.show() + + self.vbox.add(self.hbox) + self.set_resizable(False) + + dialog = DownloadDialog() + dialog.show() + gtk.main() + if dialog.user_cancelled: + raise Exception("user cancelled download!!!") +else: + def download(): + global FatalVisibleError + def FatalVisibleError(s): + console_print(u"\nError: %s" % s, f=sys.stderr) + sys.exit(-1) + + + ESC = "\x1b" + save = ESC+"7" + unsave = ESC+"8" + clear = ESC+"[2J" + erase_to_start = ESC+"[1K" + write = sys.stdout.write + flush = sys.stdout.flush + + last_progress = [None, None] + def setprogress(text, frac): + if last_progress == [text, frac]: + return + if sys.stdout.isatty(): + write(erase_to_start) + write(unsave) + console_print(text % int(100*frac), linebreak=not sys.stdout.isatty()) + if sys.stdout.isatty(): + flush() + last_progress[0], last_progress[1] = text, frac + + console_print() + if sys.stdout.isatty(): + write(save) + flush() + console_print(u"%s %s\n" % (INFO, LINK)) + + if not yes_no_question(WARNING): + return + + download = DownloadState() + one_chunk = download.copy_data() + + try: + while True: + one_chunk.next() + setprogress(DOWNLOADING, float(download.progress)/download.size) + except StopIteration: + setprogress(DOWNLOADING, 1.0) + console_print() + write(save) + + one_member = download.unpack() + + try: + while True: + name, i, total = one_member.next() + setprogress(UNPACKING, float(i)/total) + except StopIteration: + setprogress(UNPACKING, 1.0) + + console_print() + +class DropboxCommand(object): + class CouldntConnectError(Exception): pass + class BadConnectionError(Exception): pass + class EOFError(Exception): pass + class CommandError(Exception): pass + + def __init__(self): + self.s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.s.settimeout(3) + try: + self.s.connect(os.path.expanduser(u'~/.dropbox/command_socket')) + except socket.error, e: + raise DropboxCommand.CouldntConnectError() + self.f = self.s.makefile("r+", 4096) + + def close(self): + self.f.close() + self.s.close() + + def __readline(self): + try: + toret = self.f.readline().decode('utf8').rstrip(u"\n") + except socket.error, e: + raise DropboxCommand.BadConnectionError() + if toret == '': + raise DropboxCommand.EOFError() + else: + return toret + + # atttribute doesn't exist, i know what you want + def send_command(self, name, args): + self.f.write(name.encode('utf8')) + self.f.write(u"\n".encode('utf8')) + self.f.writelines((u"\t".join([k] + (list(v) + if hasattr(v, '__iter__') else + [v])) + u"\n").encode('utf8') + for k,v in args.iteritems()) + self.f.write(u"done\n".encode('utf8')) + + self.f.flush() + + ok = self.__readline() == u"ok" + if ok: + toret = {} + for i in range(21): + if i == 20: + raise Exception(u"close this connection!") + + line = self.__readline() + if line == u"done": + break + + argval = line.split(u"\t") + toret[argval[0]] = argval[1:] + + return toret + else: + problems = [] + for i in range(21): + if i == 20: + raise Exception(u"close this connection!") + + line = self.__readline() + if line == u"done": + break + + problems.append(line) + + raise DropboxCommand.CommandError(u"\n".join(problems)) + + # this is the hotness, auto marshalling + def __getattr__(self, name): + try: + return super(DropboxCommand, self).__getattr__(name) + except: + def __spec_command(**kw): + return self.send_command(unicode(name), kw) + self.__setattr__(name, __spec_command) + return __spec_command + +commands = {} + +def command(meth): + global commands + assert meth.__doc__, "All commands need properly formatted docstrings (even %r!!)" % meth + if hasattr(meth, 'im_func'): # bound method, if we ever have one + meth = meth.im_func + commands[meth.func_name] = meth + return meth + +def requires_dropbox_running(meth): + def newmeth(*n, **kw): + if is_dropbox_running(): + return meth(*n, **kw) + else: + console_print(u"Dropbox isn't running!") + newmeth.func_name = meth.func_name + newmeth.__doc__ = meth.__doc__ + return newmeth + +def start_dropbox(): + db_path = os.path.expanduser(u"~/.dropbox-dist/dropboxd").encode(sys.getfilesystemencoding()) + if os.access(db_path, os.X_OK): + f = open("/dev/null", "w") + # we don't reap the child because we're gonna die anyway, let init do it + a = subprocess.Popen([db_path], preexec_fn=os.setsid, cwd=os.path.expanduser("~"), + stderr=sys.stderr, stdout=f, close_fds=True) + + # in seconds + interval = 0.5 + wait_for = 60 + for i in xrange(int(wait_for / interval)): + if is_dropbox_running(): + return True + # back off from connect for a while + time.sleep(interval) + + return False + else: + return False + +@command +@requires_dropbox_running +def filestatus(args): + u"""get current sync status of one or more files +dropbox filestatus [-l] [-a] [FILE]... + +Prints the current status of each FILE. + +options: + -l --list prints out information in a format similar to ls. works best when your console supports color :) + -a --all do not ignore entries starting with . +""" + oparser = optparse.OptionParser() + oparser.add_option("-l", "--list", action="store_true", dest="list") + oparser.add_option("-a", "--all", action="store_true", dest="all") + (options, args) = oparser.parse_args(args) + + # first check if dropbox is already running + try: + with closing(DropboxCommand()) as dc: + if options.list: + # TODO: ls style columns + + if len(args) == 0: + dirs, nondirs = [u"."], [] + else: + dirs, nondirs = [], [] + + for a in args: + try: + (dirs if os.path.isdir(a) else nondirs).\ + append(a.decode(sys.getfilesystemencoding())) + except UnicodeDecodeError: + pass + + if len(dirs) == 0 and len(nondirs) == 0: + exit(1) + + def lowerkey(st): + return st.lower() + + dirs.sort(key=lowerkey) + nondirs.sort(key=lowerkey) + + def printstatus(fp): + if not os.path.exists(fp): + console_print(u"%s (File doesn't exist!)" % os.path.basename(fp)) + return + + try: + status = dc.icon_overlay_file_status(path=fp).get(u'status', [None])[0] + except DropboxCommand.CommandError, e: + console_print(u"%s (%s)" % (os.path.basename(fp), e)) + return + + if not sys.stdout.isatty(): + console_print(os.path.basename(fp)) + return + + if status == u"up to date": + INIT, CLEANUP = "\x1b[32m", "\x1b[0m" + elif status == u"syncing": + INIT, CLEANUP = "\x1b[36m", "\x1b[0m" + elif status == u"unsyncable": + INIT, CLEANUP = "\x1b[41m", "\x1b[0m" + else: + INIT, CLEANUP = '', '' + + console_print(u"%s%s%s" % (INIT, os.path.basename(fp), CLEANUP)) + + def printdir(name): + for subname in sorted(os.listdir(name), key=lowerkey): + if type(subname) != unicode: + continue + + if not options.all and subname[0] == u'.': + continue + + try: + printstatus(unicode_abspath(os.path.join(name, subname))) + except (UnicodeEncodeError, UnicodeDecodeError), e: + continue + try: + if len(dirs) == 1 and len(nondirs) == 0: + printdir(dirs[0]) + else: + for name in nondirs: + try: + printstatus(unicode_abspath(name)) + except (UnicodeEncodeError, UnicodeDecodeError), e: + continue + + if len(nondirs) == 0: + console_print(dirs[0] + u":") + printdir(dirs[0]) + dirs = dirs[1:] + + for name in dirs: + console_print() + console_print(name + u":") + printdir(name) + except DropboxCommand.EOFError: + console_print(u"Dropbox daemon stopped.") + except DropboxCommand.BadConnectionError, e: + console_print(u"Dropbox isn't responding!") + else: + if len(args) == 0: + args = [name for name in os.listdir(u".") if type(name) == unicode] + indent = max(len(st)+1 for st in args) + for file in args: + try: + fp = unicode_abspath(file.decode(sys.getfilesystemencoding())) + except (UnicodeEncodeError, UnicodeDecodeError), e: + continue + if not os.path.exists(fp): + console_print(u"%-*s %s" % \ + (indent, file+':', "File doesn't exist")) + continue + + try: + status = dc.icon_overlay_file_status(path=fp).get(u'status', [u'unknown'])[0] + console_print(u"%-*s %s" % (indent, file+':', status)) + except DropboxCommand.CommandError, e: + console_print(u"%-*s %s" % (indent, file+':', e)) + except DropboxCommand.CouldntConnectError, e: + console_print(u"Dropbox isn't running!") + +@command +@requires_dropbox_running +def ls(args): + u"""list directory contents with current sync status +dropbox ls [FILE]... + +This is an alias for filestatus -l +""" + return filestatus(["-l"] + args) + +@command +@requires_dropbox_running +def puburl(args): + u"""get public url of a file in your dropbox +dropbox puburl FILE + +Prints out a public url for FILE. +""" + if len(args) != 1: + console_print(puburl.__doc__,linebreak=False) + return + + try: + with closing(DropboxCommand()) as dc: + try: + console_print(dc.get_public_link(path=unicode_abspath(args[0].decode(sys.getfilesystemencoding()))).get(u'link', [u'No Link'])[0]) + except DropboxCommand.CommandError, e: + console_print(u"Couldn't get public url: " + str(e)) + except DropboxCommand.BadConnectionError, e: + console_print(u"Dropbox isn't responding!") + except DropboxCommand.EOFError: + console_print(u"Dropbox daemon stopped.") + except DropboxCommand.CouldntConnectError, e: + console_print(u"Dropbox isn't running!") + +@command +@requires_dropbox_running +def status(args): + u"""get current status of the dropboxd +dropbox status + +Prints out the current status of the Dropbox daemon. +""" + if len(args) != 0: + console_print(status.__doc__,linebreak=False) + return + + try: + with closing(DropboxCommand()) as dc: + try: + lines = dc.get_dropbox_status()[u'status'] + if len(lines) == 0: + console_print(u'Idle') + else: + for line in lines: + console_print(line) + except KeyError: + console_print(u"Couldn't get status: daemon isn't responding") + except DropboxCommand.CommandError, e: + console_print(u"Couldn't get status: " + str(e)) + except DropboxCommand.BadConnectionError, e: + console_print(u"Dropbox isn't responding!") + except DropboxCommand.EOFError: + console_print(u"Dropbox daemon stopped.") + except DropboxCommand.CouldntConnectError, e: + console_print(u"Dropbox isn't running!") + +@command +@requires_dropbox_running +def stop(args): + u"""stop dropboxd +dropbox stop + +Stops the dropbox daemon. +""" + try: + with closing(DropboxCommand()) as dc: + try: + dc.tray_action_hard_exit() + except DropboxCommand.BadConnectionError, e: + console_print(u"Dropbox isn't responding!") + except DropboxCommand.EOFError: + console_print(u"Dropbox daemon stopped.") + except DropboxCommand.CouldntConnectError, e: + console_print(u"Dropbox isn't running!") + +@command +def start(argv): + u"""start dropboxd +dropbox start [-i] + +Starts the dropbox daemon, dropboxd. If dropboxd is already running, this will do nothing. + +options: + -i --install auto install dropboxd if not available on the system +""" + + should_install = "-i" in argv or "--install" in argv + + # first check if dropbox is already running + if is_dropbox_running(): + console_print(u"Dropbox is already running!") + return + + console_print(u"Starting Dropbox...", linebreak=False) + console_flush() + if not start_dropbox(): + if not should_install: + console_print() + console_print(u"The Dropbox daemon is not installed!") + console_print(u"Run with -i to install the daemon") + return + + # install dropbox!!! + try: + download() + except: + pass + else: + if GUI_AVAILABLE: + start_dropbox() + else: + console_print(u"Dropbox has been downloaded successfully.") + console_print(u"In order to link to an account for the first time, a graphical environment is required.") + console_print(u"Try running 'dropbox start' from X windows") + console_print(u"Done!") + +@command +def help(argv): + u"""provide help +dropbox help [COMMAND] + +With no arguments, print a list of commands and a short description of each. With a command, print descriptive help on how to use the command. +""" + if not argv: + return usage(argv) + for command in commands: + if command == argv[0]: + console_print(commands[command].__doc__.split('\n', 1)[1].decode('ascii')) + return + console_print(u"unknown command '%s'" % argv[0], f=sys.stderr) + +def usage(argv): + console_print(u"Dropbox command-line interface\n") + console_print(u"commands:\n") + out = [] + for command in commands: + out.append((command, commands[command].__doc__.splitlines()[0])) + spacing = max(len(o[0])+3 for o in out) + for o in out: + console_print(" %-*s%s" % (spacing, o[0], o[1])) + console_print() + +def main(argv): + global commands + + # now we need to find out if one of the commands are in the + # argv list, and if so split the list at the point to + # separate the argv list at that point + cut = None + for i in range(len(argv)): + if argv[i] in commands: + cut = i + break + + if cut == None: + usage(argv) + return + + # lol no options for now + globaloptionparser = optparse.OptionParser() + globaloptionparser.parse_args(argv[0:i]) + + # now dispatch and run + return commands[argv[i]](argv[i+1:]) + +if __name__ == "__main__": + main(sys.argv) diff --git a/dvd-blank b/dvd-blank new file mode 100755 index 0000000..a58592c --- /dev/null +++ b/dvd-blank @@ -0,0 +1,6 @@ + +. /etc/dvd-scripts.env + +dvd+rw-format -blank $DVD_DEVICE + +echo Fertig. diff --git a/dvd-burn-files b/dvd-burn-files new file mode 100755 index 0000000..6929dcd --- /dev/null +++ b/dvd-burn-files @@ -0,0 +1,24 @@ + +set -x + +. /etc/dvd-scripts.env + +DVD_DIR=$1 + +echo "Verzeichnis $DVD_DIR auf DVD brennen..." + +MAX_SIZE=4702989182 + +# DVD-Size 4,702,989,182 +size=`du -sb "$DVD_DIR" | awk '{print $1}'` +#printf "size: %4d MB\n" `expr $size \/ 1024 \/ 1024` +printf "size: %4d MB\n" `echo "$size/1024/1024;" | bc ` +if [ $size -gt $MAX_SIZE ] +then + printf "Zu Groß (max: %4d MB) !!!\n" `expr $MAX_SIZE \/ 1024 \/ 1024` +else + growisofs -Z $DVD_DEVICE -R -J $DVD_DIR +fi +sleep 1 +echo Fertig. +eject diff --git a/dvd-burn-image b/dvd-burn-image new file mode 100755 index 0000000..df130aa --- /dev/null +++ b/dvd-burn-image @@ -0,0 +1,15 @@ +#!/bin/bash + +set -x + +. /etc/dvd-scripts.env + +#/etc/init.d/hdparm restart +hdparm -u1 -d1 $DVD_DEVICE + +DVD_IMAGE=$1 + +[ -r $DVD_IMAGE ] && growisofs -Z $DVD_DEVICE=$DVD_IMAGE +echo Fertig. +sleep 1 +eject diff --git a/dvd-burn-video b/dvd-burn-video new file mode 100755 index 0000000..2239ad8 --- /dev/null +++ b/dvd-burn-video @@ -0,0 +1,16 @@ +#!/bin/sh + +set -x + +. /etc/dvd-scripts.env + +#A/etc/init.d/hdparm restart +hdparm -d1 -u1 $DVD_DEVICE + +DVD_DIR=$1 + +growisofs -Z $DVD_DEVICE -dvd-video $DVD_DIR +growisofs -lead-out $DVD_DEVICE +echo Fertig. +sleep 1 +eject diff --git a/dvd-check-size b/dvd-check-size new file mode 100755 index 0000000..1dfd29e --- /dev/null +++ b/dvd-check-size @@ -0,0 +1,17 @@ + +#set -x + +. /etc/dvd-scripts.env + +DVD_DIR=$1 +MAX_DVD_SIZE=4702989182 + +# DVD-Size 4,702,989,182 +size=`du -sb "$DVD_DIR" | awk '{print $1}'` +printf "Größe: %4d MB\n" `expr $size \/ 1024 \/ 1024` +if [ $size -gt $MAX_DVD_SIZE ] +then + printf "zu Groß (max %4d MB)\n" `expr $MAX_DVD_SIZE \/ 1024 \/ 1024` +else + echo Paßt. +fi diff --git a/dvd-createdev b/dvd-createdev new file mode 100755 index 0000000..e85147c --- /dev/null +++ b/dvd-createdev @@ -0,0 +1,16 @@ +#!/bin/sh + +DVD_DEVICE=/dev/dvd + +if [ -L $DVD_DEVICE ] +then + echo "Link löschen" + rm $DVD_DEVICE +else + echo "Altes Device löschen $DVD_DEVICE" + umount $DVD_DEVICE + rmdir $DVD_DEVICE +fi +echo "neuen device erstellen" +mkdir $DVD_DEVICE + diff --git a/dvd-format b/dvd-format new file mode 100755 index 0000000..9299008 --- /dev/null +++ b/dvd-format @@ -0,0 +1,6 @@ + +. /etc/dvd-scripts.env + +dvd+rw-format -force $DVD_DEVICE + +echo Fertig. diff --git a/dvd-gen-movix b/dvd-gen-movix new file mode 100755 index 0000000..a054cd6 --- /dev/null +++ b/dvd-gen-movix @@ -0,0 +1,31 @@ + +set -x + +. /etc/dvd-scripts.env + +DVD_DIR=$1 +FILES=$2 + +cd $DVD_DIR + +echo "Movix DVD aus Dateien $DVD_DIR/$FILES erzeugen..." + +#MAX_SIZE=4702989182 + +# DVD-Size 4,702,989,182 +i#size=`du -sb "$DVD_DIR" | awk '{print $1}'` +#printf "size: %4d MB\n" `expr $size \/ 1024 \/ 1024` +#printf "size: %4d MB\n" `echo "$size/1024/1024;" | bc ` +#if [ $size -gt $MAX_SIZE ] +#then +# printf "Zu Groß (max: %4d MB) !!!\n" `expr $MAX_SIZE \/ 1024 \/ 1024` +#lse +# growisofs -Z $DVD_DEVICE -R -J $DVD_DIR +#fi + +mkmovixiso $FILES +ln -s movix.iso last.iso + +sleep 1 +echo Fertig. +eject diff --git a/dvd-rip-image b/dvd-rip-image new file mode 100755 index 0000000..b0c203f --- /dev/null +++ b/dvd-rip-image @@ -0,0 +1,17 @@ +#!/bin/sh + +. /etc/dvd-scripts.env + +DVD_IMAGE=$1 + +rm "$DVD_IMAGE" +rm /dat/dvd/last.iso + +echo Image wird erstellt... +dd if=$DVD_DEVICE of="$DVD_IMAGE" + +ln -s "$DVD_IMAGE" /dat/dvd/last.iso + +echo Fertig. + +eject diff --git a/dvd2vdr b/dvd2vdr new file mode 100755 index 0000000..eed83d0 --- /dev/null +++ b/dvd2vdr @@ -0,0 +1,1378 @@ +#! /bin/bash + +############################################################################ +# Copyright (C) 2006 by Ronny Frankowski (lini@lausitz.net) # +# & AngieSoft (vdr@angiesoft.de) # +# & Matthias Appel (private_tweety@gmx.net) # +# # +# This program is free software; you can redistribute it and#or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ + + +########################################################################### +# define some variables +########################################################################### + +VERSION="1.0.1" + +VIDEODIR=/video0/vdr/video # video directory of vdr +WORKDIR=/video0/vdr/tmp/dvd2vdr # working directory of dvd2vdr +DVD_DEVICE=/dev/cdrom # dvd device + +DVD2VDR_CONF=/video0/vdr/conf/plugins/dvd2vdr.conf + + # this file overrides some + # internal settings and + # command line options + +LANGUAGE="de" # select preferred language + # "de", "en" + +RECORDING_LIFETIME=99 # lifetime from 00 to 99 +RECORDING_MAX_SIZE=2000000000 # max size (byte) for a single + # *.vdr file +RECORDING_MAX_CHUNKS=255 # max chunks for spliting + +#TITLE_MIN_LENGTH=60 # mimimun length in sec for + # a title on a DVD to be + # considered for conversion + +PRIO=15 # priority from 1 to 19 +SLEEPTIME=10 # wait for user action +VERBOSE=1 # be verbose - 0: off, 1: on +DEBUG=1 # debug info - 0: off, 1-3: level +FORCE=0 # force exec - 0: off, 1: on (erzwingen) +CLEAN=1 # clean dirs - 0: off, 1: on (abschliesendes loeschen) +REMOVE=1 # remove tmp file - 0: off, 1: on (temp. loeschen im Betrieb) + +OSDINFO=1 # svdrpsend - 0: off, 1: on + +A52DEC_GAIN="+5.0" # add gain in decibels +CREATE_MARKS=0 # create a marks.vdr for vdr - 0: off, 1: on + + +########################################################################### +# define required tools +########################################################################### + +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:~/bin + +SVDRPSEND_PL=svdrpsend.pl + +VOBCOPY_BIN=vobcopy +EJECT_BIN=eject +TCPROBE_BIN=tcprobe +TCCAT_BIN=tccat +TCEXTRACT_BIN=tcextract +TCDEMUX_BIN=tcdemux + +A52DEC_BIN=a52dec +TOOLAME_BIN=toolame +MP2ENC_BIN=mp2enc + +JAVA_BIN=/usr/lib/java/bin/java +PROJECTX_JAR=/usr/local/share/vdrconvert/pX/pX.jar #/usr/local/bin/projectX.jar +PROJECTX_INI=/usr/local/share/vdrconvert/pX/pX.ini #/usr/local/etc/dvd2vdr-projectX.ini +XVFB_BIN=/usr/X11R6/bin/Xvfb + +TCMPLEX_BIN=tcmplex +TCMPLEX_PANTELTJE_BIN=tcmplex-panteltje +MPLEX_BIN=mplex + +SPLIT_BIN=split + +GENINDEX_BIN=genindex +GENINDEX_MJPEGFIX_BIN=genindex-mjpegfix + +LOGDIR=/var/log/vdr +LOGFILE=$LOGDIR/dvd2vdr.log +LOCKFILE=$LOGDIR/dvd2vdr.LOCK + + +########################################################################### +# print usage information +########################################################################### + +usage() { +test -n "$1" && echo "${RED} Error: $1${NORMAL}" && echo +echo " DVD2VDR Version ${MAGENTA}$VERSION${NORMAL}" +echo +echo " ${CYAN}Usage: ${GREEN}$0${NORMAL}" +echo " ${CYAN} or: ${GREEN}$0${NORMAL} [options]" +echo +echo " DVD2VDR is intended to convert the main movie of a DVD into" +echo " a VDR recoring. If required the main movie will be demuxed" +echo " transcoded and remuxed again." +echo +echo " ${CYAN}Actions:${NORMAL}" +echo +echo "${GREEN} all${NORMAL}" +echo " Do all steps of the following" +echo "${GREEN} copy${NORMAL}" +echo " Copy the main movie to disk" +echo "${GREEN} demux${NORMAL}" +echo " Demultiplex the main movie in mpv and ac3" +echo "${GREEN} encode${NORMAL}" +echo " Encode ac3 to mp2" +echo "${GREEN} mplex${NORMAL}" +echo " Multiplex the parts to a VDR recording" +echo "${GREEN} split${NORMAL}" +echo " Split the VDR recording into chunks" +echo "${GREEN} genindex${NORMAL}" +echo " Create an index.vdr" +echo "${GREEN} move${NORMAL}" +echo " Move recording to video directory" +echo +echo " ${CYAN}Options:${NORMAL}" +echo +echo "${GREEN} -i | --device ${MAGENTA}${NORMAL}" +echo " Read DVD structure from this device" +echo "${GREEN} -o ${MAGENTA}${NORMAL}" +echo " Write output into this video directory" +echo "${GREEN} -w ${NORMAL}" +echo " Use working directory as base for temp directory" +echo "${GREEN} -t ${MAGENTA}${NORMAL}" +echo " Use temp directory for temporary files" +echo "${GREEN} --preferred-language ${MAGENTA}${NORMAL}" +echo " Choose preferred language for messages" +echo " and the main movie (default is \"de\")" +echo "${GREEN} --no-osd-info${NORMAL}" +echo " Don't send messages to the OSD of VDR" +echo "${GREEN} --set-title ${MAGENTA}${NORMAL}" +echo " Set title of main movie to " +echo "${GREEN} --read-title-num ${MAGENTA}${NORMAL}" +echo " Read specific title set (1-99)" +echo "${GREEN} --use-tcextract${NORMAL}" +echo " Demux the main movie with tcextract (default)" +echo "${GREEN} --use-projectX${NORMAL}" +echo " Demux the main movie with projectX." +echo " Ensure to have a X server running" +echo "${GREEN} --projectX-ini ${MAGENTA}${NORMAL}" +echo " Use this X.ini for projectX" +echo "${GREEN} --use-Xvfb | --without-X${NORMAL}" +echo " Start a virtual X Server with Xvfb" +echo "${GREEN} --add-gain ${MAGENTA}${NORMAL}" +echo " Add gain to mp2 audio (-96.0 to +96.0)" +echo "${GREEN} --use-mp2enc${NORMAL}" +echo " Encode the audio track with mp2enc" +echo "${GREEN} --use-toolame${NORMAL}" +echo " Encode the audio track with toolame (default)" +echo "${GREEN} --use-mp3gain${NORMAL}" +echo " Normalize ac3 (time consuming)" +echo "${GREEN} --use-tcmplex${NORMAL}" +echo " Remux with tcmplex (default)" +echo "${GREEN} --use-tcmplex-panteltje${NORMAL}" +echo " Remux with tcmplex-panteltje" +echo "${GREEN} --use-mplex${NORMAL}" +echo " Remux with mplex" +echo "${GREEN} --use-genindex${NORMAL}" +echo " Create index.vdr with genindex (default)" +echo "${GREEN} --use-genindex-mjpegfix${NORMAL}" +echo " Create index.vdr with genindex-mjpegfix" +echo "${GREEN} --force${NORMAL}" +echo " Force execution of " +echo "${GREEN} --verbose${NORMAL}" +echo " Turns verbosity on" +echo "${GREEN} -V | --version${NORMAL}" +echo " Print version information and exit" +echo "${GREEN} --all-versions${NORMAL}" +echo " Print version information of most used tools" +echo "${GREEN} -h | -? | --help${NORMAL}" +echo " Print this usage information" +exit 1 +} + +########################################################################### +# set color parameters +########################################################################### + +# ANSI COLORS +CRE=" +" +NORMAL="" +# RED: Failure or error message +RED="" +# GREEN: Success message +GREEN="" +# YELLOW: Descriptions +YELLOW="" +# BLUE: System messages +BLUE="" +# MAGENTA: Found devices or drivers (pink) +MAGENTA="" +# CYAN: Questions (hellblau) +CYAN="" +# BOLD WHITE: Hint +WHITE="" + +########################################################################### +# check for given parameters +########################################################################### + +case $DEBUG in + 1) ;; + 2) set -x ;; + 3) set -xv ;; + *) LOGFILE=/dev/null ;; +esac + +ACTION="all" +OPTIONS=$@ +TEMPDIR="" +LANGUAGES=("de" "en") +TITLE="" +TITLENUM="AUTO" # AUTO = vobcopy-test; MAX = max. Frames; 1,2,3... DVD-Title +RECORDING="" +AUDIOTRACK=-1 +AUDIOFORMAT="" +TCEXTRACTOPTAUDIO="" +WITHOUT_X=1 +AC3_TRACK=1 + +GETTITLE_TOOLS=("user-input" "vobcopy") +COPY_TOOLS=("tccat") +DEMUX_TOOLS=("tcextract" "projectX") +ENCODE_TOOLS=("mp2enc" "toolame") +MPLEX_TOOLS=("tcmplex" "tcmplex-panteltje" "mplex") +SPLIT_TOOLS=("split") +GENINDEX_TOOLS=("genindex" "genindex-mjpegfix") + +ACTION_GETTITLE=${GETTITLE_TOOLS[1]} +ACTION_COPY=${COPY_TOOLS[0]} +ACTION_DEMUX=${DEMUX_TOOLS[0]} +ACTION_ENCODE=${ENCODE_TOOLS[0]} +ACTION_MPLEX=${MPLEX_TOOLS[1]} +ACTION_SPLIT=${SPLIT_TOOLS[0]} +ACTION_GENINDEX=${GENINDEX_TOOLS[0]} + +while [ $# -gt 0 ]; do + case $1 in + all|gettitle|copy|demux|encode|mplex|split|genindex|move) + ACTION="$1" + ;; + -i|--device) + [ -b "$2" ] || usage "${RED}unknown device ${MAGENTA}'$2'${NORMAL}" + DVD_DEVICE="$2" + shift + ;; + -o) + [ -d "$2" ] || usage "${RED}missing directory ${MAGENTA}'$2'${NORMAL}" + VIDEODIR="$2" + shift + ;; + -w) + [ -d "$2" ] || usage "${RED}missing directory ${MAGENTA}'$2'${NORMAL}" + WORKDIR="$2" + shift + ;; + -t) + [ -d "$2" ] || usage "${RED}missing directory ${MAGENTA}'$2'${NORMAL}" + TEMPDIR=`echo $2 | sed "s/\/$//"` + shift + ;; + --preferred-language) + [ $2 = "" ] || usage "${RED}missing language${NORMAL}" + LANGUAGE=$2 + shift + ;; + --no-osd-info) + OSDINFO=0 + ;; + --set-title) + TITLE=`echo $2 | sed "s/[^a-zA-Z0-9???????/:.#'&_-]/_/g"` + ACTION_GETTITLE=${GETTITLE_TOOLS[0]} + shift + ;; + --read-title-num) +# [ $2 -ge 1 -a $2 -le 99 ] || usage "${RED}invalid title number ${MAGENTA}'$2'${NORMAL}" + TITLENUM=$2 + shift + ;; + --use-tcextract) + ACTION_DEMUX=${DEMUX_TOOLS[0]} + ;; + --use-projectX) + ACTION_DEMUX=${DEMUX_TOOLS[1]} + ;; + --projectX-ini) + [ -e "$2" ] || usage "${RED}missing file ${MAGENTA}'$2'${NORMAL}" + PROJECTX_INI="$2" + shift + ;; + --use-Xvfb|--without-X) + WITHOUT_X=0 + ;; + --add-gain) + [ `echo $2 | \\ + grep -c "[+-][[:digit:]]\{1,2\}\.[[:digit:]]"` -eq 1 ] || \ + usage "${RED}invalid gain ${MAGENTA}'$2'${NORMAL}" + A52DEC_GAIN="$2" + shift + ;; + --use-mp2enc) + ACTION_ENCODE=${ENCODE_TOOLS[0]} + ;; + --use-toolame) + ACTION_ENCODE=${ENCODE_TOOLS[1]} + ;; + --use-tcmplex) + ACTION_MPLEX=${MPLEX_TOOLS[0]} + ;; + --use-tcmplex-panteltje) + ACTION_MPLEX=${MPLEX_TOOLS[1]} + ;; + --use-mplex) + ACTION_MPLEX=${MPLEX_TOOLS[2]} + ;; + --use-genindex) + ACTION_GENINDEX=${GENINDEX_TOOLS[0]} + ;; + --use-genindex-mjpegfix) + ACTION_GENINDEX=${GENINDEX_TOOLS[1]} + ;; + --force) + FORCE=1 + ;; + --clean) + CLEAN=1 + ;; + --verbose) + VERBOSE=1 + ;; + -V|--version) + echo "${GREEN}$0 ${MAGENTA}Version $VERSION${NORMAL}" + exit 1 + ;; + --all-versions) + echo "${GREEN}$0 ${MAGENTA}Version $VERSION${NORMAL}" + echo + $VOBCOPY_BIN --version + $TCPROBE_BIN -v + $TCCAT_BIN -v + $TCEXTRACT_BIN -v + $TCDEMUX_BIN -v + echo + $A52DEC_BIN - 2>&1|grep a52dec + $TOOLAME_BIN --version 2>&1|grep version + echo + $JAVA_BIN -version + echo + $MPLEX_BIN -? 2>&1|grep version + $TCMPLEX_BIN -v + $TCMPLEX_PANTELTJE_BIN -v + echo + $GENINDEX_BIN 2>&1|grep genindex + exit 1 + ;; + -h|-?|--help) + usage + ;; + *) + usage "${RED}unknown option ${MAGENTA}'$1'${NORMAL}" ;; + esac + shift +done + +[ -f "$DVD2VDR_CONF" ] && . "$DVD2VDR_CONF" + + +########################################################################### +# translation tables for user messages +########################################################################### + +LNG=0 +for i in 0 1 ; do + [ $LANGUAGE = ${LANGUAGES[$i]} ] && LNG=$i +done + +MESG_01=( \ +"Bitte die zu wandelne DVD einlegen" \ +"please insert DVD" \ +) + +MESG_02=( \ +"Keine DVD im Laufwerk erkannt" \ +"DVD not found" \ +) + +MESG_03=( \ +"Kopiere DVD auf Disk" \ +"Copy DVD to disk" \ +) + +MESG_04=( \ +"Videospur nicht gefunden - Abbruch" \ +"main movie not found - exiting" \ +) + +MESG_05=( \ +"Tonspur '$LANGUAGE' nicht gefunden - Abbruch" \ +"Audio track '$LANGUAGE' not found - exiting" \ +) + +MESG_06=( \ +"Kein unterstuetztes Audioformat auf der DVD gefunden - Abbruch" \ +"no supported audio format found - exiting" \ +) + +MESG_07=( \ +"Kopieren der DVD gescheitert - Abbruch" \ +"copying of main movie failed - exiting" \ +) + +MESG_08=( \ +"DVD auslesen beendet, bitte DVD entnehmen" \ +"main movie successfully read, please remove DVD" \ +) + +MESG_09=( \ +"Fehler bei der Umwandlung der DVD-Daten - Abbruch" \ +"failed to transcode the main movie - exiting" \ +) + +MESG_10=( \ +"DVD Daten werden mit '$ACTION_DEMUX' bearbeitet" \ +"" \ +) + +MESG_11=( \ +"DVD Daten werden mit '$ACTION_MPLEX' bearbeitet" \ +"" \ +) + +MESG_12=( \ +"DVD Daten werden gesplittet" \ +"" \ +) + +MESG_13=( \ +"DVD Daten werden mit '$ACTION_GENINDEX' bearbeitet" \ +"" \ +) + +MESG_14=( \ +"Alle temp. Daten geloescht" \ +"" \ +) + +MESG_15=( \ +"Daten befinden sich in ${VIDEODIR}" \ +"" \ +) + +MESG_16=( \ +"!!! GRATULATION , FERTIG !!!" \ +"" \ +) + +MESG_30=( \ +"textutils Fehler, update dein coreutils" \ +"error textutils, upgrade your coreutils" \ +) + +########################################################################### +# prepare to run +########################################################################### + +d2v_error () { + echo "${RED}ERROR: ${MAGENTA}$1${NORMAL}" + $EJECT_BIN $DVD_DEVICE + exit 255 +} + + +d2v_log () { + [ $VERBOSE -eq 1 -o "$2" = "force" ] && echo "`date +"%T"`: $1" + echo "`date +"%T"`: $1" >> $LOGFILE +} + + +d2v_log_separator () { + d2v_log "---------------------------------------------------------------" +} + + +d2v_log_force () { + d2v_log "$1" force +} + + +d2v_mesg () { + if [ $OSDINFO -eq 1 ] ; then + d2v_log "$SVDRPSEND_PL MESG $1" + $SVDRPSEND_PL MESG "$1" >> $LOGFILE + fi +} + + +if [ -e $LOCKFILE ] ; then + if [ $FORCE -eq 1 ] ; then + rm -f $LOCKFILE + else + PIDID=`cat $LOCKFILE` + RUNCHECK=`ps $PIDID | grep 'dvd2' | wc -l` + if [ $RUNCHECK -eq 0 ]; then + rm -f $LOCKFILE + d2v_log "dvd2vdr is not active, remove lockfile done" + else + d2v_error "$0 is already running" + fi + fi +fi + +echo "$0 $OPTIONS" > $LOGFILE || d2v_error "${RED}Cannot create \$LOGFILE ${MAGENTA}'$LOGFILE'${NORMAL}" +echo $$ > $LOCKFILE || d2v_error "${RED}Cannot create \$LOCKFILE ${MAGENTA}'$LOCKFILE'${NORMAL}" + +d2v_log_separator +d2v_log_force START + +[ -d $VIDEODIR ] || d2v_error "${RED}\$VIDEODIR ${MAGENTA}'$VIDEODIR' ${RED}not found${NORMAL}" + VIDEODIR=`echo $VIDEODIR | sed "s/\/$//"` +[ -d $WORKDIR ] || d2v_error "${RED}\$WORKDIR ${MAGENTA}'$WORKDIR' ${RED}not found${NORMAL}" + WORKDIR=`echo $WORKDIR | sed "s/\/$//"` +[ -b $DVD_DEVICE ] || d2v_error "${RED}\$DVD_DEVICE ${MAGENTA}'$DVD_DEVICE' ${RED}not found${NORMAL}" + +[ $PRIO -ge 1 -a $PRIO -le 19 ] || \ + d2v_error "${RED}\$PRIO ${MAGENTA}$PRIO ${RED}out of range${NORMAL}" +[ $VERBOSE -ge 0 -a $VERBOSE -le 1 ] || \ + d2v_error "${RED}\$VERBOSE ${MAGENTA}$VERBOSE ${RED}out of range${NORMAL}" + +########################################################################### +# check the temp directory +########################################################################### + +d2v_log_separator +d2v_log_force "checking the temp directory" + +if [ $ACTION = "all" -a -z "$TEMPDIR" ] ; then + TEMPDIR=`mktemp -dp ${WORKDIR}` + d2v_log "\$TEMPDIR='$TEMPDIR' created" +elif [ $ACTION != "all" -a -z "$TEMPDIR" ] ; then + HELP="`echo && echo \$\> ls -d1 ${WORKDIR} && \ + ls -d1 ${WORKDIR}/tmp.* 2> /dev/null`" + [ `ls -d1 ${WORKDIR}/tmp.* 2> /dev/null | wc -l` -ne 1 ] && \ + d2v_error "${RED}no unique temp directory found $HELP${NORMAL}" + TEMPDIR=`ls -d1 ${WORKDIR}/tmp.* | head -n 1` + d2v_log "\$TEMPDIR='$TEMPDIR' used" +else + d2v_log "\$TEMPDIR='$TEMPDIR' used" +fi + + + +########################################################################### +# read and write global variables to disk +########################################################################### + +VARIABLES="TITLE RECORDING TITLENUM AUDIOTRACK AUDIOFORMAT TCEXTRACTOPTAUDIO" + +readvars () { + local FILE=${TEMPDIR}/variables.info + + if [ -f $FILE ] ; then + d2v_log_separator + d2v_log_force "reading file '$FILE'" + + for i in $VARIABLES ; do + if [ "$i" != "TITLE" -o "$TITLE" = "" ] ; then + eval $i=\"`grep "^$i=" $FILE | awk -F = '{print $2}'`\" + eval d2v_log \"\\\$$i=\'$`echo $i`\'\" + fi + done + fi +} + +writevars () { + local FILE=${TEMPDIR}/variables.info + + if [ "$TITLE" != "" -a "$RECORDING" != "" ] ; then + d2v_log_separator + d2v_log_force "writing file '$FILE'" + + echo "LASTRUN=`date +"%Y-%m-%d %T"`" > $FILE || \ + d2v_error "${RED}Cannot create file ${MAGENTA}'$FILE'${NORMAL}" + + for i in $VARIABLES ; do + eval echo "$i=$`echo $i`" >> $FILE + done + fi +} + + +########################################################################### +# gettitle of the main movie +########################################################################### + +gettitle () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_GETTITLE' to get the title of the main movie" + + if [ "$TITLE" = "" -o "$RECORDING" = "" -o $FORCE -eq 1 ] ; then + + # insert DVD and do some checks + d2v_mesg "${MESG_01[$LNG]}" + $EJECT_BIN $DVD_DEVICE + sleep $SLEEPTIME + + local DVDSTATUS=1 + while [ "$DVDSTATUS" -gt 0 ] ; do + $TCPROBE_BIN -i $DVD_DEVICE -H 10 >> $LOGFILE 2>&1> /dev/null + DVDSTATUS=$? + if [ $DVDSTATUS -gt 0 ]; then + d2v_mesg "${MESG_02[$LNG]}" + # insert DVD + d2v_mesg "${MESG_01[$LNG]}" + $EJECT_BIN $DVD_DEVICE + sleep $SLEEPTIME + fi + done + + case $ACTION_GETTITLE in + ${GETTITLE_TOOLS[0]}) + ;; + ${GETTITLE_TOOLS[1]}) + d2v_log "`echo && echo \$\> $VOBCOPY_BIN -i $DVD_DEVICE \ + -v -v -I -L ${TEMPDIR} 2\> /dev/null`" + $VOBCOPY_BIN -i $DVD_DEVICE -v -v -I \ + -L ${TEMPDIR} 2> /dev/null && \ + TITLE=`cat ${TEMPDIR}/vobcopy_*.log | \ + grep 'Name of the dvd' | head -n 1 | awk '{print $6}'` && \ + cat ${TEMPDIR}/vobcopy_*.log >> $LOGFILE + if [ $TITLENUM = "AUTO" ] ; then + TITLENUM=`cat ${TEMPDIR}/vobcopy_*.log | \ + grep 'Using Title' | head -n 1 | awk '{print $4}'` && \ + fi + ;; + esac + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + + TITLE=`echo $TITLE | sed "s/[^a-zA-Z0-9???????/:.#'&_-]/_/g"` + [ `echo $TITLE | wc -m` -le 2 ] && TITLE="DVD`date +%Y-%m-%d-%M-%H`" + + RECORDING="`date +%Y-%m-%d.%H.%M`.99.$RECORDING_LIFETIME.rec" + fi + + d2v_log_force "\$TITLE='$TITLE'" + d2v_log_force "\$TITLENUM='$TITLENUM'" + d2v_log_force "\$RECORDING='$RECORDING'" +} + + +########################################################################### +# test for the main movie +########################################################################### + +test () { + d2v_log_separator + d2v_log_force \ + "using 'tcprobe' to test for the main movie" + + if [ ! -f ${TEMPDIR}/001.vob -o $FORCE -eq 1 -o \ + $AUDIOTRACK -lt 0 -o "$AUDIOFORMAT" = "" -o \ + "$TCEXTRACTOPTAUDIO" = "" ] ; then + + # find main movie + local MAX_TITLENUM=0 + + d2v_log "`echo && echo \$\> $TCPROBE_BIN -H 0 \ + -i $DVD_DEVICE 2\>\&1 \| grep 'title 1/' \| awk '{print $5}'`" + + MAX_TITLENUM=`$TCPROBE_BIN -H 0 -i $DVD_DEVICE 2>&1 | \ + grep 'title 1/' | awk '{print $5}'` + + if [ $MAX_TITLENUM -eq 0 ] ; then + d2v_mesg "${MESG_04[$LNG]}" + $TCPROBE_BIN -H 0 -i $DVD_DEVICE 2>&1 >> $LOGFILE + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${RED}exiting${NORMAL}" + fi + + d2v_log "\$MAX_TITLENUM='$MAX_TITLENUM'" + + local i=0 + local FRAMES=0 + local MAX_FRAMES=0 + + if [ $TITLENUM = "MAX" ] ; then + while [ "$i" -lt $MAX_TITLENUM ] ; do + i=$((i+1)) + FRAMES=`$TCPROBE_BIN -i $DVD_DEVICE -H 10 -T $i \ + 2>/dev/null | grep 'frames' | awk '{print $3}'` + [ -z $FRAMES ] && FRAMES="0" + if [ $FRAMES -gt $MAX_FRAMES ] ; then + if [ $FRAMES -gt $((${TITLE_MIN_LENGTH}*25)) ]; then + TITLENUM="$i" + MAX_FRAMES="$FRAMES" + fi + fi + done + fi + + d2v_log "\$MAX_FRAMES='$MAX_FRAMES'" + + if [ $TITLENUM = "MAX" ]; then + d2v_mesg "${MESG_04[$LNG]}" + $TCPROBE_BIN -H 0 -i $DVD_DEVICE 2>&1 >> $LOGFILE + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${RED}exiting${NORMAL}" + fi + + d2v_log "\$TITLENUM='$TITLENUM'" + + # create the marks.vdr + + if [ $CREATE_MARKS -eq 1 ]; then + d2v_log "`echo && echo \$\> $TCPROBE_BIN -i $DVD_DEVICE -H 10 \ + -T $TITLENUM 2\>\&1 \| grep Chapter \| cut -d \\\" \\\" -f 4 \ + \> ${TEMPDIR}/marks.vdr`" + $TCPROBE_BIN -i $DVD_DEVICE -H 10 -T $TITLENUM 2>&1 | \ + grep Chapter | cut -d " " -f 4 > ${TEMPDIR}/marks.vdr + fi + + # read audio track + local AUDIOTYPE="" + local AUDIOTYPELINES=0 + local AUDIOFORMATLINES=0 + + d2v_log "`echo && echo \$\> $TCPROBE_BIN -i $DVD_DEVICE -H 10 \ + -T $TITLENUM 2\> /dev/null \| grep dvd_reader.c \| grep kHz \| \ + cat -b - \> ${TEMPDIR}/transcode-audio.log`" + $TCPROBE_BIN -i $DVD_DEVICE -H 10 -T $TITLENUM 2> /dev/null | \ + grep dvd_reader.c | \ + grep kHz | cat -b - > ${TEMPDIR}/transcode-audio.log + + d2v_log "`echo && echo \$\> $TCPROBE_BIN -i $DVD_DEVICE -H 10 \ + -T $TITLENUM 2\> /dev/null \| grep "audio track:" \ + cat -b - \> ${TEMPDIR}/transcode-audio2.log`" + $TCPROBE_BIN -i $DVD_DEVICE -H 10 -T $TITLENUM 2> /dev/null | \ + grep "audio track:" | cat -b - > ${TEMPDIR}/transcode-audio2.log + + AUDIOTRACK=`cat ${TEMPDIR}/transcode-audio.log | \ + grep -n " "$LANGUAGE" " | grep "ac3" | head -n 1 | \ + awk '{print (($1-1))}'` + + if [ -z $AUDIOTRACK ] ; then + AUDIOTRACK=`cat ${TEMPDIR}/transcode-audio.log | grep -n " "$LANGUAGE" " | \ + head -n 1 | awk '{print (($1-1))}'` + if [ -z $AUDIOTRACK ] ; then + AUDIOTRACK=-1 + fi + fi + + AUDIOTYPE=`cat ${TEMPDIR}/transcode-audio.log | \ + grep " "$LANGUAGE" " | head -n 1 | awk '{print $3}'` + AUDIOTYPELINES=`cat ${TEMPDIR}/transcode-audio.log | \ + grep " "$LANGUAGE" " | head -n 1 | awk '{print $3}' | \ + wc -m | awk '{print $1}'` + AUDIOFORMATLINES=`cat ${TEMPDIR}/transcode-audio2.log | \ + grep "0x55"| head -n 1 | wc -m | awk '{print $1}'` + TRANSCODE_AUDIO=`cat ${TEMPDIR}/transcode-audio.log` + TRANSCODE_AUDIO2=`cat ${TEMPDIR}/transcode-audio2.log` + + if [ -z $AUDIOTYPELINES ] ; then + d2v_mesg "${MESG_30[$LNG]}" + $TRANSCODE_AUDIO >> $LOGFILE + $TRANSCODE_AUDIO2 >> $LOGFILE + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${RED}exiting${NORMAL}" + fi + + if [ $AUDIOTYPELINES -eq 0 ] ; then + d2v_mesg "${MESG_05[$LNG]}" + $TRANSCODE_AUDIO >> $LOGFILE + $TRANSCODE_AUDIO2 >> $LOGFILE + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${RED}exiting${NORMAL}" + fi + + + [ -z $AUDIOFORMATLINES ] && $AUDIOFORMATLINES="0" + if [ $AUDIOFORMATLINES -eq 0 ] ; then + AUDIOFORMAT="other" + else + AUDIOFORMAT="mp3" + fi + + if [ $DEBUG -gt 1 ] ; then + d2v_log_separator + d2v_log_force "write output from transcode-audio.log" + d2v_log "\$TRANSCODE_AUDIO='$TRANSCODE_AUDIO'" + d2v_log_separator + d2v_log_separator + d2v_log_force "write output from transcode-audio2.log" + d2v_log "\$TRANSCODE_AUDIO2='$TRANSCODE_AUDIO2'" + d2v_log_separator + fi + + d2v_log_force "\$AUDIOTRACK='$AUDIOTRACK'" + d2v_log "\$AUDIOTYPE='$AUDIOTYPE'" + d2v_log "\$AUDIOTYPELINES='$AUDIOTYPELINES'" + d2v_log_force "\$AUDIOFORMAT='$AUDIOFORMAT'" + d2v_log "\$AUDIOFORMATLINES='$AUDIOFORMATLINES'" + + case $AUDIOTYPE in + a??) + TCEXTRACTOPTAUDIO="ac3" + ;; + *pcm|raw) + TCEXTRACTOPTAUDIO="pcm" + if [ ACTION_ENCODE != ${ENCODE_TOOLS[1]} ] ; then + ACTION_ENCODE=${ENCODE_TOOLS[1]} + d2v_log "pcm audio track found - \ + forced the usage of '$ACTION_ENCODE'" + fi + ;; + mpeg?) + TCEXTRACTOPTAUDIO="mp2" + ;; + dts) + TCEXTRACTOPTAUDIO="dts" + ;; + *) + d2v_mesg "${MESG_06[$LNG]}" + cat $TRANSCODE_AUDIO >> $LOGFILE + cat $TRANSCODE_AUDIO2 >> $LOGFILE + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${RED}exiting${NORMAL}" + ;; + esac + + d2v_log_force "\$TCEXTRACTOPTAUDIO='$TCEXTRACTOPTAUDIO'" + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + else + d2v_log_force "\$AUDIOTRACK='$AUDIOTRACK'" + d2v_log_force "\$AUDIOFORMAT='$AUDIOFORMAT'" + d2v_log_force "\$TCEXTRACTOPTAUDIO='$TCEXTRACTOPTAUDIO'" + fi +} + + +########################################################################### +# copy the main movie to disk +########################################################################### + +copy () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_COPY' to copy the main movie to disk" + + if [ ! -f ${TEMPDIR}/001.vob -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/001.vob ] && rm -f ${TEMPDIR}/001.vob + + # read main movie off the DVD + d2v_mesg "${MESG_03[$LNG]} TITEL: $TITLE NUM: $TITLENEM AUDIO: $TCEXTRACTOPTAUDIO" + + d2v_log "`echo && echo \$\> $TCCAT_BIN -t dvd -i $DVD_DEVICE \ + -T $TITLENUM,-1 -L 2\> /dev/null \> ${TEMPDIR}/001.vob`" + nice -n ${PRIO} $TCCAT_BIN -t dvd -i $DVD_DEVICE -T $TITLENUM,-1 \ + -L 2> /dev/null > ${TEMPDIR}/001.vob + + local STATUS=$? + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_07[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$TCCAT_BIN ${RED}failed - exiting${NORMAL}" + fi + + # eject DVD + d2v_mesg "${MESG_08[$LNG]}" + $EJECT_BIN $DVD_DEVICE + sleep $SLEEPTIME + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + + if [ $AUDIOFORMAT = "mp3" ] ; then + d2v_log "`echo && echo \$\> mv ${TEMPDIR}/001.vob \ + ${TEMPDIR}/001.mpeg`" && \ + mv ${TEMPDIR}/001.vob ${TEMPDIR}/001.mpeg + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + fi + if [ $AUDIOFORMAT = "other" -a "$TCEXTRACTOPTAUDIO" = "mp2" ] ; then + d2v_log "cho && echo \$\> mv ${TEMPDIR}/001.vob \ + ${TEMPDIR}/001.mpeg" && \ + mv ${TEMPDIR}/001.vob ${TEMPDIR}/001.mpeg + d2v_log "cho && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}" + fi + + + fi +} + + +########################################################################### +# demultiplex the main movie in mpv and ac3 +########################################################################### + +demux () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_DEMUX' to demultiplex the main movie in mpv and ac3" + + if [ ! -f ${TEMPDIR}/001.vob ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.vob' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.mpv -o ! -f ${TEMPDIR}/001.ac3 -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/001.mpv ] && rm -f ${TEMPDIR}/001.mpv + [ -f ${TEMPDIR}/001.ac3 ] && rm -f ${TEMPDIR}/001.ac3 + rm -f ${TEMPDIR}/video.fifo + rm -f ${TEMPDIR}/audio.fifo + + local STATUS=1 + + if [ "$AUDIOFORMAT" != "mp3" ] ; then + case $ACTION_DEMUX in + ${DEMUX_TOOLS[0]}) + + # demux using fifos and tcextract + d2v_mesg "${MESG_10[$LNG]}" + mkfifo ${TEMPDIR}/video.fifo + mkfifo ${TEMPDIR}/audio.fifo + + d2v_log "`echo && echo \$\> $TCEXTRACT_BIN -i \ + ${TEMPDIR}/video.fifo -t vob -x mpeg2 -a 0xe0 \ + \> ${TEMPDIR}/001.mpv \&`" + + nice -n ${PRIO} $TCEXTRACT_BIN -i ${TEMPDIR}/video.fifo \ + -t vob -x mpeg2 -a 0xe0 \ + > ${TEMPDIR}/001.mpv & + + d2v_log "`echo && echo \$\> $TCEXTRACT_BIN -i \ + ${TEMPDIR}/audio.fifo -t vob -x ${TCEXTRACTOPTAUDIO} \ + -a $AUDIOTRACK \> ${TEMPDIR}/001.ac3 \&`" + nice -n ${PRIO} $TCEXTRACT_BIN -i ${TEMPDIR}/audio.fifo \ + -t vob -x ${TCEXTRACTOPTAUDIO} -a ${AUDIOTRACK} \ + > ${TEMPDIR}/001.ac3 & + + sleep 5 + d2v_log "`echo && echo \$\> cat ${TEMPDIR}/001.vob \| \ + tee ${TEMPDIR}/video.fifo ${TEMPDIR}/audio.fifo \ + \> /dev/null`" + nice -n ${PRIO} cat ${TEMPDIR}/001.vob | \ + tee ${TEMPDIR}/audio.fifo ${TEMPDIR}/video.fifo \ + > /dev/null + + STATUS=$? + ;; + ${DEMUX_TOOLS[1]}) + + if [ $WITHOUT_X -eq 0 ] ; then + # start virtual X server + $XVFB_BIN -once :4 >/dev/null 2>&1 & + export DISPLAY=localhost:4 + fi + + export LANG=de_DE@euro + + # demux using projectX + d2v_log "`echo && echo \$\> $JAVA_BIN -jar $PROJECTX_JAR \ + -c $PROJECTX_INI -o ${TEMPDIR} \ + ${TEMPDIR}/001.vob 2\>\&1 \>\> $LOGFILE`" + nice -n ${PRIO} $JAVA_BIN -jar $PROJECTX_JAR \ + -c $PROJECTX_INI -o ${TEMPDIR} \ + ${TEMPDIR}/001.vob 2>&1 >> $LOGFILE + + STATUS=$? + + if [ $WITHOUT_X -eq 0 ] ; then + # stop Virtual X server + /usr/bin/killall Xvfb + fi + ;; + esac + + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$ACTION_DEMUX ${RED}failed - exiting${NORMAL}" + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + else + d2v_log "demultiplexing not required - \ + main movie contains mp2 audio track" + fi + fi + [ $REMOVE -eq 1 ] && rm -f ${TEMPDIR}/001.vob +} + + +########################################################################### +# encode ac3 to mp2 +########################################################################### + +encode () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_ENCODE' to encode ac3 to mp2" + + if [ ! -f ${TEMPDIR}/001.ac3 ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.ac3' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.mp2 -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/001.mp2 ] && rm -f ${TEMPDIR}/001.mp2 + + local STATUS=1 + + if [ "$AUDIOFORMAT" != "mp3" ] ; then + + if [ "$TCEXTRACTOPTAUDIO" = "pcm" ] ; then + d2v_log "pcm or raw audio track move to wav audio track" + mv ${TEMPDIR}/001.ac3 ${TEMPDIR}/001.wav + fi + + if [ "$TCEXTRACTOPTAUDIO" != "pcm" ] ; then + # encode with a52dec ... + d2v_log "`echo && echo \$\> $A52DEC_BIN -o wavdolby \ + -g "$A52DEC_GAIN" ${TEMPDIR}/001.ac3 \ + 2\>\&1 \> ${TEMPDIR}/001.wav \| grep -v \'last\' \ + \>\> $LOGFILE`" + nice -n ${PRIO} $A52DEC_BIN -o wavdolby \ + -g "$A52DEC_GAIN" ${TEMPDIR}/001.ac3 \ + 2>&1 > ${TEMPDIR}/001.wav | grep -v 'last' \ + >> $LOGFILE + STATUS=$? + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$A52DEC_BIN ${RED}failed - exiting${NORMAL}" + fi + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + + case $ACTION_ENCODE in + ${ENCODE_TOOLS[0]}) + + # ... and mp2enc + d2v_log "`echo && echo \$\> cat ${TEMPDIR}/001.wav \| \ + $MP2ENC_BIN -r 48000 -o ${TEMPDIR}/001.mp2 \ + \> /dev/null 2\>\> $LOGFILE`" + nice -n ${PRIO} cat ${TEMPDIR}/001.wav | \ + $MP2ENC_BIN -r 48000 -o ${TEMPDIR}/001.mp2 \ + > /dev/null 2>> $LOGFILE + STATUS=$? + ;; + ${ENCODE_TOOLS[1]}) + + # ... and toolame + d2v_log "`echo && echo \$\> cat ${TEMPDIR}/001.wav \| \ + $TOOLAME_BIN -s 48 /dev/stdin ${TEMPDIR}/001.mp2 \ + \> /dev/null 2\>\> $LOGFILE`" + nice -n ${PRIO} cat ${TEMPDIR}/001.wav | \ + $TOOLAME_BIN -s 48 /dev/stdin ${TEMPDIR}/001.mp2 \ + > /dev/null 2>> $LOGFILE + STATUS=$? + ;; + esac + + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$ACTION_ENCODE ${RED}failed - exiting${NORMAL}" + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + else + d2v_log "encoding not required - \ + main movie contains mp2 audio track" + fi + fi + [ $REMOVE -eq 1 ] && rm -f ${TEMPDIR}/001.wav +} + + +########################################################################### +# multiplex the parts to a VDR recording +########################################################################### + +mplex () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_MPLEX' to multiplex the part to a VDR recording" + + if [ ! -f ${TEMPDIR}/001.mpv ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.mpv' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.ac3 ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.ac3' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.mp2 ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.mp2' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.mpeg -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/001.mpeg ] && rm -f ${TEMPDIR}/001.mpeg + + if [ "$AUDIOFORMAT" != "mp3" ] ; then + + local STATUS=1 + + d2v_mesg "${MESG_11[$LNG]}" + + case $ACTION_MPLEX in + ${MPLEX_TOOLS[0]}) + [ $AC3_TRACK -eq 1 ] && \ + INC_AC3_TRACK="-s ${TEMPDIR}/001.ac3" + + # tcmplex a MPEG file + d2v_log "`echo && echo \$\> $TCMPLEX_BIN -m 2 \ + -i ${TEMPDIR}/001.mpv -p ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2\>\&1 \| grep -v \'%\' - \>\> $LOGFILE`" + nice -n ${PRIO} $TCMPLEX_BIN -m 2 \ + -i ${TEMPDIR}/001.mpv -p ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2>&1 | grep -v '%' - >> $LOGFILE + STATUS=$? + ;; + ${MPLEX_TOOLS[1]}) + [ $AC3_TRACK -eq 1 ] && \ + INC_AC3_TRACK="-1 ${TEMPDIR}/001.ac3" + + # tcmplex-panteltje a MPEG file + d2v_log "`echo && echo \$\> $TCMPLEX_PANTELTJE_BIN -m 2 \ + -i ${TEMPDIR}/001.mpv -0 ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2\>\&1 \| grep -v \'%\' - \>\> $LOGFILE`" + nice -n ${PRIO} $TCMPLEX_PANTELTJE_BIN -m 2 \ + -i ${TEMPDIR}/001.mpv -0 ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2>&1 | grep -v '%' - >> $LOGFILE + STATUS=$? + ;; + ${MPLEX_TOOLS[2]}) + [ $AC3_TRACK -eq 1 ] && \ + INC_AC3_TRACK="${TEMPDIR}/001.ac3" + + # mplex a MPEG file + d2v_log "`echo && echo \$\> $MPLEX_BIN -f 9 \ + ${TEMPDIR}/001.mpv ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2\>\&1 \| grep -v \'%\' - \>\> $LOGFILE`" + nice -n ${PRIO} $TCMPLEX_BIN -f 9 \ + ${TEMPDIR}/001.mpv ${TEMPDIR}/001.mp2 \ + $INC_AC3_TRACK -o ${TEMPDIR}/001.mpeg \ + 2>&1 | grep -v '%' - >> $LOGFILE + STATUS=$? + ;; + esac + + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$ACTION_MPLEX ${RED}failed - exiting${NORMAL}" + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + else + d2v_log "multiplexing not required - \ + main movie contains mp2 audio track" + fi + fi + [ $REMOVE -eq 1 ] && rm -f ${TEMPDIR}/001.mpv ${TEMPDIR}/001.ac3 ${TEMPDIR}/001.mp2 +} + + +########################################################################### +# split the VDR recording into chunks +########################################################################### + +split () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_SPLIT' to split the VDR recording into chunks" + + d2v_mesg "${MESG_12[$LNG]}" + + if [ ! -f ${TEMPDIR}/001.mpeg ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.mpeg' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/001.vdr -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/002.vdr ] && rm -f ${TEMPDIR}/???.vdr + [ -f ${TEMPDIR}/001.mpeg.* ] && rm -f ${TEMPDIR}/001.mpeg.* + + local FILESIZE=`ls -l ${TEMPDIR}/001.mpeg | awk '{print $5}'` + + if [ $FILESIZE -gt $RECORDING_MAX_SIZE ] ; then + d2v_log "`echo && echo \$\> $SPLIT_BIN -b $RECORDING_MAX_SIZE \ + ${TEMPDIR}/001.mpeg ${TEMPDIR}/001.vdr.`" + nice -n ${PRIO} $SPLIT_BIN -b $RECORDING_MAX_SIZE \ + ${TEMPDIR}/001.mpeg ${TEMPDIR}/001.mpeg. + + local STATUS=$? + if [ $STATUS -eq 1 ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$ACTION_SPLIT ${RED}failed - exiting${NORMAL}" + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && \ + ls -l ${TEMPDIR}`" + + local NEWNAME=0 + for DNAME in ${TEMPDIR}/001.mpeg.* ; do + NEWNAME=`echo $NEWNAME | awk '{printf "%03d",$1+1}'` + mv $DNAME ${TEMPDIR}/$NEWNAME.vdr + + if [ $NEWNAME -gt $RECORDING_MAX_CHUNKS ] ; then + d2v_mesg "${MESG_09[$LNG]}" + cp $LOGFILE ${TEMPDIR}/$TITLE.log + d2v_error "${MAGENTA}$RECORDING_MAX_CHUNKS ${RED}to many chunks - exiting${NORMAL}" + fi + done + else + mv ${TEMPDIR}/001.mpeg ${TEMPDIR}/001.vdr + fi + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" +} + + +########################################################################### +# create an index.vdr +########################################################################### + +genindex () { + d2v_log_separator + d2v_log_force \ + "using '$ACTION_GENINDEX' to create an index.vdr" + + if [ ! -f ${TEMPDIR}/001.vdr ] ; then + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_error "${MAGENTA}'${TEMPDIR}/001.vdr' ${RED}not found${NORMAL}" + fi + + if [ ! -f ${TEMPDIR}/index.vdr -o $FORCE -eq 1 ] ; then + + # clean up + [ -f ${TEMPDIR}/index.vdr ] && rm -f ${TEMPDIR}/index.vdr + + cd ${TEMPDIR} + + case $ACTION_GENINDEX in + ${GENINDEX_TOOLS[0]}) + d2v_log "`echo && echo \$\> $GENINDEX_BIN 2\>\&1 \| \ + grep -v \'%\' - \>\> $LOGFILE`" + nice -n ${PRIO} $GENINDEX_BIN 2>&1 | \ + grep -v '%' - >> $LOGFILE + ;; + ${GENINDEX_TOOLS[1]}) + d2v_log "`echo && echo \$\> $GENINDEX_MJPEGFIX_BIN 2\>\&1 \| \ + grep -v \'I-Frame\' - \>\> $LOGFILE`" + nice -n ${PRIO} $GENINDEX_MJPEGFIX_BIN 2>&1 | \ + grep -v 'I-Frame' - >> $LOGFILE + ;; + esac + fi + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" +} + + +########################################################################### +# move recording to video directory +########################################################################### + +move () { + d2v_log_separator + d2v_log_force \ + "using 'mv' to move recording to video directory" + + mkdir -p ${VIDEODIR}/${TITLE}/${RECORDING} >> $LOGFILE || \ + d2v_error "${RED}failed to create ${MAGENTA}'${VIDEODIR}/${TITLE}/${RECORDING}'${NORMAL}" + d2v_log "'${VIDEODIR}/${TITLE}/${RECORDING}' created" + + mv ${TEMPDIR}/*.vdr ${VIDEODIR}/${TITLE}/${RECORDING} + + d2v_log "`echo && echo \$\> ls -l ${TEMPDIR} && ls -l ${TEMPDIR}`" + d2v_log "`echo && echo \$\> ls -l ${VIDEODIR}/${TITLE}/${RECORDING} && \ + ls -l ${VIDEODIR}/${TITLE}/${RECORDING}`" +} + + +########################################################################### +# do all the bits +########################################################################### + +if [ $ACTION = "copy" ] ; then + gettitle + test + eval $ACTION +fi + + +if [ $ACTION = "all" ] ; then + readvars + gettitle + test + copy + if [ "$AUDIOFORMAT" = "mp3" ] ; then + split + genindex + move + elif [ "$AUDIOFORMAT" = "other" -a "$TCEXTRACTOPTAUDIO" = "mp2" ] ; then + split + genindex + move + else + demux + encode + mplex + split + genindex + move + fi +fi + +writevars + + +########################################################################### +# yeeha, we did it +########################################################################### + +[ $ACTION = "all" -a $CLEAN = 1 ] && rm -rf $TEMPDIR && d2v_log "\$TEMPDIR '$TEMPDIR' deleted" + +rm -f $LOCKFILE + +d2v_log_separator +d2v_log_force END +d2v_log_separator diff --git a/dvdauthor_helperfunctions.sh b/dvdauthor_helperfunctions.sh new file mode 100755 index 0000000..10f6855 --- /dev/null +++ b/dvdauthor_helperfunctions.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# +# (P) & (C) 2003 by Dr. Peter Bieringer +# +# Original site of publishing: +# ftp://ftp.bieringer.de/pub/linux/dvd/dvdauthor-addons/ +# +# License: GPLv2 +# +# Requires: +# - gozer, imlib2, netpbm-progs +# +# ChangeLog +# 20030510/PB: initial creation +# 20030511/PB: import info function + +. ~/.vdrconvert/vdrconvert.env + +##### Functions ###### + +# Put text into a bitmap +put_text() { + local file="$1"; shift + if [ ! -z "$PATH_FONTS" -a ! -z "$DVD_USE_FONT" ] + then + local font="$1" + shift + fi + local color_bg="$1"; shift + local color_fg="$1"; shift + local loc_x="$1"; shift + local loc_y="$1"; shift + local text="$1"; shift + local rest="$*" + + local tmp_png="tmp-txt.png" + local tmp_pnm="tmp-txt.pnm" + local tmp_alphapnm="tmp-txt.alpha.pnm" + local tmp_output="tmp-output.pnm" + if [ ! -w "." ]; then + echo "ERR(put_text): file not writable: $file" + return 1 + fi + + [ ! -z "$RECODE" ] && rtext="`echo $text | $RECODE`" || rtext=$text + if [ -z "$PATH_FONTS" -o -z "$DVD_USE_FONT" ] + then + #set -x + gozer --background $color_bg --foreground $color_fg --text "$rtext" $rest $tmp_png + else + gozer --fontpath $PATH_FONTS --font $font --background $color_bg --foreground $color_fg --text "$rtext" $rest $tmp_png + #set +x + fi + + pngtopnm $tmp_png >$tmp_pnm + pngtopnm -alpha $tmp_png >$tmp_alphapnm + + pnmcomp -xoff=$loc_x -yoff=$loc_y -alpha=$tmp_alphapnm $tmp_pnm $file >$tmp_output + mv $tmp_output $file + + rm -f $tmp_png $tmp_pnm $tmp_alphapnm $tmp_output +} + +# Put a bitmap file into another bitmap file +put_file() { + local file=$1 + local loc_x=$2 + local loc_y=$3 + local file2=$4 + + local tmp_pnm="tmp-txt.pnm" + + if [ ! -w "." ]; then + echo "ERR(put_file): file not writable: $file" + return 1 + fi + if [ ! -r "$file2" ]; then + echo "ERR(put_file): file not readable: $file2" + return 1 + fi + + pnmcomp -xoff=$loc_x -yoff=$loc_y $file2 $file >$tmp_pnm + mv $tmp_pnm $file + + rm -f $tmp_pnm +} diff --git a/dvddirdel b/dvddirdel new file mode 100755 index 0000000..42a3a43 --- /dev/null +++ b/dvddirdel @@ -0,0 +1,41 @@ +#!/bin/sh + +if [ -f /usr/local/etc/dvdauthor.conf ]; then + . /usr/local/etc/dvdauthor.conf +fi + +if [ -f ~/.dvdauthorrc ]; then + . ~/.dvdauthorrc +fi + +help=0 +out=0 +for i in "$@"; do + if [ $out = 1 ]; then + WORKDIR="$i" + out=0 + elif [ "x$i" = "x-h" ]; then + help=1 + elif [ "x$i" = "x-o" ]; then + out=1 + fi +done + +if [ $help = 1 -o "x$WORKDIR" = "x" ]; then + echo "DVDAuthor, version 0.6.18. Send bugs to " + echo "syntax: dvddirdel [-o DIR]" + echo " deletes a previously authored DVD directory structure in DIR" + exit 1 +fi + +if [ -d "$WORKDIR" ]; then + rm -f "$WORKDIR/VIDEO_TS"/VIDEO_TS.VOB + rm -f "$WORKDIR/VIDEO_TS"/VIDEO_TS.IFO + rm -f "$WORKDIR/VIDEO_TS"/VIDEO_TS.BUP + rm -f "$WORKDIR/VIDEO_TS"/VTS_??_?.VOB + rm -f "$WORKDIR/VIDEO_TS"/VTS_??_0.IFO + rm -f "$WORKDIR/VIDEO_TS"/VTS_??_0.BUP + rmdir "$WORKDIR/VIDEO_TS" + rmdir "$WORKDIR/AUDIO_TS" + rmdir "$WORKDIR" +fi diff --git a/dvdunauthor b/dvdunauthor new file mode 100755 index 0000000000000000000000000000000000000000..048da77c8501bab14568d07f7a3110a7d2157f5f GIT binary patch literal 158013 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%0A^^+zo3)*rFBTYtpj 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 literal 0 HcmV?d00001 diff --git a/fv_html b/fv_html new file mode 100755 index 0000000..b718d4a --- /dev/null +++ b/fv_html @@ -0,0 +1,5 @@ +#!/bin/bash + +arg=$1 + +/home/marc/bin/fv $1 | awk '{printf("

%s

\n", $0);}' diff --git a/getrecnames.sh b/getrecnames.sh new file mode 100644 index 0000000..fb5fd77 --- /dev/null +++ b/getrecnames.sh @@ -0,0 +1,18 @@ + +hd=/media/test +videodir=/video/ + +recdirs=$(find . -name "*.rec") + +echo $recdirs +for i in $recdirs +do + echo rec:$i + recdir=$(basename "$i") + dirv=$(find $videodir -name "$recdir") + d=$(echo $dirv | awk -F/ '{print $(NF-1)}') + echo "$dirv = $d" + mkdir -p $hd/$d + mv $i $hd/$d + +done diff --git a/git-prompt.sh b/git-prompt.sh new file mode 100755 index 0000000..41aa587 --- /dev/null +++ b/git-prompt.sh @@ -0,0 +1,707 @@ + + # don't set prompt if this is not interactive shell + [[ $- != *i* ]] && return + +################################################################### CONFIG + + ##### read config file if any. + + unset dir_color rc_color user_id_color root_id_color init_vcs_color clean_vcs_color + unset modified_vcs_color added_vcs_color addmoded_vcs_color untracked_vcs_color op_vcs_color detached_vcs_color hex_vcs_color + unset rawhex_len + + conf=git-prompt.conf; [[ -r $conf ]] && . $conf + conf=/etc/git-prompt.conf; [[ -r $conf ]] && . $conf + conf=~/.git-prompt.conf; [[ -r $conf ]] && . $conf + conf=~/.config/git-prompt.conf; [[ -r $conf ]] && . $conf + unset conf + + + ##### set defaults if not set + + git_module=${git_module:-on} + svn_module=${svn_module:-off} + hg_module=${hg_module:-on} + vim_module=${vim_module:-on} + error_bell=${error_bell:-off} + cwd_cmd=${cwd_cmd:-\\w} + + + #### dir, rc, root color + cols=`tput colors` # in emacs shell-mode tput colors returns -1 + if [[ -n "$cols" && $cols -ge 8 ]]; then # if terminal supports colors + dir_color=${dir_color:-CYAN} + rc_color=${rc_color:-red} + user_id_color=${user_id_color:-blue} + root_id_color=${root_id_color:-magenta} + else # only B/W + dir_color=${dir_color:-bw_bold} + rc_color=${rc_color:-bw_bold} + fi + unset cols + + #### prompt character, for root/non-root + prompt_char=${prompt_char:-'>'} + root_prompt_char=${root_prompt_char:-'>'} + + #### vcs colors + init_vcs_color=${init_vcs_color:-WHITE} # initial + clean_vcs_color=${clean_vcs_color:-blue} # nothing to commit (working directory clean) + modified_vcs_color=${modified_vcs_color:-red} # Changed but not updated: + added_vcs_color=${added_vcs_color:-green} # Changes to be committed: + addmoded_vcs_color=${addmoded_vcs_color:-yellow} + untracked_vcs_color=${untracked_vcs_color:-BLUE} # Untracked files: + op_vcs_color=${op_vcs_color:-MAGENTA} + detached_vcs_color=${detached_vcs_color:-RED} + + hex_vcs_color=${hex_vcs_color:-BLACK} # gray + + + max_file_list_length=${max_file_list_length:-100} + short_hostname=${short_hostname:-off} + upcase_hostname=${upcase_hostname:-on} + count_only=${count_only:-off} + rawhex_len=${rawhex_len:-5} + + aj_max=20 + + +##################################################################### post config + + ################# make PARSE_VCS_STATUS + unset PARSE_VCS_STATUS + [[ $git_module = "on" ]] && type git >&/dev/null && PARSE_VCS_STATUS+="parse_git_status" + [[ $svn_module = "on" ]] && type svn >&/dev/null && PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}parse_svn_status" + [[ $hg_module = "on" ]] && type hg >&/dev/null && PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}parse_hg_status" + PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}return" + ################# terminfo colors-16 + # + # black? 0 8 + # red 1 9 + # green 2 10 + # yellow 3 11 + # blue 4 12 + # magenta 5 13 + # cyan 6 14 + # white 7 15 + # + # terminfo setaf/setab - sets ansi foreground/background + # terminfo sgr0 - resets all attributes + # terminfo colors - number of colors + # + ################# Colors-256 + # To use foreground and background colors: + # Set the foreground color to index N: \033[38;5;${N}m + # Set the background color to index M: \033[48;5;${M}m + # To make vim aware of a present 256 color extension, you can either set + # the $TERM environment variable to xterm-256color or use vim's -T option + # to set the terminal. I'm using an alias in my bashrc to do this. At the + # moment I only know of two color schemes which is made for multi-color + # terminals like urxvt (88 colors) or xterm: inkpot and desert256, + + ### if term support colors, then use color prompt, else bold + + black='\['`tput sgr0; tput setaf 0`'\]' + red='\['`tput sgr0; tput setaf 1`'\]' + green='\['`tput sgr0; tput setaf 2`'\]' + yellow='\['`tput sgr0; tput setaf 3`'\]' + blue='\['`tput sgr0; tput setaf 4`'\]' + magenta='\['`tput sgr0; tput setaf 5`'\]' + cyan='\['`tput sgr0; tput setaf 6`'\]' + white='\['`tput sgr0; tput setaf 7`'\]' + + BLACK='\['`tput setaf 0; tput bold`'\]' + RED='\['`tput setaf 1; tput bold`'\]' + GREEN='\['`tput setaf 2; tput bold`'\]' + YELLOW='\['`tput setaf 3; tput bold`'\]' + BLUE='\['`tput setaf 4; tput bold`'\]' + MAGENTA='\['`tput setaf 5; tput bold`'\]' + CYAN='\['`tput setaf 6; tput bold`'\]' + WHITE='\['`tput setaf 7; tput bold`'\]' + + dim='\['`tput sgr0; tput setaf p1`'\]' # half-bright + + bw_bold='\['`tput bold`'\]' + + on='' + off=': ' + bell="\[`eval ${!error_bell} tput bel`\]" + colors_reset='\['`tput sgr0`'\]' + + # replace symbolic colors names to raw treminfo strings + init_vcs_color=${!init_vcs_color} + modified_vcs_color=${!modified_vcs_color} + untracked_vcs_color=${!untracked_vcs_color} + clean_vcs_color=${!clean_vcs_color} + added_vcs_color=${!added_vcs_color} + op_vcs_color=${!op_vcs_color} + addmoded_vcs_color=${!addmoded_vcs_color} + detached_vcs_color=${!detached_vcs_color} + hex_vcs_color=${!hex_vcs_color} + + unset PROMPT_COMMAND + + ####### work around for MC bug. + ####### specifically exclude emacs, want full when running inside emacs + if [[ -z "$TERM" || ("$TERM" = "dumb" && -z "$INSIDE_EMACS") || -n "$MC_SID" ]]; then + unset PROMPT_COMMAND + PS1="\w$prompt_char " + return 0 + fi + + #################################################################### MARKERS + screen_marker="sCRn" + if [[ $LC_CTYPE =~ "UTF" && $TERM != "linux" ]]; then + elipses_marker="…" + else + elipses_marker="..." + fi + + export who_where + + +cwd_truncate() { + # based on: https://www.blog.montgomerie.net/pwd-in-the-title-bar-or-a-regex-adventure-in-bash + + # arg1: max path lenght + # returns abbrivated $PWD in public "cwd" var + + cwd=${PWD/$HOME/\~} # substitute "~" + + case $1 in + full) + return + ;; + last) + cwd=${PWD##/*/} + [[ $PWD == $HOME ]] && cwd="~" + return + ;; + *) + # if bash < v3.2 then don't truncate + if [[ ${BASH_VERSINFO[0]} -eq 3 && ${BASH_VERSINFO[1]} -le 1 || ${BASH_VERSINFO[0]} -lt 3 ]] ; then + return + fi + ;; + esac + + # split path into: head='~/', truncateble middle, last_dir + + local cwd_max_length=$1 + # expression which bash-3.1 or older can not understand, so we wrap it in eval + exp31='[[ "$cwd" =~ (~?/)(.*/)([^/]*)$ ]]' + if eval $exp31 ; then # only valid if path have more then 1 dir + local path_head=${BASH_REMATCH[1]} + local path_middle=${BASH_REMATCH[2]} + local path_last_dir=${BASH_REMATCH[3]} + + local cwd_middle_max=$(( $cwd_max_length - ${#path_last_dir} )) + [[ $cwd_middle_max < 0 ]] && cwd_middle_max=0 + + + # trunc middle if over limit + if [[ ${#path_middle} -gt $(( $cwd_middle_max + ${#elipses_marker} + 5 )) ]]; then + + # truncate + middle_tail=${path_middle:${#path_middle}-${cwd_middle_max}} + + # trunc on dir boundary (trunc 1st, probably tuncated dir) + exp31='[[ $middle_tail =~ [^/]*/(.*)$ ]]' + eval $exp31 + middle_tail=${BASH_REMATCH[1]} + + # use truncated only if we cut at least 4 chars + if [[ $(( ${#path_middle} - ${#middle_tail})) -gt 4 ]]; then + cwd=$path_head$elipses_marker$middle_tail$path_last_dir + fi + fi + fi + return + } + + +set_shell_label() { + + xterm_label() { + local args="$*" + echo -n "]2;${args:0:200}" ; # FIXME: replace hardcodes with terminfo codes + } + + screen_label() { + # FIXME: run this only if screen is in xterm (how to test for this?) + xterm_label "$screen_marker $plain_who_where $@" + + # FIXME $STY not inherited though "su -" + [ "$STY" ] && screen -S $STY -X title "$*" + } + if [[ -n "$STY" ]]; then + screen_label "$*" + else + case $TERM in + + screen*) + screen_label "$*" + ;; + + xterm* | rxvt* | gnome-terminal | konsole | eterm | wterm ) + # is there a capability which we can to test + # for "set term title-bar" and its escapes? + xterm_label "$plain_who_where $@" + ;; + + *) + ;; + esac + fi + } + + export -f set_shell_label + +###################################################### ID (user name) + id=`id -un` + id=${id#$default_user} + +########################################################### TTY + tty=`tty` + tty=`echo $tty | sed "s:/dev/pts/:p:; s:/dev/tty::" ` # RH tty devs + tty=`echo $tty | sed "s:/dev/vc/:vc:" ` # gentoo tty devs + + if [[ "$TERM" = "screen" ]] ; then + + # [ "$WINDOW" = "" ] && WINDOW="?" + # + # # if under screen then make tty name look like s1-p2 + # # tty="${WINDOW:+s}$WINDOW${WINDOW:+-}$tty" + # tty="${WINDOW:+s}$WINDOW" # replace tty name with screen number + tty="$WINDOW" # replace tty name with screen number + fi + + # we don't need tty name under X11 + case $TERM in + xterm* | rxvt* | gnome-terminal | konsole | eterm* | wterm | cygwin) unset tty ;; + *);; + esac + + dir_color=${!dir_color} + rc_color=${!rc_color} + user_id_color=${!user_id_color} + root_id_color=${!root_id_color} + + ########################################################### HOST + ### we don't display home host/domain $SSH_* set by SSHD or keychain + + # How to find out if session is local or remote? Working with "su -", ssh-agent, and so on ? + + ## is sshd our parent? + # if { for ((pid=$$; $pid != 1 ; pid=`ps h -o pid --ppid $pid`)); do ps h -o command -p $pid; done | grep -q sshd && echo == REMOTE ==; } + #then + + host=${HOSTNAME} + if [[ $short_hostname = "on" ]]; then + host=`hostname -s` + fi + host=${host#$default_host} + uphost=`echo ${host} | tr a-z A-Z` + if [[ $upcase_hostname = "on" ]]; then + host=${uphost} + fi + + host_color=${uphost}_host_color + host_color=${!host_color} + if [[ -z $host_color && -x /usr/bin/cksum ]] ; then + cksum_color_no=`echo $uphost | cksum | awk '{print $1%7}'` + color_index=(green yellow blue magenta cyan white) # FIXME: bw, color-256 + host_color=${color_index[cksum_color_no]} + fi + + host_color=${!host_color} + + # we might already have short host name + host=${host%.$default_domain} + +#################################################################### WHO_WHERE + # [[user@]host[-tty]] + + if [[ -n $id || -n $host ]] ; then + [[ -n $id && -n $host ]] && at='@' || at='' + color_who_where="${id}${host:+$host_color$at$host}${tty:+ $tty}" + plain_who_where="${id}$at$host" + + # add trailing " " + color_who_where="$color_who_where " + plain_who_where="$plain_who_where " + + # if root then make it root_color + if [ "$id" == "root" ] ; then + user_id_color=$root_id_color + prompt_char="$root_prompt_char" + fi + color_who_where="$user_id_color$color_who_where$colors_reset" + else + color_who_where='' + fi + + +parse_svn_status() { + + [[ -d .svn ]] || return 1 + + vcs=svn + + ### get rev + eval ` + svn info | + sed -n " + s@^URL[^/]*//@repo_dir=@p + s/^Revision: /rev=/p + " + ` + ### get status + + unset status modified added clean init added mixed untracked op detached + eval `svn status 2>/dev/null | + sed -n ' + s/^A... \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p + s/^M... \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p + s/^\?... \([^.].*\)/untracked=untracked; untracked_files[${#untracked_files[@]}]=\"\1\";/p + ' + ` + # TODO branch detection if standard repo layout + + [[ -z $modified ]] && [[ -z $untracked ]] && clean=clean + vcs_info=svn:r$rev + } + +parse_hg_status() { + + # ☿ + + [[ -d ./.hg/ ]] || return 1 + + vcs=hg + + ### get status + unset status modified added clean init added mixed untracked op detached + + eval `hg status 2>/dev/null | + sed -n ' + s/^M \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p + s/^A \([^.].*\)/added=added; added_files[${#added_files[@]}]=\"\1\";/p + s/^R \([^.].*\)/added=added;/p + s/^! \([^.].*\)/modified=modified;/p + s/^? \([^.].*\)/untracked=untracked; untracked_files[${#untracked_files[@]}]=\\"\1\\";/p + '` + + branch=`hg branch 2> /dev/null` + + [[ -z $modified ]] && [[ -z $untracked ]] && [[ -z $added ]] && clean=clean + vcs_info=${branch/default/D} + } + + + +parse_git_status() { + + # TODO add status: LOCKED (.git/index.lock) + + git_dir=`[[ $git_module = "on" ]] && git rev-parse --git-dir 2> /dev/null` + #git_dir=`eval \$$git_module git rev-parse --git-dir 2> /dev/null` + #git_dir=` git rev-parse --git-dir 2> /dev/null` + + [[ -n ${git_dir/./} ]] || return 1 + + vcs=git + + ########################################################## GIT STATUS + file_regex='\([^/ ]*\/\{0,1\}\).*' + added_files=() + modified_files=() + untracked_files=() + freshness="$dim" + unset branch status modified added clean init added mixed untracked op detached + + # quoting hell + eval " $( + git status 2>/dev/null | + sed -n ' + s/^# On branch /branch=/p + s/^nothing to commi.*/clean=clean/p + s/^# Initial commi.*/init=init/p + + s/^# Your branch is ahead of .[/[:alnum:]]\+. by [[:digit:]]\+ commit.*/freshness=${WHITE}↑/p + s/^# Your branch is behind .[/[:alnum:]]\+. by [[:digit:]]\+ commit.*/freshness=${YELLOW}↓/p + s/^# Your branch and .[/[:alnum:]]\+. have diverged.*/freshness=${YELLOW}↕/p + + /^# Changes to be committed:/,/^# [A-Z]/ { + s/^# Changes to be committed:/added=added;/p + + s/^# modified: '"$file_regex"'/ [[ \" ${added_files[*]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\"/p + s/^# new file: '"$file_regex"'/ [[ \" ${added_files[*]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\"/p + s/^# renamed:[^>]*> '"$file_regex"'/ [[ \" ${added_files[*]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\"/p + s/^# copied:[^>]*> '"$file_regex"'/ [[ \" ${added_files[*]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\"/p + } + + /^# Changed but not updated:/,/^# [A-Z]/ { + s/^# Changed but not updated:/modified=modified;/p + s/^# modified: '"$file_regex"'/ [[ \" ${modified_files[*]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\"/p + s/^# unmerged: '"$file_regex"'/ [[ \" ${modified_files[*]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\"/p + } + + /^# Changes not staged for commit:/,/^# [A-Z]/ { + s/^# Changes not staged for commit:/modified=modified;/p + s/^# modified: '"$file_regex"'/ [[ \" ${modified_files[*]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\"/p + s/^# unmerged: '"$file_regex"'/ [[ \" ${modified_files[*]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\"/p + } + + /^# Unmerged paths:/,/^[^#]/ { + s/^# Unmerged paths:/modified=modified;/p + s/^# both modified:\s*'"$file_regex"'/ [[ \" ${modified_files[*]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\"/p + } + + /^# Untracked files:/,/^[^#]/{ + s/^# Untracked files:/untracked=untracked;/p + s/^# '"$file_regex"'/ [[ \" ${untracked_files[*]} ${modified_files[*]} ${added_files[*]} \" =~ \" \1 \" ]] || untracked_files[${#untracked_files[@]}]=\"\1\"/p + } + ' + )" + + if ! grep -q "^ref:" $git_dir/HEAD 2>/dev/null; then + detached=detached + fi + + + ################# GET GIT OP + + unset op + + if [[ -d "$git_dir/.dotest" ]] ; then + + if [[ -f "$git_dir/.dotest/rebasing" ]] ; then + op="rebase" + + elif [[ -f "$git_dir/.dotest/applying" ]] ; then + op="am" + + else + op="am/rebase" + + fi + + elif [[ -f "$git_dir/.dotest-merge/interactive" ]] ; then + op="rebase -i" + # ??? branch="$(cat "$git_dir/.dotest-merge/head-name")" + + elif [[ -d "$git_dir/.dotest-merge" ]] ; then + op="rebase -m" + # ??? branch="$(cat "$git_dir/.dotest-merge/head-name")" + + # lvv: not always works. Should ./.dotest be used instead? + elif [[ -f "$git_dir/MERGE_HEAD" ]] ; then + op="merge" + # ??? branch="$(git symbolic-ref HEAD 2>/dev/null)" + + elif [[ -f "$git_dir/index.lock" ]] ; then + op="locked" + + else + [[ -f "$git_dir/BISECT_LOG" ]] && op="bisect" + # ??? branch="$(git symbolic-ref HEAD 2>/dev/null)" || \ + # branch="$(git describe --exact-match HEAD 2>/dev/null)" || \ + # branch="$(cut -c1-7 "$git_dir/HEAD")..." + fi + + + #### GET GIT HEX-REVISION + if [[ $rawhex_len -gt 0 ]] ; then + rawhex=`git rev-parse HEAD 2>/dev/null` + rawhex=${rawhex/HEAD/} + rawhex="=$hex_vcs_color${rawhex:0:$rawhex_len}" + else + rawhex="" + fi + + #### branch + branch=${branch/master/M} + + # another method of above: + # branch=$(git symbolic-ref -q HEAD || { echo -n "detached:" ; git name-rev --name-only HEAD 2>/dev/null; } ) + # branch=${branch#refs/heads/} + + ### compose vcs_info + + if [[ $init ]]; then + vcs_info=${white}init + + else + if [[ "$detached" ]] ; then + branch="/dev/null`" + + + elif [[ "$op" ]]; then + branch="$op:$branch" + if [[ "$op" == "merge" ]] ; then + branch+="<--$(git name-rev --name-only $(<$git_dir/MERGE_HEAD))" + fi + #branch="<$branch>" + fi + vcs_info="$branch$freshness$rawhex" + + fi + } + + +parse_vcs_status() { + + unset file_list modified_files untracked_files added_files + unset vcs vcs_info + unset status modified untracked added init detached + unset file_list modified_files untracked_files added_files + + [[ $vcs_ignore_dir_list =~ $PWD ]] && return + + eval $PARSE_VCS_STATUS + + + ### status: choose primary (for branch color) + unset status + status=${op:+op} + status=${status:-$detached} + status=${status:-$clean} + status=${status:-$modified} + status=${status:-$added} + status=${status:-$untracked} + status=${status:-$init} + # at least one should be set + : ${status?prompt internal error: git status} + eval vcs_color="\${${status}_vcs_color}" + # no def: vcs_color=${vcs_color:-$WHITE} # default + + + ### VIM + + if [[ $vim_module = "on" ]] ; then + # equivalent to vim_glob=`ls .*.vim` but without running ls + unset vim_glob vim_file vim_files + old_nullglob=`shopt -p nullglob` + shopt -s nullglob + vim_glob=`echo .*.sw?` + eval $old_nullglob + + if [[ $vim_glob ]]; then + set $vim_glob + #vim_file=${vim_glob#.} + if [[ $# > 1 ]] ; then + vim_files="*" + else + vim_file=${1#.} + vim_file=${vim_file/.sw?/} + [[ .${vim_file}.swp -nt $vim_file ]] && vim_files=$vim_file + fi + # if swap is newer, then this is unsaved vim session + # [temoto custom] if swap is older, then it must be deleted, so show all swaps. + fi + fi + + + ### file list + unset file_list + if [[ $count_only = "on" ]] ; then + [[ ${added_files[0]} ]] && file_list+=" "${added_vcs_color}+${#added_files[@]} + [[ ${modified_files[0]} ]] && file_list+=" "${modified_vcs_color}*${#modified_files[@]} + [[ ${untracked_files[0]} ]] && file_list+=" "${untracked_vcs_color}?${#untracked_files[@]} + else + [[ ${added_files[0]} ]] && file_list+=" "$added_vcs_color${added_files[@]} + [[ ${modified_files[0]} ]] && file_list+=" "$modified_vcs_color${modified_files[@]} + [[ ${untracked_files[0]} ]] && file_list+=" "$untracked_vcs_color${untracked_files[@]} + fi + [[ ${vim_files} ]] && file_list+=" "${MAGENTA}vim:${vim_files} + + if [[ ${#file_list} -gt $max_file_list_length ]] ; then + file_list=${file_list:0:$max_file_list_length} + if [[ $max_file_list_length -gt 0 ]] ; then + file_list="${file_list% *} $elipses_marker" + fi + fi + + + head_local="$vcs_color(${vcs_info}$vcs_color${file_list}$vcs_color)" + + ### fringes + head_local="${head_local+$vcs_color$head_local }" + #above_local="${head_local+$vcs_color$head_local\n}" + #tail_local="${tail_local+$vcs_color $tail_local}${dir_color}" + } + +disable_set_shell_label() { + trap - DEBUG >& /dev/null + } + +# show currently executed command in label +enable_set_shell_label() { + disable_set_shell_label + # check for BASH_SOURCE being empty, no point running set_shell_label on every line of .bashrc + trap '[[ -z "$BASH_SOURCE" && ($BASH_COMMAND != prompt_command_function) ]] && + set_shell_label $BASH_COMMAND' DEBUG >& /dev/null + } + +declare -ft disable_set_shell_label +declare -ft enable_set_shell_label + +# autojump (see http://wiki.github.com/joelthelion/autojump) + +# TODO reverse the line order of a file +#awk ' { line[NR] = $0 } +# END { for (i=NR;i>0;i--) +# print line[i] }' listlogs + +j (){ + : ${1? usage: j dir-beginning} + # go in ring buffer starting from current index. cd to first matching dir + for (( i=(aj_idx-1)%aj_max; i != aj_idx%aj_max; i=(--i+aj_max)%aj_max )) ; do + if [[ ${aj_dir_list[$i]} =~ ^.*/$1[^/]*$ ]] ; then + cd "${aj_dir_list[$i]}" + return + fi + done + echo '?' + } + +alias jumpstart='echo ${aj_dir_list[@]}' + +###################################################################### PROMPT_COMMAND + +prompt_command_function() { + rc="$?" + + if [[ "$rc" == "0" ]]; then + rc="" + else + rc="$rc_color$rc$colors_reset$bell " + fi + + cwd=${PWD/$HOME/\~} # substitute "~" + set_shell_label "${cwd##[/~]*/}/" # default label - path last dir + + parse_vcs_status + + # autojump + if [[ ${aj_dir_list[aj_idx%aj_max]} != $PWD ]] ; then + aj_dir_list[++aj_idx%aj_max]="$PWD" + fi + + # if cwd_cmd have back-slash, then assign it value to cwd + # else eval cwd_cmd, cwd should have path after exection + eval "${cwd_cmd/\\/cwd=\\\\}" + + PS1="$colors_reset$rc$head_local$color_who_where$dir_color$cwd$tail_local$dir_color$prompt_char $colors_reset" + + unset head_local tail_local pwd + } + + PROMPT_COMMAND=prompt_command_function + + enable_set_shell_label + + unset rc id tty modified_files file_list + +# vim: set ft=sh ts=8 sw=8 et: diff --git a/init-var-on-tmp.sh b/init-var-on-tmp.sh index 248e9b3..3bf02ea 100755 --- a/init-var-on-tmp.sh +++ b/init-var-on-tmp.sh @@ -4,7 +4,7 @@ set -x VARTEMP=/tmp/var VARPERSISTENT=/var -VARDIRS="cache" +VARDIRS="cache log/fhem" BINDDIRS="cache lock run" case $1 in @@ -14,7 +14,8 @@ case $1 in for f in $VARDIRS do - rsync -av $VARPERSISTENT/$f.bak/ $VARTEMP/$f + fbase=$(basename $f) + rsync -av $VARPERSISTENT/$fbase.bak/ $VARTEMP/$f done for f in $BINDDIRS @@ -27,7 +28,8 @@ case $1 in echo "saving var-directory from temp to flash" for f in $VARDIRS do - [ -d $VARTEMP/$f ] && rsync -av $VARTEMP/$f/ $VARPERSISTENT/$f.bak + fbase=$(basename $f) + [ -d $VARTEMP/$f ] && rsync -av $VARTEMP/$f/ $VARPERSISTENT/$fbase.bak done ;; esac diff --git a/instapaper_epub.sh b/instapaper_epub.sh new file mode 100644 index 0000000..c06d806 --- /dev/null +++ b/instapaper_epub.sh @@ -0,0 +1,10 @@ +#!/bin/bash +Username="MarcHoppe@gmx.de" +Password="insta0815" +Docs=~/Documents +OutputDir=~/Documents/ePub + +curl --cookie-jar ${Docs}/cjar --data "username=$Username" -d "password=${Password}" --output ${Docs}/insta.html http://www.instapaper.com/user/login +curl -b ${Docs}/cjar --output ${OutputDir}/insta.epub http://www.instapaper.com/epub +rm -f ${Docs}/cjar ${Docs}/insta.html + diff --git a/ipad.sh b/ipad.sh index 0bcb480..dc46e9d 100644 --- a/ipad.sh +++ b/ipad.sh @@ -1,3 +1,5 @@ +#!/bin/bash + ipaddir=/dat/ipad @@ -40,9 +42,9 @@ do done # Podcasts -filedir="/dat/mp3/podcast/cache" -dstdir=$ipaddir/ -ln -s $filedir $dstdir/podcast +#filedir="/dat/mp3/podcast/cache" +#dstdir=$ipaddir/ +#ln -s $filedir $dstdir/podcast # Musik linkdir=$ipaddir/music @@ -90,7 +92,7 @@ done dstdir=$ipaddir/bilder srcdir=/dat/bilder -#[ -d $dstdir ] || mkdir -p $dstdir +[ -d $dstdir ] || mkdir -p $dstdir cd $dstdir || exit [ "$dstdir" != "" ] && rm -r * @@ -99,6 +101,8 @@ find $srcdir -name ipad -print0 | while read -d $'\0' f do fileindir=$f linkdest=$(dirname "$fileindir") + echo "adding: $f" + ln -s "$linkdest" #[ -x "$artist/$album" ] || ln -s "$linkdest" "$artist/$album" done diff --git a/iso2utf.sh b/iso2utf.sh new file mode 100755 index 0000000..9ea2380 --- /dev/null +++ b/iso2utf.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -x + +file_iso=$1 +file_utf=${file_iso}.utf8 + +[ -f $file_iso ] || exit +iconv --from-code=ISO-8859-1 --to-code=UTF-8 $file_iso > $file_utf + diff --git a/m4a2ogg.sh b/m4a2ogg.sh new file mode 100644 index 0000000..e4ec7b8 --- /dev/null +++ b/m4a2ogg.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# m4a to ogg + +i=$1 + tmp=$(mktemp) + y=`echo "$i"|sed -e 's/.m4a/.ogg/'` + faad -i "$i" 1>/dev/null 2>"$tmp" + if [ $? -ne 0 ] ; then + rm "$tmp" + echo "failed to get information from $i" + continue + fi + title=`grep 'title: ' "$tmp"|sed -e 's/title: //'` + artist=`grep 'artist: ' "$tmp"|sed -e 's/artist: //'` + album=`grep 'album: ' "$tmp"|sed -e 's/album: //'` + genre=`grep 'genre: ' "$tmp"|sed -e 's/genre: //'` + track=`grep 'track: ' "$tmp"|sed -e 's/track: //'` + year=`grep 'year: ' "$tmp"|sed -e 's/date: //'` + faad "$i" -o - | oggenc -q 4 -t "$title" -a "$artist" -l "$album" -G "$genre" -N "$track" -d "$year" -o "$y" - + if [ $? -ne 0 ] ; then + echo "failed to encode $i" + fi + rm "$tmp" + diff --git a/mirrors.update b/mirrors.update new file mode 100644 index 0000000..904c335 --- /dev/null +++ b/mirrors.update @@ -0,0 +1,15 @@ +#!/bin/bash + +fhemdir=/home/marc/src/fhem +fhem_mirror=$fhemdir/fhem-git +myfhem=$fhemdir/my + +cd $fhem_mirror +git svn rebase +#git merge remotes/git-svn +git push github master +#cd $myfhem +#git fetch origin +#git push github master + + diff --git a/mkosm.sh b/mkosm.sh new file mode 100644 index 0000000..cdaf155 --- /dev/null +++ b/mkosm.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -x + +mapfile=$1 +splitter=../splitter.jar +mkgmap=../mkgmap.jar +mapid=65241345 +country_name=greece + +sudo swapon /dat/tmp/swap.img + + +#wget http://download.geofabrik.de/osm/europe/germany/$mapfile.bz2 +#bunzip $mapfile.bz2 + +mkdir tiles +rm -r tiles/* +cd tiles/ + +java -Xmx5000M -jar $splitter --mapid=$mapid --max-nodes=500000 ../$mapfile + +cd .. +mkdir gbasemap +rm -r gbasemap/* +cd gbasemap +java -Xmx5000M -jar $mkgmap --style-file=../styles/masterstyle --description='Openstreetmap' --country-name=$country_name --country-abbr=GR --family-id=3 --product-id=45 --series-name='master-edition' --family-name=OSM --area-name=GR --latin1 --lower-case --mapname=$mapid --draw-priority=10 --add-pois-to-areas --road-name-pois --net --route --gmapsupp ../tiles/*.osm.gz /home/marc/osm/styles/master.TYP + +sudo swapoff /dat/tmp/swap.img diff --git a/mkvdrrecdir.sh b/mkvdrrecdir.sh new file mode 100755 index 0000000..e57fff0 --- /dev/null +++ b/mkvdrrecdir.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +#set -x + +RECORDING_LIFETIME=99 +RECORDING="$(date +%Y-%m-%d.%H.%M).99.$RECORDING_LIFETIME.rec" +mkdir $RECORDING diff --git a/mp32wav b/mp32wav new file mode 100755 index 0000000..455d407 --- /dev/null +++ b/mp32wav @@ -0,0 +1,85 @@ +#!/bin/bash +# +# /usr/local/bin/mp3tocd -- mp3-Files nach wav oder au umwandeln +# und brennen. +# Das Format 44100 Hz, 16Bit Stereo ist notwendig, siehe Text +# +# mp32wav mp3dir wavdir + +set -x + +function usage () +{ + echo " +mp32wav mp3dir wavdir + mp3dir: Verzeichnis, in dem die mp3-Dateien gepseichert sind. + wavdir: Verzeichnis, in das die erzeugten wave-Dateien geschrieben werden" +} + +function yesno () +{ + while true; do + read ans + case "$ans" in + y|Y|j|J|[yY]es|[jJ]a) + return 1 + ;; + n|N|[nN]o|[nN]ein) + return 0 + ;; + *) + echo -e '\a\nVertipper. (j,ja,y,yes/n,nein,no)' + ;; + esac + done +} + +if ! test -d "$1"; then + usage +fi +if ! test -d "$2"; then + usage +fi + +mp3dir="$1" +wavdir="$2" + +#pushd $destdir > /dev/null +let count=0 + +for i in "$mp3dir"/*.mp3; do + echo "$i wird decodiert" + + ## Der Umstand mit der fuehrenden Null in der 'if'-Abfrage bewirkt, + ## dass (maximal) 100 Tracks in der richtigen Reihenfolge gebrannt + ## werden + + if test "$count" -le 9; then + track=""0$count"track.wav" + else + track=""$count"track.wav" + fi + trakfile="$i" + echo Datei1 "$trakfile" + track=$(basename "$i" .mp3).wav + echo Datei2 "$track" + + mpg123 -v -s -r 44100 --stereo --wav "$wavdir"/"$track" "$i" + + let count=$(expr $count + 1) +done + +echo -e "\n erzeugte Tracks:" +ls -l "$wavdir"/[0-9][0-9]*.wav +echo "KByte insgesamt: $(du -kc "$wavdir"/[0-9][0-9]*.wav | tail -n 1 | awk '{print $1}')" +#echo " +#Brennen durchfuehren (j,y,ja,yes/n,nein,no)?" + +#if ! yesno; then + #cdrecord -v -speed=$speed $blank -pad dev=$wdev -audio [0-9][0-9]track.$format + # popd > /dev/null +# rm -R $destdir +#else +# echo "Die Tracks in $destdir wurden nicht geloescht" +#fi + diff --git a/podcastupdate.sh b/podcastupdate.sh new file mode 100755 index 0000000..dee30fd --- /dev/null +++ b/podcastupdate.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +LOGFILE=/tmp/podcatcher.log +set -x +sleep +#swapon /dat/tmp/swap.img +svdrpsend MESG "Podcasts aktualisieren-gestarted" +cd /mp3/podcast +echo "start ----------------------------" >> $LOGFILE +date >> $LOGFILE +./catch.sh >> $LOGFILE 2>&1 +svdrpsend MESG "Podcasts aktualisiert" +#swapoff /dat/tmp/swap.img diff --git a/podcastupdated.sh b/podcastupdated.sh new file mode 100755 index 0000000..1eaa74d --- /dev/null +++ b/podcastupdated.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "/usr/local/bin/podcastupdate.sh" | at now diff --git a/queue b/queue new file mode 100755 index 0000000..4de31de --- /dev/null +++ b/queue @@ -0,0 +1,16 @@ +#!/bin/bash + +qfile=/tmp/queue.commands + +if [ "$1" = "-list" ]; then + cat $qfile + exit +fi + +echo $* >> $qfile + +lines=$(cat $qfile | wc -l) + +if [ $lines -eq 1 ]; then + nohup /usr/local/bin/unqueue $qfile & +fi diff --git a/recwebradio.sh b/recwebradio.sh new file mode 100644 index 0000000..2f4fda9 --- /dev/null +++ b/recwebradio.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +t1=$1 +t2=$2 + diff --git a/rmdvbmodules.sh b/rmdvbmodules.sh new file mode 100644 index 0000000..a3ed50b --- /dev/null +++ b/rmdvbmodules.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +sudo rmmod budget_ci +sudo rmmod tda1004x +sudo rmmod dvb_ttpci +sudo rmmod stv0299 +sudo rmmod ves1x93 +sudo rmmod rc_hauppauge +sudo rmmod saa7146_vv +sudo rmmod videodev +sudo rmmod budget_core +sudo rmmod dvb_core +sudo rmmod v4l2_compat_ioctl32 +sudo rmmod videobuf_dma_sg +sudo rmmod saa7146 +sudo rmmod ttpci_eeprom +sudo rmmod v4l1_compat diff --git a/start_dropbox.sh b/start_dropbox.sh new file mode 100644 index 0000000..2e8ae6b --- /dev/null +++ b/start_dropbox.sh @@ -0,0 +1 @@ +HOME=/home/marc/.dropbox-ipad/ nohup .dropbox-dist/dropbox start diff --git a/sync_pod.pl b/sync_pod.pl new file mode 100755 index 0000000..49352b5 --- /dev/null +++ b/sync_pod.pl @@ -0,0 +1,862 @@ +#!/usr/bin/perl -w + +# (c) 2002 Armin Obersteiner +# License: GPL v2 + +use MP3::Info; +use Unicode::String qw( latin1 utf16 ); +use Shell qw ( find gzip ); +use Getopt::Std; +use File::Copy; +use Filesys::DiskFree; + +use Data::Dumper qw (Dumper); + +use strict; + +my $version="0.68"; + +# +# options & config +# + +my %opt; +getopts("fcnh",\%opt); + +if($opt{h}) { + print <<"EOF"; +$0 [-c] [-f] [Search Pattern 1] [Search Pattern 2] ... + + -c create: create directory structure on plain ipod before syncing + (default: you get a warning if there is no ipod structure) + + -f force: rename ipod and use it with $0 before syncing + (default: an unknown ipod stays untouched) + + -n name check: checks mp3 names for possible illegal characters + + Search Patterns: for each search pattern a playlist is created + (case insensitive) +EOF + exit; +} + +my $buffer = 5*1024*1024; # leave some MB free for iTunesDB + +my @required = qw ( SYNCMODE PLAYLISTDIR IPODDIR BACKUPDIR ); + +my $rc=readrc("$ENV{HOME}/.ipod/config",\@required); + +#print Dumper($rc); + + +# +# check ipod name +# + +my ($ipod_name, $real_name, $computer_name)=get_ipodname($rc->{IPODDIR}); +unless($ipod_name) { + die "IPOD dir not found: $rc->{IPODDIR}" unless $opt{c}; +} + +# +# check ipod dirs (recreate them if necessary) +# + +mkdir "$rc->{IPODDIR}/iPod_Control",0755 unless(-d "$rc->{IPODDIR}/iPod_Control"); +mkdir "$rc->{IPODDIR}/iPod_Control/Music",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music"); +mkdir "$rc->{IPODDIR}/iPod_Control/iTunes",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/iTunes"); +mkdir "$rc->{IPODDIR}/iPod_Control/Device",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Device"); +for(0..19) { + my $d=sprintf "%.2d",$_; + mkdir "$rc->{IPODDIR}/iPod_Control/Music/F$d",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music/F$d"); +} + +unless($opt{c}) { + print STDERR "IPOD name: $ipod_name\n"; + print STDERR "Synced by: $real_name\n"; + print STDERR "Synced on: $computer_name\n"; + + if($rc->{WRITEDEVICEINFO} && !$opt{f}) { + my $exit=0; + unless($rc->{IPODNAME} eq $ipod_name) { + $exit=1; + print STDERR "Your IPOD name: $rc->{IPODNAME}\n"; + } + unless($rc->{REALNAME} eq $real_name) { + $exit=1; + print STDERR "Your real name: $rc->{REALNAME}\n"; + } + unless($rc->{COMPUTERNAME} eq $computer_name) { + $exit=1; + print STDERR "Your computer: $rc->{COMPUTERNAME}\n"; + } + die "names mismatch, use -f to override" if $exit; + } + print STDERR "\n"; +} + +# +# write ipod name +# + +if($rc->{WRITEDEVICEINFO}) { + set_ipodname( + $rc->{IPODDIR},$rc->{BACKUPDIR}, + $rc->{IPODNAME},$rc->{REALNAME},$rc->{COMPUTERNAME} + ); + $ipod_name=$rc->{IPODNAME}; +} + +# +# check for songs +# + +my %songs; +my %check; + +my $dir; +$dir=$rc->{IPODDIR}."/iPod_Control/Music"; +$dir=$rc->{SYNCDIR} if($rc->{SYNCMODE} >= 2); + +my %tosync; +if(($rc->{SYNCLIST}) && ($rc->{SYNCMODE} == 2)) { + open IN,$rc->{SYNCLIST} or die "all-playlist: $rc->{SYNCLIST} not found"; + while() { + chomp; + $tosync{$_}=1; + } + close IN; +} + +my @mp3s; +if(($rc->{SYNCMODE} == 3)) { + my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null"); + my %test; + + for my $p (@pl) { + chomp $p; + my ($n) = $p =~ /.*\/(.*?)$/; + open IN,$p or die "playlist: $p could not be opened"; + while() { + unless($test{$_}) { + push @mp3s,$_; + $test{$_}=1; + } + } + } +} else { + @mp3s=find($dir); +} + +for(@mp3s) { + chomp $_; + next unless(/\.(m|M)(p|P)3$/); + my $name=$_; + + if(keys %tosync) { + next unless($tosync{$name}); + } + + if($opt{n}) { + die "illegal character in filename [$name]\n" unless ($name =~ /^[A-Za-z0-9\.\-_\/\,]+$/); + } + + s/\://g; + s/.*\///g; + $songs{$name}{name}=$_; + if($rc->{SYNCMODE} >= 2) { + $songs{$name}{dir}="F".hash($_); + } else { + ($songs{$name}{dir}) = $name =~ /\/(F\d\d)\//; + } + + { + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + $atime,$mtime,$ctime,$blksize,$blocks) = stat($name); + $songs{$name}{size}=$size; + $songs{$name}{date}=$mtime; + } + + my $tag; + $tag = get_mp3tag($name) unless($rc->{ALWAYSTEMPLATES}); + + my ($artist,$album,$title,$order,$_dummy_); + + if($tag) { + # print Dumper($tag); + # YEAR ARTIST COMMENT TRACKNUM TITLE ALBUM GENRE + $artist=$tag->{ARTIST}; + $album=$tag->{ALBUM}; + $title=$tag->{TITLE}; + $order=$tag->{TRACKNUM}; + $order=$1 if($order =~ /(\d+)\s*\//); + + } else { + for(sort {length($b) <=> length($a)} keys %{$rc->{FILETEMPLATES}}) { + if(my @x = $name =~ /$_/) { + my $c=0; + for my $x (@x) { + #print "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";\n"; + eval "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";"; + die "eval error: $@" if($@); + $c++; + } + last; + } + } + } + + unless($title) { + die "no title found in: $name"; + } + + $title =~ s/_/ /g; + $artist =~ s/_/ /g; + $album =~ s/_/ /g; + + $songs{$name}{title}=$title; + $songs{$name}{artist}=""; + $songs{$name}{album}=""; + $songs{$name}{order}=0; + $songs{$name}{artist}=$artist if $artist; + $songs{$name}{album}=$album if $album; + $songs{$name}{order}=$order if $order; + + my $info = get_mp3info ($name); + + $songs{$name}{size}=$info->{SIZE}; + $songs{$name}{bitrate}=$info->{BITRATE}; + $songs{$name}{duration}=int($info->{SECS}*1000); + $songs{$name}{vbr}=$info->{VBR}; + + #print Dumper($info); + + my $n=$songs{$name}{dir}."/".$songs{$name}{name}; + unless($check{$n}) { + $check{$n}=1; + } else { + die "songname: $songs{$name}{name} not unique"; + } +} + +# +# deleting unwanted songs +# + +my %known; +for(keys %songs) { + $known{$songs{$_}{name}}=1; +} + +#print Dumper(\%known); + +my @ipod = find ("$rc->{IPODDIR}/iPod_Control/Music"); +my @todel; +for(@ipod) { + next unless (/\.mp3$/i); + chomp; + + my ($name) = $_ =~ /\/([^\/]+\.mp3)$/i; + unless($known{$name}) { + push @todel,$_; + } +} + +my $del; +if($rc->{DELETEASK} && @todel) { + for(@todel) { + print "del: $_\n"; + } + print "Do you really want to delete this songs? (y/N) "; + my $in=; + chomp $in; + $del=1 if($in =~ /^y$/i); +} else { + $del=1; +} + +if($del) { + for(@todel) { + print STDERR "deleting: $_\n"; + unlink($_); + } +} + +# +# copy songs +# + +my $main_sl=""; +my $main_pl=""; +my $index=500; + +#print Dumper(\%songs); + +my $df = new Filesys::DiskFree; + +SONGS: for my $song (keys %songs) { + my $attr; + my $out=""; + my $attr_c=3; + + if($rc->{SYNCMODE} >= 2) { + my $to = "$rc->{IPODDIR}/iPod_Control/Music/$songs{$song}{dir}/$songs{$song}{name}"; + #my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, + # $atime,$mtime,$ctime,$blksize,$blocks) = stat($to); + #$size=0 unless $size; + #print "checking: $song [$songs{$song}{size}] -> $to [$size]\n"; + #if($size != $songs{$song}{size}) { + + unless(-e $to) { + print STDERR "syncing: $songs{$song}{name}\n"; + # cp "\"$song\" \"$to\""; + + $df->df(); + my $free=$df->avail($rc->{IPODDIR}); + + if($free-$songs{$song}{size}-$buffer>0) { + copy($song,$to); + } else { + print STDERR "no space availiable for: $songs{$song}{name} [$songs{$song}{size}]\n"; + delete $songs{$song}; + next SONGS; + } + } + } + + $songs{$song}{index}=$index; + + $out.=create_mhod($songs{$song}{title},1); + + if($songs{$song}{artist}) { + $attr_c++; + $out.=create_mhod($songs{$song}{artist},4); + } + if($songs{$song}{album}) { + $attr_c++; + $out.=create_mhod($songs{$song}{album},3); + } + + $out.=create_mhod("MPEG audio file",6); + $out.=create_mhod(":iPod_Control:Music:".$songs{$song}{dir}.":".$songs{$song}{name},2); + + $out=create_mhit( + $attr_c,length($out),$index,$songs{$song}{vbr}, + $songs{$song}{date},$songs{$song}{size}, + $songs{$song}{duration},$songs{$song}{order}, + $songs{$song}{bitrate} + ).$out; + + $main_sl.=$out; + + $main_pl.=create_mhod_mhip($songs{$song}{index}); + + $index++; +} + +#print Dumper(\%songs); + +my %playlists; +my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null"); + +for my $p (@pl) { + chomp $p; + my ($n) = $p =~ /.*\/(.*?)$/; + open IN,$p or die "playlist: $p could not be opened"; + while() { + my $song=$_; + chomp $song; + + unless($songs{$song}) { + print STDERR "ignoring song in playlist [$p], [$song] does not exist in syncdir or ipod full\n"; + } else { + $playlists{$n}{raw}.=create_mhod_mhip($songs{$song}{index}); + $playlists{$n}{count}++; + } + } + close IN; +} + +# +# creating search pattern playlists +# + +for my $pattern (@ARGV) { + my @list; + for(keys %songs) { + push @list,$songs{$_}{index} if($_ =~ /$pattern/i); + } + unless(@list) { + print STDERR "nothing for searchpattern: $pattern found\n"; + } else { + my ($name)=$pattern=~/(\S\S\S+)/; + unless(length($name)>=3) { + $name=$pattern; + $name =~ s/[^A-Za-z0-9]//g; + } + for(@list) { + $playlists{$name}{raw}.=create_mhod_mhip($_); + $playlists{$name}{count}++; + } + print STDERR @list." songs for searchpattern: $pattern found\n"; + } +} + +#print Dumper(\%playlists); + +# +# build the pieces together +# + +my $output; + +my $song_c=keys %songs; + +print STDERR "\nFound songs: $song_c\n"; + +my $tmp=create_mhlt($song_c).$main_sl; +$main_sl=create_mhsd(96+length($tmp),1).$tmp; + +print STDERR "Songlist created\n"; + +my $pl_c=keys %playlists; + +print STDERR "\nFound additional playlists: $pl_c\n"; + +$tmp=create_mhlp($pl_c+1).create_playlist_main($ipod_name,$song_c).$main_pl; +print STDERR "\nMain playlist created: $song_c songs\n\n"; + +for(keys %playlists) { + $tmp.=create_playlist($_,$playlists{$_}{count}).$playlists{$_}{raw}; + print STDERR "Playlist \"$_\" created: $playlists{$_}{count} songs\n"; +} + +$main_pl=create_mhsd(96+length($tmp),2).$tmp; + + +$output=create_mhbd(104+length($main_sl.$main_pl)).$main_sl.$main_pl; + +# backup old iTunesDB +if(-e "$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB") { + my $t=time(); + copy("$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB","$rc->{BACKUPDIR}/iTunesDB_$t"); + gzip("$rc->{BACKUPDIR}/iTunesDB_$t"); +} + +open OUT,">".$rc->{IPODDIR}."/iPod_Control/iTunes/iTunesDB" or die "cannot write iTunesDB"; +print OUT $output; +close OUT; + +print STDERR "\niTunesDB created.\n"; +exit; +# END + + +# +# internal subroutines +# + +sub create_mhbd { + my ($size) = @_; + + my $r= "mhbd"; + $r.= pack "V",104; + $r.= pack "V",$size; + $r.= pack "V",1; + $r.= pack "V",1; + $r.= pack "V",2; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhlp { + my ($count) = @_; + + my $r= "mhlp"; + $r.= pack "V",92; + $r.= pack "V",$count; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_playlist { + my ($name,$anz) = @_; + + my $ipod_name=create_mhod($name,1); + + my $r= "mhyp"; + $r.= pack "V",108; + $r.= pack "V",108+648+length($ipod_name)+$anz*(76+44); + $r.= pack "V",2; + $r.= pack "V",$anz; + $r.= pack "V",0; + $r.= pack "V",3088620292; + $r.= pack "V",2317718671; + $r.= pack "V",3655876446; + for(1..18) { + $r.= pack "V",0; + } + + $r.= "mhod"; + $r.= pack "V",24; + $r.= pack "V",648; + $r.= pack "V",100; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",12714187; # ?? 12714187 + $r.= pack "V",26215000; + $r.= pack "V",0; + $r.= pack "V",65736; + $r.= pack "V",1; # ?? 1 + $r.= pack "V",6; # ?? 6 + $r.= pack "V",0; # ?? 0 + $r.= pack "V",2555905; # ?? 2555905 + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13107202; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",3276813; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192004; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192003; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",5242888; + for(1..107) { + $r.= pack "V",0; + } + $r.= pack "V",140; + for(1..19) { + $r.= pack "V",0; + } + + return $r.$ipod_name; +} + +sub create_playlist_main { + my ($name,$anz) = @_; + + my $ipod_name=create_mhod($name,1); + + my $r= "mhyp"; + $r.= pack "V",108; + $r.= pack "V",108+648+length($ipod_name)+$anz*(76+44); + $r.= pack "V",2; + $r.= pack "V",$anz; + $r.= pack "V",1; + $r.= pack "V",3087491191; + $r.= pack "V",837788566; + $r.= pack "V",62365; + for(1..18) { + $r.= pack "V",0; + } + + $r.= "mhod"; + $r.= pack "V",24; + $r.= pack "V",648; + $r.= pack "V",100; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13172927; # ?? 12714187 + $r.= pack "V",26215000; + $r.= pack "V",0; + $r.= pack "V",65736; + $r.= pack "V",5; # ?? 1 + $r.= pack "V",6; # ?? 6 + $r.= pack "V",3; # ?? 0 + $r.= pack "V",1179649; # ?? 2555905 + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",13107202; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",3276813; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192004; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",8192003; + for(1..3) { + $r.= pack "V",0; + } + $r.= pack "V",5242888; + for(1..107) { + $r.= pack "V",0; + } + $r.= pack "V",140; + for(1..19) { + $r.= pack "V",0; + } + + return $r.$ipod_name; +} + +sub create_mhod_mhip { + my ($ref) = @_; + + my $r= "mhip"; + $r.= pack "V",76; + $r.= pack "V",76; + $r.= pack "V",1; + $r.= pack "V",0; + $r.= pack "V",$ref-1; + $r.= pack "V",$ref; + $r.= pack "V",3088619525; + for(1..11) { + $r.= pack "V",0; + } + + $r.="mhod"; + $r.= pack "V",24; + $r.= pack "V",44; + $r.= pack "V",100; + $r.= pack "V",0; + $r.= pack "V",0; + $r.= pack "V",$ref-1; + for(1..4) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhsd { + my ($size,$type) = @_; + + my $r="mhsd"; + $r.= pack "V",96; + $r.= pack "V",$size; + $r.= pack "V",$type; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhlt { + my ($count) = @_; + + my $r="mhlt"; + $r.= pack "V",92; + $r.= pack "V",$count; + for(1..20) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhit { + my ($arttr_c,$attr_s,$index,$vbr,$date,$size,$dur,$order,$bitrate) = @_; + + my $r="mhit"; + $r.= pack "V",156; + $r.= pack "V",156+$attr_s; + $r.= pack "V",$arttr_c; + $r.= pack "V",$index; + $r.= pack "V",1; + $r.= pack "V",0; + my $type=256; + $type+=1 if($vbr); + $r.= pack "V",$type; + $r.= pack "V",$date+2082844800; + $r.= pack "V",$size; + $r.= pack "V",$dur; + $r.= pack "V",$order; + $r.= pack "V",0; + $r.= pack "V",0; + $r.= pack "V",$bitrate; + $r.= pack "V",2890137600; + for(1..23) { + $r.= pack "V",0; + } + + return $r; +} + +sub create_mhod { + my ($string,$type) = @_; + my $len=length($string); + + my $r="mhod"; + $r.= pack "V",24; + $r.= pack "V",(40+2*$len); + $r.= pack "V",$type; + $r.= pack "V2",0; + $r.= pack "V",1; + $r.= pack "V",(2*$len); + $r.= pack "V2",0; + + my $u=latin1($string); + $u->byteswap; + $r.= $u->utf16; + + return $r; +} + +sub set_ipodname { + my ($dev,$backup,$name,$real,$cpu)=@_; + $dev.="/iPod_Control/iTunes/DeviceInfo"; + + my $file; + + for(1..384) { + $file.=pack "V",0; + } + + my $l=length($name); + substr($file,0,2)=pack "v",$l; + my $u=latin1($name); + $u->byteswap; + substr($file,2,$l*2)=$u->utf16; + + $l=length($real); + substr($file,512,2)=pack "v",$l; + $u=latin1($real); + $u->byteswap; + substr($file,514,$l*2)=$u->utf16; + + $l=length($cpu); + substr($file,1024,2)=pack "v",$l; + $u=latin1($cpu); + $u->byteswap; + substr($file,1026,$l*2)=$u->utf16; + + if(-e $dev) { + my $t=time(); + copy($dev,"$backup/DeviceInfo_$t"); + gzip("$backup/DeviceInfo_$t"); + } + open IPOD,">$dev" or die "cannot write DeviceInfo"; + print IPOD $file; + close IPOD; +} + +sub get_ipodname { + my $dev=shift; + $dev.="/iPod_Control/iTunes/DeviceInfo"; + my $file; + my $buff; + + open IPOD,$dev or return undef; + while (read(IPOD, $buff, 8 * 2**10)) { + $file.=$buff; + } + close IPOD; + + my $l=unpack "v",substr($file,0,2); + my $s=substr($file,2,$l*2); + my $u=utf16($s); + $u->byteswap; + my $name=$u->latin1; + + $l=unpack "v",substr($file,512,2); + $s=substr($file,514,$l*2); + $u=utf16($s); + $u->byteswap; + my $realname=$u->latin1; + + $l=unpack "v",substr($file,1024,2); + $s=substr($file,1026,$l*2); + $u=utf16($s); + $u->byteswap; + my $computername=$u->latin1; + + return ($name,$realname,$computername); +} + +sub hash { + my $string=shift; + my $key; + + my $len=length($string); + + for(my $j=$len-1 ; $j>1 ; $j--) { + $key+=ord(substr($string,$j,1)); + } + + return sprintf "%.2d",(substr($key,length($key)-2,2) % 20); +} + +sub readrc { + my $file = shift; + my $req = shift; + my $rc; + + my $sub; + + open IN,$file or die "cannot open rc file: $file"; + while() { + next if /^\s*$/; + next if /^\s*#/; + + if(/^\s*(\S+)\s*=\s*(.*?)\s*$/) { + my $k=$1; + my $n=$2; + ($n) = $n =~ /^\"(.*?)\"$/ if($n =~ /\"/); + unless($sub) { + $rc->{$k}=$n; + } else { + ($k) = $k =~ /^\"(.*?)\"$/ if($k =~ /\"/); + my @n=split /,/,$n; + for(@n) { + s/^\s+//g; + s/\s+$//g; + s/^\"//; + s/\"$//; + } + $rc->{$sub}->{$k}=\@n; + } + } elsif (/^\s*(\S+)\s*\{/) { + $sub=$1; + } elsif (/^\s*}/) { + $sub=undef; + } + } + + if($rc->{SYNCMODE} == 2) { + push @$req,"SYNCDIR"; + } + if($rc->{WRITEDEVICEINFO} == 1) { + push @$req,("IPODNAME","REALNAME","COMPUTERNAME"); + } + if($rc->{ALWAYSTEMPLATES} == 1) { + push @$req,"FILETEMPLATES"; + } + + for my $d (keys %$rc) { + if($d =~ /DIR$/) { + $rc->{$d} =~ s/\~/$ENV{HOME}/; + } + } + $rc->{SYNCLIST} =~ s/\~/$ENV{HOME}/ if $rc->{SYNCLIST}; + + for(@$req) { + die "RC PARAMETER: $_ not found" unless($rc->{$_}); + } + return $rc; +} diff --git a/syncauto.sh b/syncauto.sh new file mode 100644 index 0000000..d84e5ae --- /dev/null +++ b/syncauto.sh @@ -0,0 +1,3 @@ + +# sudo mount -o uid=marc /dev/sdt1 /media/hdext +rsync -a --no-o --no-p --no-g -L --modify-window 1 --stats --delete --progress /mp3/auto/ /media/hdext/ diff --git a/taz-download.sh b/taz-download.sh index c3adb93..6c549f0 100755 --- a/taz-download.sh +++ b/taz-download.sh @@ -8,7 +8,7 @@ # So sehen die Dateien aus: # http://www.taz.de/cgi-bin/digiabo/2007_04_17_HTM.zip -TAZDIR=/dat/books/taz +TAZDIR=/media/nas/books/taz TAZUSER=103450 TAZPASSWD=oxculo TAZTYPE=.pdf @@ -72,3 +72,6 @@ for i in {1..16} do download "${TAG[$i]}""$TAZTYPE_EPUB" "$TAZURL""taz_""${TAG[$i]}""$TAZTYPE_EPUB" done + +# Sync to Dropbox +bash /home/marc/bin/tazsync.sh diff --git a/tazsync.sh b/tazsync.sh new file mode 100644 index 0000000..b02073a --- /dev/null +++ b/tazsync.sh @@ -0,0 +1,26 @@ + +daysback=10 + +srcdir=/dat/books/taz +dstdir=/home/marc/Dropbox-ipad/taz +tmpdir=/tmp + +[ -d $dstdir ] || exit +[ -d $srcdir ] || exit +[ -d $tmpdir ] || exit + +cd $dstdir +find . -type f | sort> $tmpdir/alt.lst + +cd $srcdir +find . -mtime -$daysback -name "*.epub" | sort > $tmpdir/new.lst + +rsync --files-from=$tmpdir/new.lst . $dstdir/ + +cd $dstdir + +cat $tmpdir/alt.lst $tmpdir/new.lst | sort -u > $tmpdir/all.lst +cat $tmpdir/all.lst +cat $tmpdir/new.lst +diff $tmpdir/new.lst $tmpdir/all.lst | grep "^>" | sed "s/^> //" | xargs rm +# $rmfiles diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..19b5d7f --- /dev/null +++ b/test.sh @@ -0,0 +1,7 @@ + +echo "#!/bin/bash" > /tmp/cctest +echo "dstdir=\$(dirname \$1)" >> /tmp/cctest +echo "echo rsync -av \$1 \$bakdir/\$dstdir" >> /tmp/cctest + +export bakdir=/media/hdext/git +find /home/marc/ -type d -name .git -exec bash -x /tmp/cctest {} \; diff --git a/tonas.sh b/tonas.sh new file mode 100644 index 0000000..f067a3f --- /dev/null +++ b/tonas.sh @@ -0,0 +1,3 @@ + +sudo -u vdr rsync -avz --progress --delete --exclude "*.del" /video/ /media/hdext/video/vdr/ +sudo -u vdr rsync -avz --progress --delete /mp3/ /media/hdext/audio/ diff --git a/torrentcreate.sh b/torrentcreate.sh new file mode 100644 index 0000000..f4441cc --- /dev/null +++ b/torrentcreate.sh @@ -0,0 +1 @@ +ctorrent -t -u http://tracker.thepiratebay.org/announce -s test.torrent garmin_allinone_d_2009-07-17.tar diff --git a/tvm2vdr_start b/tvm2vdr_start new file mode 100755 index 0000000..7b66a39 --- /dev/null +++ b/tvm2vdr_start @@ -0,0 +1,12 @@ +#!/bin/bash + +tmpdir1=/tmp/tvmovie2vdr +tmpdir2=/tmp/tvmovie2vdrup +logdir=/var/log/tvmovie2vdr + +[ -d $tmpdir1 ] || mkdir $tmpdir1 +[ -d $tmpdir2 ] || mkdir $tmpdir2 +[ -d $logdir ] || mkdir $logdir + +tvm2vdr + diff --git a/unqueue b/unqueue new file mode 100755 index 0000000..7f865b2 --- /dev/null +++ b/unqueue @@ -0,0 +1,15 @@ +#!/bin/bash +set -x +qfile=$1 + +lines=$(cat $qfile | wc -l) + +while [ $lines -ge 1 ]; do + entry=$(head -n 1 $qfile) + $entry + tail -n +2 $qfile > ${qfile}.tmp + mv ${qfile}.tmp ${qfile} + lines=$(cat $qfile | wc -l) +done + +rm $qfile diff --git a/update_garmin.sh b/update_garmin.sh index 7c25455..5476c89 100644 --- a/update_garmin.sh +++ b/update_garmin.sh @@ -3,8 +3,8 @@ LocalDir=/dat/gps/garmin -allinone=1 -radfahrer=1 +allinone=0 +radfahrer=0 kleineisel=1 # ------------------------------------------- @@ -67,14 +67,15 @@ if [ $radfahrer -eq 1 ]; then cd $LocalDir/radfahrer - wget -nv http://osm.arndnet.de/ -O index.html + #wget -nv http://osm.arndnet.de/ -O index.html + wget -N http://radkarte.formann.de/gmapsupp.img.zip #uncompress < Radkarte > Radkarte.html - cp index.html Radkarte.html - url_rad=$(cat Radkarte.html | grep img\.zip | cut -f 2 -d '"') - wget -nv -N $url_rad + #cp index.html Radkarte.html + #url_rad=$(cat Radkarte.html | grep img\.zip | cut -f 2 -d '"') + #wget -nv -N $url_rad datestr=$(stat -c %y gmapsupp.img.zip | cut -f 1 -d ' ') [ -f radfahrer_$datestr.zip ] || cp gmapsupp.img.zip radfahrer_$datestr.zip - rm Radkarte.html + #rm Radkarte.html fi diff --git a/vdrrecren b/vdrrecren new file mode 100755 index 0000000..4602a79 --- /dev/null +++ b/vdrrecren @@ -0,0 +1,199 @@ +#!/usr/bin/ruby +require 'socket' + +DEBUG=1 +#Port=6419 +Port=2001 + +def SvdrpRecv(s) + lines=Array.new + begin + str=s.readline + lines.push(str) + #puts("SvdrpReceived: " + str + " - |" + str[3,1] + "|" ) if $DEBUG + end while str[3,1]=="-" + return(lines) +end + +def SvdrpSend( s, strSvdrpCmd ) + s.write(strSvdrpCmd + "\n") + l=SvdrpRecv(s) + return(l) +end + +def Svdrp( strSvdrpCmd ) + puts("Svdrp:" + strSvdrpCmd) if DEBUG + s=TCPSocket::new("localhost", Port) + l=SvdrpRecv(s) + l=SvdrpSend(s, strSvdrpCmd) + s.write("quit\r\n") + s.close + return(l) +end + +def CmdRen( num, strNewName ) + cmd=sprintf("MOVR %d %s", num, strNewName) + printf("Aufnahme umbennenen in '%s' ...\n", cmd) + Svdrp(cmd) +end + +if ARGV.size!=2 + printf("invalid arguments: %d\n",ARGV.size ) + exit +end +CMD=ARGV[0] +REC=ARGV[1] +if not File.directory?(REC) + puts("not a directory") + exit +end +RECDATEDIR=File.basename(REC) +RECPATH=File.dirname(REC) +RECNAME=File.basename(RECPATH) +BASEDIR=File.dirname(RECPATH) +EPISODENAME=File.basename(BASEDIR) + +printf("recpath:%s basedir:%s recname:%s recdatedir:%s\n", RECPATH, BASEDIR, RECNAME, RECDATEDIR) +sp=RECDATEDIR.split(".") +RECDATE=sp[0] +RECHOUR=sp[1].to_i +RECMIN=sp[2].to_i +if sp.last()!="rec" + puts("not .rec-dir") + exit +end +#printf("1\n") + +sp=RECDATE.split("-") +RECDAY=sp[2].to_i +RECMON=sp[1].to_i +RECYEAR=sp[0].to_i + +strTime=sprintf("%02d:%02d", RECHOUR, RECMIN); +strDate=sprintf("%02d.%02d.%02d", RECDAY, RECMON, RECYEAR % 100); + +l=Svdrp("LSTR") + +recs=Array.new +printf("Date:%s ; Time:%s\n", strDate,strTime) if DEBUG +l.each do |x| + z=x[4..x.size-1] + sp=z.split(" ") + + #printf("d:%s;t:%s-%s;%s-%s\n", sp[1], sp[2], strDate,strTime, x) + #printf("%s%s|%s %s|%s\n", z, sp[1], sp[2][0,5], strDate, strTime) + if sp[1]==strDate && sp[2][0,5]==strTime + puts("LSTR:"+x) if DEBUG + recs.push(x) + end +end + +if recs.size==0 + puts("Aufnahme nicht gefunden") + exit +end +if recs.size>1 + puts("Aufnahmezeit nicht eindeutig") + exit +end + + +#p(recs[0]) +# Get Rec-Num +rec=recs[0][4..(recs[0].size-1)] +puts("rec:"+rec) if DEBUG +rec_s=rec.split(' ') +num=rec_s[0].to_i +printf("Num:%s\n",num) if DEBUG +# Get Title of Rec +title="" +rec_s[4..rec_s.size].each { |x| title=title+x+' ' } +printf("Title:%s\n",title) if DEBUG +# Get Dir of Rec +dir_s=title.split('~') +dir="" +printf("Dir_s:%s size:%d\n", dir_s, dir_s.size) if DEBUG +if(dir_s.size>1) + dir_s[0..dir_s.size-2].each { |x| dir=dir+x+'~' } +end +puts("Dir: " + dir) if DEBUG +dir_parent="" +dir_parent=dir_s[dir_s.size-2] if dir_s.size>=2 +puts("ParentDir: " + dir_parent) if DEBUG + +# read info.vdr-file +info_title="" +info_short="" +info_desc="" +infofile=REC + "/info.vdr" +if ! File.exists?( infofile ) + infofile=REC + "/info" +end +puts("Infofile: " + infofile) if DEBUG +if File.exists?( infofile ) + puts("Infofile: " + infofile) if DEBUG + f = File.new( infofile ) + lines=f.readlines + f.close + lines.each do |l| + if l[0,2]=="T " + info_title=l[2..l.size].chop + elsif l[0,2]=="S " + info_short=l[2..l.size].chop + elsif l[0,2]=="D " + ld=l.size + ld=80 if ld>80 + info_desc=l[2..ld].chop + end + end +end +#printf("5\n") + +puts("Info Title: " + info_title) if DEBUG +puts(" Short: " + info_short) if DEBUG +puts(" Desc : " + info_desc) if DEBUG +#printf("6 %d\n", DEBUG) + +puts("CMD:"+CMD) if DEBUG +case CMD +when "ShortToName" : + if info_short.size>0 + puts("ShortToName") if DEBUG + newname=(dir+info_short) #.gsub(" ", "\\ ") + CmdRen(num, newname) + end +when "TitleToName" : + if info_title.size>0 + puts("TitleToName") if DEBUG + newname=(dir+info_title) #.gsub(" ", "\\ ") + CmdRen(num, newname) + end +when "DescToName" : + if info_desc.size>0 + puts("DescToName") if DEBUG + newname=(dir+info_desc) #.gsub(" ", "\\ ") + CmdRen(num, newname) + end +when "DirToName" : + if dir_parent.size>0 + puts("DirToName") if DEBUG + CmdRen(num, dir.chop) + end +when "TitleToDir" : + if info_title.size>0 + puts("TitleToDir") if DEBUG + title=info_title.gsub(" ", "_").gsub("(","\(").gsub(")","\)").gsub("/", "#2F").gsub(":", "#3A") + printf("title:%s recpath:%s\n", title, RECPATH) + newdir=BASEDIR+"/"+title + cmd=sprintf("mkdir %s", newdir) + puts(cmd) + system("mkdir", newdir) + cmd=sprintf("mv %s %s", RECPATH, newdir+"/"+RECNAME) + puts(cmd) + system("mv", RECPATH, newdir+"/"+RECNAME) + cmd=sprintf("touch /video/.update") + puts(cmd) + system("touch", "/video/.update") + #system("ls -l") + end +end diff --git a/vdrrecren.rb b/vdrrecren.rb new file mode 100755 index 0000000..a75a1a9 --- /dev/null +++ b/vdrrecren.rb @@ -0,0 +1,144 @@ +#!/usr/bin/ruby + +require 'socket' + +def SvdrpRecv(s) + lines=Array.new + begin + str=s.readline + lines.push(str) + #puts("SvdrpReceived: " + str + " - |" + str[3,1] + "|" ) if $DEBUG + end while str[3,1]=="-" + return(lines) +end + +def SvdrpSend( s, strSvdrpCmd ) + s.write(strSvdrpCmd + "\n") + l=SvdrpRecv(s) + return(l) +end + +def Svdrp( strSvdrpCmd ) + puts("opening socket...") if $DEBUG + s=TCPSocket::new("localhost", 2001) + l=SvdrpRecv(s) + l=SvdrpSend(s, strSvdrpCmd) + s.write("quit\r\n") + s.close + return(l) +end + +def RenameRec( num, strDir, strName) + if strName.size>0 + cmd=sprintf("RENR %d '%s'", num, strDir + strName) + printf("Aufnahme %d umbennenen in '%s'...\n", num, strDir+strName) + #Svdrp(cmd) + end +end + +if ARGV.size!=2 + printf("invalid arguments: %d\n",ARGV.size ) + exit +end + +CMD=ARGV[0] +REC=ARGV[1] + +if not File.directory?(REC) + puts("not a directory") + exit +end +RECDATEDIR=File.basename(REC) +RECPATH=File.dirname(REC) +RECNAME=File.basename(RECPATH) +BASEDIR=File.dirname(RECPATH) +EPISODENAME=File.basename(BASEDIR) + +sp=RECDATEDIR.split(".") +RECDATE=sp[0] +RECHOUR=sp[1].to_i +RECMIN=sp[2].to_i +if sp[5]!="rec" + puts("not .rec-dir") + exit +end + +sp=RECDATE.split("-") +RECDAY=sp[2].to_i +RECMON=sp[1].to_i +RECYEAR=sp[0].to_i + +strTime=sprintf("%02d:%02d", RECHOUR, RECMIN); +strDate=sprintf("%02d.%02d.%02d", RECDAY, RECMON, RECYEAR % 100); + +l=Svdrp("LSTR") + +recs=Array.new +#printf("Date:%s ; Time:%s\n", strDate,strTime) if $DEBUG +l.each do |x| + sp=x.split(" ") + #printf("d:%s;t:%s\n", sp[1], sp[2]) + if sp[1]==strDate && sp[2][0,5]==strTime + recs.push(x) + end +end + +if recs.size>1 + puts("Aufnahmezeit nicht eindeutig") + exit +end + +# Get Rec-Num +rec=recs[0][4..(recs[0].size-1)] +rec_s=rec.split(' ') +num=rec_s[0].to_i + +# Get Title of Rec +title="" +rec_s[3..rec_s.size].each { |x| title=title+x+' ' } +#printf("t:%s\n",title) + +# Get Dir of Rec +dir_s=title.split('~') +dir="" +dir_s[0..dir_s.size-2].each { |x| dir=dir+x+'~' } +dir_parent=dir_s[dir_s.size-2] if dir_s.size>=2 +#puts("D:"+dir) + +# read info.vdr-file +infofile=REC + "/info.vdr" +if File.exists?( infofile ) + puts("reading " + infofile) if $DEBUG + f = File.new( infofile ) + lines=f.readlines + f.close + info_title="" + info_short="" + info_desc="" + lines.each do |l| + if l[0,2]=="T " + info_title=l[2..l.size].chop + elsif l[0,2]=="S " + info_short=l[2..l.size].chop + elsif l[0,2]=="D " + ld=l.size + ld=80 if l.size > 80 + info_desc=l[2..ld].chop + end + end +end + +puts(info_title) if $DEBUG +puts(info_short) if $DEBUG +puts(info_desc) if $DEBUG + +case CMD +when "ShortToName" : + RenameRec(num, dir, info_short) +when "DirToName" : + if dir_parent.size>0 + RenameRec(num, "", dir.chop) + end +when "DescToName" : + RenameRec(nu, dir, info_desc) +end diff --git a/vdrrecren_start b/vdrrecren_start new file mode 100755 index 0000000..6119593 --- /dev/null +++ b/vdrrecren_start @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "/usr/local/bin/vdrrecren $1 '$2' 2>&1 >> /tmp/vdrrecren.log" | at now +echo "Command: /usr/local/bin/vdrrecren $1 '$2' 2>&1 >> /tmp/vdrrecren.log" >> /tmp/vdrrecren.log diff --git a/zeit.sh b/zeit.sh old mode 100644 new mode 100755 index f1008f0..41a4024 --- a/zeit.sh +++ b/zeit.sh @@ -1,6 +1,6 @@ #!/bin/bash -destdir=~/tmp/zeit +destdir=/dat/books/zeit user=mh256 pw=zeit0815 @@ -17,22 +17,24 @@ tmpfile_bl=/tmp/zeit_bl.tmp [ -d $destdir ] || mkdir -p $destdir cd $destdir + +# links zum Download des pdf und epub ermitteln wget --user=$user --password=$pw $url -O $tmpfile pdf_url=$(cat $tmpfile | grep Download | head -n 1 | sed -r 's/href=.(.*pdf).*/\1/') epub_url=$(cat $tmpfile | grep content.*Download | awk -F "\"" '{print $2}') - +# Nummer des Ausgabe zum umbenennen des epub ermitteln number=$(echo $pdf_url | sed -r 's/^.*DZ_ePaper_(.*)\.pdf/\1/' | awk -F_ '{ printf("%s-%s",$2,$1)}' ) - +# links zum download von Beilage und Zeitmagazin ermitteln wget --user=$user --password=$pw $url_zm -O $tmpfile_zm pdfzm_url=$(cat $tmpfile_zm | grep Download | head -n 1 | sed -r 's/href=.(.*pdf).*/\1/') wget --user=$user --password=$pw $url_bl -O $tmpfile_bl pdfbl_url=$(cat $tmpfile_bl | grep Download | head -n 1 | sed -r 's/href=.(.*pdf).*/\1/') - +# alles herunterladen wget --user=$user --password=$pw $epub_url -O die_zeit_20$number.epub wget --user=$user --password=$pw "$url_base/$pdf_url" wget --user=$user --password=$pw "$url_base/$pdfzm_url" wget --user=$user --password=$pw "$url_base/$pdfbl_url" - +# Temp-files loeschen rm $tmpfile $tmpfile_zm $tmpfile_bl