Sonntag, 7. Juli 2013

iTunes mit 2 Tonspuren nutzen

Gestern wollte ich mir Misfits ansehen. Konvertiert hatte ich die Folgen mit Hilfe von VideoMonkey und mp4box.

Leider spielten iTunes und mein iPod beide Tonspuren gleichzeitig ab, während VLC damit keine Probleme hatte, das umzuschalten.

In einem Forum fand ich dann den Hinweis auf Subler. Mit Hilfe von Subler habe ich es nun hinbekommen. In beiden Tonspuren muß dieselbe "Alternate Group" gesetzt werden.

Samstag, 6. Oktober 2012

Time Machine Failing - Get alerted by Growl

I had it now 2 times that my Time Machine backups were failing. First because of a dead hard drive, which I didn't notice for more than a month, second because of - I don't know. It simply failed.

Unfortunately there is no notification at all if this happens. No mail, no hint, no nothing.

So I had the idea to write a small perl script which is checking every hour (by cron) how old the last successful backup is, and give me a growl notification if it's older than 2 hours.

So without any further ado, this is the script. Copy and Paste it into a file called "time-machine-check.pl", make it executable and put into your crontab something like this:

7 * * * * /Users/shk/bin/time-machine-check.pl

to make it execute every 7 minutes after the hour.

#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
use File::Basename;
use Getopt::Long qw(:config no_ignore_case);
use Pod::Usage;

my $MAXAGO= 2;
my $DEFAULTS    = '/usr/bin/defaults';
my $LOCK_FILE   = '/private/tmp/.'.(basename $0);
my $TM_FILE     = '/private/var/db/.TimeMachine.Results';
my $KEY=          'BACKUP_COMPLETED_DATE';
my @READ_BACKUP = ($DEFAULTS, 'read',  $TM_FILE, $KEY);
my @GROWL_NOTIFY= ('/usr/local/bin/growlnotify',
    '-t' => 'Last backup too long ago!',
    '-n' => 'Time Machine',
    '-a' => 'Time Machine',
    '-w',
);

my (
    $test,
    $age,
);

help() unless GetOptions(
    't'          => \$test,
    'a=i'        => \$age,
    'h|help'     => \&help,
    'm|man'      => \&man,
);
$age||= $MAXAGO;

sub help { pod2usage(-verbose=>1); exit; }
sub man  { pod2usage(-verbose=>2); exit; }

# Get date of last successful backup
my $lastbackup= execute(@READ_BACKUP);

my ($y,$m,$d,$H,$M,$S)= ($lastbackup=~ /^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)\s/);
my $ago= time - timelocal($S, $M, $H, $d, $m-1, $y);

# Convert to hours
$ago/= 3600;

# Prepare the message
my $msg;
if ($ago >= 24) {
    $msg= plural(int($ago/24), "%d day", "%d days");
}
elsif ($ago >= 1) {
    $msg= plural(int($ago), "%d hour", "%d hours");
}
else {
    $msg= plural(int($ago*60), "%d minute", "%d minutes");
}

# Do we already have a message and is it younger than 1 day?
my $second_message;
if (-e $LOCK_FILE) {
    my $second_message= 1;
    if (-M $LOCK_FILE < 1) {
        undef $msg unless $test;
    }
}

# Make the message sticky by default
my $sticky= '-s';
if ($ago < $age) {
    # unless it's a test message and not an alert
    $sticky= '';
    undef $msg unless $test;
}

# Now display the message
my $lf;
if ($sticky) {
    open $lf, '>>', $LOCK_FILE;
    print $lf $$,$/;
    close $lf;
    $lf= $LOCK_FILE unless $second_message;
    END {
        unlink $lf if defined $lf;
    }
}
execute(@GROWL_NOTIFY, $sticky, '-m' => "The last successful backup was done more than $msg ago.") if $msg;


sub plural {
    my($num, $singular, $plural, $zero)= @_;
    if ($num == 1) {
        return sprintf($singular, $num);
    }
    if ($zero and not $num) {
        return $zero;
    }
    return sprintf($plural, $num);
}

sub execute {
    open my $in, '-|', @_ or die "Failed to execute\n\t".join(' ',@_).": $!\n";
    $_= do { local $/; <$in> };
    close $in;
    return $_;
}

=head1 NAME

time-machine-check.pl - a small script to notify via growl when no backup was done.

=head1 SYNOPSIS

time-machine-check.p -a hours -t

=head1 DES‎CRIP‎TION

This is a small perl script to be used as a cronjob like so:

7 * * * * /usr/local/bin/time-machine-check.pl -a 2

which will give a growl notification in case the last backup is older than 2 hours.

=head1 OPTIONS

=over 4

=item B<-a> hours

Maximum allowed backup age before notifying.

=item B<-t>

Test option. Notify in any case.

=back

=head1 BUGS

none yet

=head1 TODO

let's see...

=author

time-machine-check-2012.mail.skeeve@xoxy.net

=cut

Samstag, 4. August 2012

MP4 Filme skalieren

Manchmal sind Filme, die ich mit meinem M750S aufgenommen habe, falsch skaliert. Mit mp4box lassen sie sich ziemlich einfach neu skalieren.

Zuerst mit mp4box die aktuellen Maße prüfen:


$ mp4box -info Ab\ durch\ die\ Hecke.mp4 
* Movie Info *
Timescale 1000 - Duration 01:17:24.880
Fragmented File no - 2 track(s)
File Brand isom - version 512
Created: GMT Thu Jan  1 00:00:00 1970


File has no MPEG4 IOD/OD


iTunes Info:
Name: Ab durch die Hecke
Comment: Convertified by iSquint - http://www.isquint.org
Encoder Software: Lavf50.5.0


Track # 1 Info - TrackID 1 - TimeScale 25 - Duration 01:17:24.880
Media Info: Language "Undetermined" - Type "vide:mp4v" - 116122 samples
Visual Track layout: x=0 y=0 width=640 height=480
MPEG-4 Config: Visual Stream - ObjectTypeIndication 0x20
MPEG-4 Visual Size 640 x 480 - Simple Profile @ Level 1
Pixel Aspect Ratio 1:1 - Indicated track size 640 x 480
Self-synchronized


Track # 2 Info - TrackID 2 - TimeScale 44100 - Duration 01:17:24.664
Media Info: Language "Undetermined" - Type "soun:mp4a" - 200029 samples
MPEG-4 Config: Audio Stream - ObjectTypeIndication 0x40
MPEG-4 Audio MPEG-4 Audio AAC LC - 2 Channel(s) - SampleRate 44100
Synchronized on stream 1

Eigentlich sollte der Film in 16:9 sein. Am Einfachsten wird skaliert, indem man die gewünschte Breite errechnet: 480/9*16=853,333...

Ich wähle hier 856 als neue Breite.


$ mp4box -par 1=856:640 Ab\ durch\ die\ Hecke.mp4 





Mittwoch, 11. Juli 2012

MP4 Dateien asynchron

Ich habe ab und an mal ein paar asynchrone MP4 Dateien. Mit mp4box läßt sich das relativ einfach wieder beheben.

Zuerst mit mp4box info async.mp4 prüfen, welche Streams vorhanden sind.


* Movie Info *
Timescale 1000 - Duration 01:29:34.640
Fragmented File no - 2 track(s)
File Brand isom - version 512
Created: GMT Thu Jan  1 00:00:00 1970


File has no MPEG4 IOD/OD


iTunes Info:
Name: Ein Skandal in Belgravia
Artist: Sherlock
Album: Sherlock, Staffel 2
Comment: Convertified by iSquint - http://www.isquint.org
Album Artist: Sherlock
Encoder Software: Lavf50.5.0


Track # 1 Info - TrackID 1 - TimeScale 25 - Duration 01:29:34.640
Media Info: Language "Undetermined" - Type "vide:mp4v" - 134366 samples
Visual Track layout: x=0 y=0 width=640 height=352
MPEG-4 Config: Visual Stream - ObjectTypeIndication 0x20
MPEG-4 Visual Size 640 x 352 - Simple Profile @ Level 1
Pixel Aspect Ratio 1:1 - Indicated track size 640 x 352
Self-synchronized


Track # 2 Info - TrackID 2 - TimeScale 44100 - Duration 01:29:30.450
Media Info: Language "Undetermined" - Type "soun:mp4a" - 231286 samples
MPEG-4 Config: Audio Stream - ObjectTypeIndication 0x40
MPEG-4 Audio MPEG-4 Audio AAC LC - 2 Channel(s) - SampleRate 44100
Synchronized on stream 1


Dann den video track und den (oder die) Audiotracks, letztere mit passendem delay, zu einem neuen Video zusammenfügen:

mp4box -add async.mp4#1=1 -add async.mp4#2=2:delay=1000 -new sync.mp4

Dienstag, 12. April 2011

JavaSCrypt - A crypt(3) implementation in JavaScript

For my Password Generator which I plan to port to JavaScript, I need to have an implementation of crypt(3) for JavaScript.

I quickly found, a source code online, buthad some problems porting it.

Searching the web a bit more I found Michael Dipperstein's page describing a bug, or better, implementation detail which hit him. Applying his changes, I got my JavaScript version running.

So here is the - straightforward - implementation of crypt(3) in JavaScript.



<html>
<head>
<script>
/*
* This program implements the
* Proposed Federal Information Processing
* Data Encryption Standard.
* See Federal Register, March 17, 1975 (40FR12134)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* The source is taken from
* http://google.com/codesearch/p#ZWtxA-fyzBo/UnixArchive/PDP-11/Distributions/research/Henry_Spencer_v7/v7.tar.gz%7C118goTAkg2o/usr/src/libc/gen/crypt.c
* and bug-fixed according to
* http://michael.dipperstein.com/crypt/crypt3.c
*
* permission is granted to use this code at your own will nad risk
* I don't guarantee anything.
*
* Written 2011-04-12 by Skeeve
* mail: javascrypt.v0-1.skeeve et xoxy dot net
*/

function JavaSCrypt() {

/*
* Initial permutation,
*/
const IP = [
58,50,42,34,26,18,10, 2,
60,52,44,36,28,20,12, 4,
62,54,46,38,30,22,14, 6,
64,56,48,40,32,24,16, 8,
57,49,41,33,25,17, 9, 1,
59,51,43,35,27,19,11, 3,
61,53,45,37,29,21,13, 5,
63,55,47,39,31,23,15, 7,
];

/*
* Final permutation, FP = IP^(-1)
*/
const FP = [
40, 8,48,16,56,24,64,32,
39, 7,47,15,55,23,63,31,
38, 6,46,14,54,22,62,30,
37, 5,45,13,53,21,61,29,
36, 4,44,12,52,20,60,28,
35, 3,43,11,51,19,59,27,
34, 2,42,10,50,18,58,26,
33, 1,41, 9,49,17,57,25,
];

/*
* Permuted-choice 1 from the key bits
* to yield C and D.
* Note that bits 8,16... are left out:
* They are intended for a parity check.
*/
const PC1_C = [
57,49,41,33,25,17, 9,
1,58,50,42,34,26,18,
10, 2,59,51,43,35,27,
19,11, 3,60,52,44,36,
];

const PC1_D = [
63,55,47,39,31,23,15,
7,62,54,46,38,30,22,
14, 6,61,53,45,37,29,
21,13, 5,28,20,12, 4,
];

/*
* Sequence of shifts used for the key schedule.
*/
const shifts = [
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,
];

/*
* Permuted-choice 2, to pick out the bits from
* the CD array that generate the key schedule.
*/
const PC2_C = [
14,17,11,24, 1, 5,
3,28,15, 6,21,10,
23,19,12, 4,26, 8,
16, 7,27,20,13, 2,
];

const PC2_D = [
41,52,31,37,47,55,
30,40,51,45,33,48,
44,49,39,56,34,53,
46,42,50,36,29,32,
];

/*
* The C and D arrays used to calculate the key schedule.
*/

var C=new Array(28);
var D=new Array(28);
/*
* The key schedule.
* Generated from the key.
*/
var KS=new Array(
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48)
);
/*
* Set up the key schedule from the key.
*/
function setkey(key) {
/*
* First, generate C and D by permuting
* the key. The low order bit of each
* 8-bit char is not used, so C and D are only 28
* bits apiece.
*/
for (var i=0; i<28; i++) {
C[i] = key[PC1_C[i]-1];
D[i] = key[PC1_D[i]-1];
}
/*
* To generate Ki, rotate C and D according
* to schedule and pick up a permutation
* using PC2.
*/
for (var i=0; i<16; i++) {
/*
* rotate.
*/
for (var k=0; k<shifts[i]; k++) {
var t = C[0];
for (var j=0; j<28-1; j++)
C[j] = C[j+1];
C[27] = t;
t = D[0];
for (j=0; j<28-1; j++)
D[j] = D[j+1];
D[27] = t;
}
/*
* get Ki. Note C and D are concatenated.
*/
for (var j=0; j<24; j++) {
KS[i][j] = C[PC2_C[j]-1];
KS[i][j+24] = D[PC2_D[j]-28-1];
}
}
}

/*
* The E bit-selection table.
*/
var E= new Array(48);
var e= [
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9,10,11,12,13,
12,13,14,15,16,17,
16,17,18,19,20,21,
20,21,22,23,24,25,
24,25,26,27,28,29,
28,29,30,31,32, 1,
];

/*
* The 8 selection functions.
* For some reason, they give a 0-origin
* index, unlike everything else.
*/
const S= [
[
14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
],
[
15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
],
[
10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
],
[
7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
],
[
2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
],
[
12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
],
[
4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
],
[
13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11,
],
];

/*
* P is a permutation on the selected combination
* of the current L and key.
*/
const P= [
16, 7,20,21,
29,12,28,17,
1,15,23,26,
5,18,31,10,
2, 8,24,14,
32,27, 3, 9,
19,13,30, 6,
22,11, 4,25,
];

/*
* The combination of the key and the input, before selection.
*/
var preS= new Array(48);

/*
* The payoff: encrypt a block.
*/

function encrypt(block, edflag) {
/*
* The current block, divided into 2 halves.
*/
var L= new Array(32);
var R= new Array(32);
var tempL= new Array(32);
var f= new Array(32);

/*
* First, permute the bits in the input
*/
for (var j=0; j<32; j++) {
L[j] = block[IP[j]-1];
R[j] = block[IP[j+32]-1];
}
/*
* Perform an encryption operation 16 times.
*/
for (var ii=0; ii<16; ii++) {
/*
* Set direction
*/
var i= (edflag>0) ? 15-ii : ii;
/*
* Save the R array,
* which will be the new L.
*/
for (var j=0; j<32; j++)
tempL[j] = R[j];
/*
* Expand R to 48 bits using the E selector;
* exclusive-or with the current key bits.
*/
for (var j=0; j<48; j++)
preS[j] = R[E[j]-1] ^ KS[i][j];
/*
* The pre-select bits are now considered
* in 8 groups of 6 bits each.
* The 8 selection functions map these
* 6-bit quantities into 4-bit quantities
* and the results permuted
* to make an f(R, K).
* The indexing into the selection functions
* is peculiar; it could be simplified by
* rewriting the tables.
*/
for (var j=0; j<8; j++) {
var t = 6*j;
var k = S[j][(preS[t+0]<<5)+
(preS[t+1]<<3)+
(preS[t+2]<<2)+
(preS[t+3]<<1)+
(preS[t+4]<<0)+
(preS[t+5]<<4)];
t = 4*j;
f[t+0] = (k>>3)&01;
f[t+1] = (k>>2)&01;
f[t+2] = (k>>1)&01;
f[t+3] = (k>>0)&01;
}
/*
* The new R is L ^ f(R, K).
* The f here has to be permuted first, though.
*/
for (var j=0; j<32; j++)
R[j] = L[j] ^ f[P[j]-1];
/*
* Finally, the new L (the original R)
* is copied back.
*/
for (var j=0; j<32; j++)
L[j] = tempL[j];
}
/*
* The output L and R are reversed.
*/
for (var j=0; j<32; j++) {
var t = L[j];
L[j] = R[j];
R[j] = t;
}
/*
* The final output
* gets the inverse permutation of the very original.
*/
for(var j = 0; j < 64; j++) {
var i = FP[j]-1;
if (i < 32)
block[j] = L[i];
else
block[j] = R[i - 32];
}
return block;
}

this.crypt= function (pw,salt) {
const charZ= "Z".charCodeAt(0);
const char9= "9".charCodeAt(0);
const charDot= ".".charCodeAt(0);
var i;
var j;
var c;
var temp;
var block= new Array(66);
var iobuf= new Array(16);
for(var i=0; i<66; i++)
block[i] = 0;
var ii;
for(i=0, ii=0; ii<pw.length && (c= pw.charCodeAt(ii)) && i<64; i++, ii++){
for(j=0; j<7; j++, i++)
block[i] = (c>>(6-j)) & 01;
}
setkey(block);

for(i=0; i<66; i++)
block[i] = 0;

for(i=0;i<48;i++)
E[i] = e[i];

for(i=0;i<2;i++){
c = salt.charCodeAt(i);
iobuf[i] = c;
if(c > charZ) c -= 6;
if(c > char9) c -= 7;
c -= charDot;
for(j=0;j<6;j++){
if(((c>>j) & 01) > 0){
temp = E[6*i+j];
E[6*i+j] = E[6*i+j+24];
E[6*i+j+24] = temp;
}
}
}

for(i=0; i<25; i++)
block= encrypt(block,0);

for(i=0; i<11; i++){
c = 0;
for(j=0; j<6; j++){
c <<= 1;
c |= block[6*i+j];
}
c += charDot;
if(c > char9) c += 7;
if(c > charZ) c += 6;
iobuf[i+2] = c;
}
iobuf[i+2] = 0;
if(iobuf[1]==0)
iobuf[1] = iobuf[0];
var result="";
for (i=0; iobuf[i]>0; ++i) {
result+= String.fromCharCode(iobuf[i]);
}
return(result);
}

}
var javascrypt= new JavaSCrypt;
</script>
</head>
<body>
<form action="javascript:false;">
Pass: <input type="text" name="pwd">
<br>
Salt: <input type="text" name="salt" maxlength="2">
<br/>
<button onclick="this.form.result.value=javascrypt.crypt(this.form.pwd.value, this.form.salt.value)">encrypt</button>
<br>
<input type="text" name="result" disabled="disabled">
</body>
</html>


Samstag, 9. April 2011

Passwort Generator

Ich brauchte mal wieder ein Passwort.

Und als ich mich in meinen Mailaccount einloggte und sah "118" fehlgeschlagene Login Versuche, habe ich mir gedacht, jetzt muß aber mal wirklich was sicheres her.

Da fiel mir ein Applescript ein, was ich vor Äonen mal in einem ehemals guten Appleforum veröffentlicht hatte. Zum Glück gibt es das Script dort noch und ich habe es mal rasch überarbeitet und erweitert.

Anmerkung: Dies ist eine erneut überarbeitete Version.
Anmerkung 2: Und nocheinmal überarbeitet. Außerdem plane ich eine JavaScript Version.

Die Vorteile des Scripts:
  1. Man kann ein simples Passwort eingeben.
  2. Man bekommt daraus immer dasselbe schwierige Passwort generiert.
  3. Dieses schwierige Passwort ist ziemlich sicher nicht zu erraten.
  4. Man kann den Generator immer wieder verwenden um sich sein schwieriges Passwort zu regenerieren. Deswegen braucht man es sich auch nirgends zu speichern.
  5. Es gibt einen "Copy" Knopf mit dem das generierte Passwort in das Clipboard kopiert werden kann um es so einfach per cmd-V zu übernehmen


--
-- Passwort Generator v0.4.2 von Skeeve
--
-- Dies AppleScript darf frei verwendet werden.
-- Es wird keinerlei Gewähr für irgendetwas übernommen.
-- Insbesondere nicht für die Sicherheit der generierten
-- Passworte!
--
-- Fragen und Anregungen bitte an
-- pwdgen.v0-4-2.skeeve et xoxy punkt net
--
on run
set version to "Passwort Generator v0.4.2"
set input to ""
repeat
set input to text returned of (display dialog "Gib Dein Passwort ein." & return & return & "Es wird dann eine sichere Variante generiert." default answer input with title version)
if input ≠ "" then exit repeat
end repeat
repeat
set input to do shell script "perl -e '
$s=substr($_=shift, 0, 2);
$s=substr(crypt($s,$s), -2);
print $s;
print substr crypt($1, $s),2 foreach (/(.{1,8})/g);
' " & quoted form of input
repeat
set choice to display dialog "Gib Dein Passwort ein, um ein weiteres sicheres zu generieren." & return & return & "• Dein sicheres Passwort lautet •" default answer input buttons {"OK", "Copy", "Cancel"} default button 1 with title version
set input to the text returned of choice
set choice to the button returned of choice
if choice is "Cancel" then return
if choice is "Copy" then
set the clipboard to the input
else
exit repeat
end if
end repeat
end repeat
end run

Mittwoch, 28. Oktober 2009

Ich bin diskriminierend

Weil ich ein angeblich diskriminierendes Zitat gebracht habe, habe ich heute meine "Letzte Verwarnung" im Familienforum erhalten. Mal sehen. Vielleicht gönne ich mir zum Geburtstag ja dieses T-Shirt. Immerhin gehen 3€ aufs Konto des FoeBuD e.V..

Aber richtig gefreut habe ich mich über folgenden Beitrag einer Userin: 
Kleingeistige Arschlöcher sind für mich die, die nicht in der Lage sind, sich auf einer objektiven Ebene und sachlich mit einem Thema oder einer Person auseinanderzusetzen.
Und das ausgerechnet von der, die mich ständig als "Flitzpiepe" bezeichnet. In ihrer Weltsicht ist das ein (Zitat) "kleiner nerviger Hosenscheißer". In normaler Sprache bezeichnet man damit eine Person, die nicht ernstgenommen wird. Nunja. Daß mich keiner ernstnimmt, das bin ich gewohnt und das ist mir eigentlich auch egal. Aber wenn etwas als "nicht objektiv" und als unsachlich bezeichnet werden kann, dann doch wohl ganz eindeutig ihr Verhalten mir gegenüber.

Die Folgerung daraus ist klar. Mir war bisher aber nicht bewußt, daß sie so schlecht über sich selbst denkt. Allerdings erklärt das so einiges in ihrem Verhalten. Von daher bin ich echt dankbar für den Beitrag. Ich verstehe sie jetzt viel besser.