Make special keys Just Work · 1092 Tage zuvor von stargaming
I’m using a “Wireless Desktop Edge” from Labtec (image, large). I haven’t cared about the special keys so far (after migrating to Linux), but after a while the mouse became really inconvenient.
Notice: I’m doing this under Sidux (Linux 2.6.22.1-slh-smp-2 #1 SMP PREEMPT Wed Jul 11 01:45:29 CEST 2007 i686 GNU/Linux), KDE-full. YMMV.
Getting keycodes
Retrieving a keycode to a button on the keyboard is pretty trivial. Start the application xev and press whatever button you’d like to know about. Run it in a terminal because the information will go to the console. Close the window when you’re done (or press Ctrl+C).
Along those lines, the latter ones will be the most interesting ones for you (this is the event for my shutdown/hibernate key):
KeyPress event, serial 29, synthetic NO, window 0x3600001,
root 0x1a5, subw 0x3600002, time 826747352, (51,47), root:(55,831),
state 0x0, keycode 223 (keysym 0x0, NoSymbol), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
The keycode is in line 3, if you’ve overseen it.
If you’re too lazy to do this yourself, I can give you my results:
| key | keycode |
|---|---|
| Play/Pause | 162 |
| Stop | 164 |
| Previous | 144 |
| Next | 153 |
| Mute | 160 |
Linking the keycode to a symbolic name
In this step, we’ll utilize the xmodmap tool. There is a good howto from David Vespe, Remapping Keys, but the manual page should be enough for everyone.
For a quick introduction, there is that keycode and there is a “keysym”, a symbolic name for the key. Basically, you can use any symbolic name defined in /usr/include/X11/keymapdef.h (without the KX_ prefix). I found this group symbolic key names for the 3270 terminal and since it wasn’t in use, I took that one. You could overwrite the “Japanese Keyboard Support”, “Braille” or “Vietnamese” as well, I guess.
#define XK_3270_Quit 0xfd09
#define XK_3270_Jump 0xfd12
#define XK_3270_Play 0xfd16
#define XK_3270_DeleteWord 0xfd1a
#define XK_3270_ExSelect 0xfd1b
I took those because I found these names most… symbolic for the keys. ;)
| key | keycode | keysym |
|---|---|---|
| Play/Pause | 162 | 3270_Play |
| Stop | 164 | 3270_Quit |
| Previous | 144 | 3270_ExSelect |
| Next | 153 | 3270_Jump |
| Mute | 160 | 3270_DeleteWord |
You can try mapping keycode to keysym with xmodmap -e, as in:
$ xmodmap -e "keycode 162 = 3270_Play"
$ xmodmap -e "keycode 164 = 3270_Quit"
$ xmodmap -e "keycode 144 = 3270_ExSelect"
$ xmodmap -e "keycode 153 = 3270_Jump"
$ xmodmap -e "keycode 160 = 3270_DeleteWord"
If you go to any KDE application that supports “Global Shortcuts” now, you’ll actually find a reaction to those keys.
Mapping permanently
Now, there are several ways to run those xmodmap commands once per session. But the most convenient is, in my opionion, modifying /etc/X11/Xsession/ to invoke xmodmap ~/.xmodmap at the start of an X session.
XMODMAPFILE=$HOME/.xmodmap
if [ -f $XMODMAPFILE ]; then
xmodmap $XMODMAPFILE
fi
Now, this will source the .xmodmap file in your home directory. You can just fill this with the arguments you gave to xmodmap -e.
keycode 162 = 3270_Play
keycode 164 = 3270_Quit
keycode 144 = 3270_ExSelect
keycode 153 = 3270_Jump
keycode 160 = 3270_DeleteWord
Alternative mapping
If you haven’t got root access, you can perhaps just edit your .Xsession, .xsession or .loginrc (first two confirmed in my /etc/X11/Xsession, latter one from a 10 years old internet source). The line xmodmap $HOME/.xmodmap should be enough in there.
KDE startup manager (updated)
I might have been kinda mislead about the persistance/invokation on KDE. It seems you rather have to edit /etc/kde*/kdm/Xsession. If you cannot edit this document, a file based on your shell might work, too:
| shell | location |
|---|---|
| bash 1 | $HOME/.bash_profile $HOME/.bash_login $HOME/.profile |
| zsh 2 | $zdir/zprofile $zhome/.zprofile $zdir/zlogin $zhome/.zlogin |
| csh/tcsh | /etc/csh.login ~/.login |
| * | /etc/profile $HOME/.profile |
1: only the first existing file in this list is sourced.
2: $zdir is /etc/zsh or /etc, $zhome is ${ZDOTDIR:-$HOME}
Your shell will be determined by your $SHELL variable.

Support in Bugtrackern · 1108 Tage zuvor von stargaming
Manchmal frage ich mich, welche Leute Bugtracker entwerfen.
Bugtracker, das sind spezielle Internetformulare um Fehler in einer Software zu melden. Meist wird die gleiche Prozedur auch als Wunschliste (“Feature Request”) verwendet und man kann häufig, neben der Problembeschreibung auch einen passenden Patch einsenden.
Die meisten Tracker sind leider hoffnungslos überladen und die Entwickler kommen einfach nicht hinterher — die meisten Patches verrotten sogar.
Wenn dann aber bei jedem x-beliebigen Bugtracker von einem 5-Mann-Projekt (kommt mir also bitte nicht mit den bösen Spammern…) eine Registration erforderlich ist, vergeht mir echt die Lust, noch irgendwie mitzuhelfen. Wozu denn der Unfug?

Making of "Spam: Leihgaben ausgewertet" · 1141 Tage zuvor von stargaming
Die tolle Grafik in Spam: Leihgaben ausgewertet wurden anhand dieses Codeschnipsels erstellt.
Ich hab’s mit Python 2.5 getestet. Dazu braucht man noch Matplotlib zum Plotten.
Die Daten werden aus Mbox-Dateien extrahiert — solche legt z. B. Thunderbird im Benutzerordner an. In der aktuellen Einstellung werden da einfach nur alle Beträge in Dollar rausgelesen.
Benutzt wird das Programm mit keinen Programmparametern (dann erwartet es die Daten in der Datei “Test”), sonst kann auch die Quelldatei über die Befehlszeile angegeben werden. Ausgabe passiert immer nach “loans.png”. Die Transparenz (wie im Artikel) habe ich mit Gimp nachgebessert, da ich sonst noch PIL (Python Imaging Library) oder sonstiges benutzen hätte müssen.
- #!/usr/bin/env python
- # encoding: utf-8
- #
- #
- from __future__ import with_statement, division
- # logging
- from logging import *
- basicConfig(level=DEBUG,
- datefmt='%M:%S',
- format='%(relativeCreated)05d %(levelname)8s: %(message)s')
- debug('Enabled log.')
- # reading mbox-format Mailboxes (Mozilla/Netscape)
- debug('Loading mailbox reader..')
- from mailbox import mbox
- # parsing utilites
- debug('Loading email parsers..')
- import datetime as _dt
- _strptime = _dt.datetime.strptime
- from re import compile as _compile
- from operator import itemgetter as _item
- from collections import defaultdict as _dict
- # plotting framework
- debug('Loading plotting framework..')
- import pylab
- info('All packages included.')
- money = _compile(r'''\$(\d{1,3}),000''')
- avg = lambda *a:sum(a) // len(a)
- def main(path):
- info('Opening mbox..')
- repo = mbox(path)
- info('Creating database..')
- loan = _dict(list)
- info('Parsing %d emails..', len(repo))
- for mail in repo.itervalues():
- amount = money.search(mail.as_string())
- if amount:
- date = _strptime(mail.get_from(), '- %a %b %d %H:%M:%S %Y')
- amount = int(amount.group(1).replace(',', ''))
- loan[date].append(amount)
- del repo
- info('Matched %d emails.', len(loan))
- info('Building an average value of every date..')
- loanavg = list()
- for date, amounts in loan.iteritems():
- loanavg.append((date, avg(*amounts)))
- del loan
- info('Sorting results..')
- loanavg.sort(key=_item(0))
- info('Extracting information..')
- x, y = zip(*loanavg)
- x = pylab.date2num(x)
- del loanavg
- info('Plotting %d dates..', len(x))
- debug('Drawing first plot..')
- pylab.xlabel('date')
- pylab.ylabel('loan in $1000')
- pylab.plot_date(x,
- y,
- xdate=True,
- linestyle='-',
- markersize=0.01,
- )
- pylab.axis('tight')
- info('Saving plot to file..')
- pylab.savefig('loans.png', facecolor='white')
- info('Showing plot..')
- pylab.show()
- if __name__ == '__main__':
- from sys import argv
- if len(argv) >= 2:
- main(' '.join(argv[1:]))
- else:
- main('Test')

A bug in matplotlib? · 1168 Tage zuvor von stargaming
I’m just abusing this place to temporarily store the bug report, going to submit it to matplotlib’s bug tracker later.
>>> from pylab import * >>> plot([1], [1]) [<matplotlib.lines.Line2D instance at 0x013A1378>] >>> plot([1], [1]) [<matplotlib.lines.Line2D instance at 0x013A13F0>] </txp:krl_geshiSyntaxHighlight>
- >>> from pylab import *
- >>> plot_date([1], [1])
- []
- >>> plot_date([1], [1])
- """
- Traceback (most recent call last):
- File "", line 1, in
- File "python25\lib\site-packages\matplotlib\pylab.py", line 2064, in plot_date
- ret = gca().plot_date(*args, **kwargs)
- File "python25\lib\site-packages\matplotlib\axes.py", line 2397, in plot_date
- self.xaxis_date(tz)
- File "python25\lib\site-packages\matplotlib\axes.py", line 1566, in xaxis_date
- formatter = AutoDateFormatter(locator)
- UnboundLocalError: local variable 'locator' referenced before assignment
- """
patch to matplotlib\axes.py
1560a1561,1562
> else:
> locator = thislocator

Struggling with Ubuntu · 1169 Tage zuvor von stargaming
I am (again, as some of you might know) struggling with a *nix install on my machine, trying Ubuntu Feisty Fawn (7.04) this time. To share my experiences on the one hand, and to receive some help on the other one, I will write down my progress and efforts so far.
First, you should note that I’m running a AMD Athlon 64 3000+. As far as I explored, all my hardware is ok and appropriate (I’m running Windows on it successfully). Memtest86+ passed without any errors (didn’t try it for a longer period of time but my Windows is running just fine for 2 or 3 days).
32 bit install
Okay, let’s start. I tried to install Ubuntu 7.04 i386 (right, 32 bit, I didn’t want to do without Flash and all this 32 bit pre-ancient stuff) and failed miserably. I got something like the following:
Int 14: CR2 f8000000 err 00000000 EIP c020c384 CS 00000000 flags 00010007
After investigating some time into Google searches, I could only come up with “Flash your BIOS”. Since I’m pretty uncomfortable with harming my computer (yes, a little bit of paranoia here), I’d like to keep this as a very last option. (And as I also read that for some people, this didn’t change anything, I’m not going to try it myself at the moment.)
Ah — if you want sources, just try a quick Google search, I’m refering to the top 10 results mostly.
My first thought was, Whoops! Perhaps, 32 bit does not work that good on amd64 at last? Our funny journey continues.
As a sidenote: I came to the selection screen. This worked all fine, but when I chose “Run or install Ubuntu”, it error’d.
For all those who keep suggesting a BIOS flash: a) My paranoia will drive me nuts if I even consider this one! b) Other people had no success with it. c) It was just some random note from the world wide web and has been documented to work just once. This is no good evidence to make it a general solution. c) Dated BIOS on an amd64? You’re kidding, aren’t you?
64 bit install
Downloaded Ubuntu 7.04 for amd64 machines, burned it to a disk, inserted it into my cdrom, hoping to see a goddamn linux finally, failed again:
Kernel alive
Kernel direct mapping tables up to 100000000 @ 8000-d000
PANIC: early exception rip ffffffff8035c819 error 0 cr2 ffff810040000000
Googled again with a bit more success now. There were several results, either cross-linking to the “Flash your BIOS” thread or suggesting some boot options.
Boot options
acpi=off noapic nolapic
mce=off acpi=off pci=conf1
noacpi=noapm
These were the three main suggestions ol’ mailing list archives gave me.
Note: There is a SuSE distribution installed on my machine. I didn’t install it myself, though, and it freezes occasionally. See below for details.
This matched a recommendation of the person who installed a linux version on this machine and told me he had some trouble with ACPI, too.
However, neither removing quiet nosplash nor adding one of the switches (I even tried to combine them all!) fixed the installation, regardless of the number of bits. I saw a nice text console that gave me lots of warnings like about misallocations on IRQ 0 or something like that (sorry, I could neither read, nor memorize nor scroll up (any hints how to scroll up in these 50% consoles?) fast enough) but it always stopped while * Loading hardware drivers. (If someone helps me to scroll up (no, it obviously isn’t PgUp/PgDown), I could supply additional information.)
Diving into BIOS
As of a hint of the previous maintainer, that pointed towards disabling ACPI, I started my (rather badly computer-translated BIOS (I’m german, as some may have noticed) ;)) BIOS setup. In the Energy (I’m retranslating them for easier comprehension) tab, there were two adequate entries:
ACPI Suspend Type [S1&S3]
ACPI APIC support [Deactivated]
No other mentions of ACPI. If you need further information, I’m happy to supply my BIOS’ version.
Help!
If you got any hints, feel free to use the comment form or write an email to stargaming (at) gmail (.) com. Thank you.
scroll up shift+bildauf/bildab — ChosenOne (“bildauf” means PgUp, “bildab” means PgDown)
32 bit alternate install
Just (one day later) tried Ubuntu 6.10’s 32 bit alternate version (for all those who aren’t comfortable with the normal installation). Guess what — failed again.
Unknown interrupt or fault at EIP 00000060 c0100231 00000230
Google yields a number of results this time, mostly pointing towards a broken disk. However, I won’t waste another blank CD except anyone will convince me that those alternative installs have a chance to fix my problems.
Retry alternatives.
Welcome again to our show. Our last episode terminated with “EPIC FAIL” (4chan-insider, sorry).
I’m writing the following report like one and a half month after it happened. I might mix some events up, be unable to read my handwritings whilst installation or not remember what actually happened, however, just keep in mind: It. Did. Not. Work. At all. (It not “just works”, geez!)
So, I retried the latest alternate disk and it even kinda worked. I tried pci=conf1, noacpi and noapic and all resulted in an interrupt 14. With acpi=off I could — attention now, dear audience — enter the textmode install. It threw some mysterious (apparently not too bad) exceptions about IRQ #11.
When in hardware initialization mode, these wonderful messages popped up:
ata: SATA link up 1.5 Gbps (status 113 control 300 qc timeout)
failed to set xfermode
speed UDMA
failed to recover some devices, retrying in 5 seconds
This procedure repeated about 6 times (connected with some CD acticity) and finally resulted in a textmode install. If you’re young and naive, you could think (or yell) now, “Oh, it worked! That’s wonderful, go on with the textmode and install Ubuntu. Finally.”
You failed. I went through the setup — ecstatic to the limit — and finally came through partitioning. “So, where will I put my Ubuntu now? The 120 Gb disk or the 80 Gb one?” But that’s not at all what the setup asked. It was “120 Gb hdd. Ok?!” No, damn, that was not okay at all!
That’s it again. I aborted the installation, unplugged the CD and rebooted Windows. “It just works.”
If you’re interested, I also had to switch the CD over to another drive because the slave one threw an Incorrect CD-ROM detected error. Just another whack of my weird, weird computer setup.
Why not another Debian?
Hello and welcome back. Due to some recent recommendations, I tried Sidux, another Debian derivate. And you can believe me or not, it worked. I started it up in normal mode (there are quite a few options for debugging erroneous machines — perhaps gonna try those later) with a nice KDE desktop and a console and internet access and all this stuff.
Unfortunately, the disk setup didn’t work, again. It just recognized this one hdd and I really don’t want to install it there.
I was unabled to find any dmesg, /var/log was all over populated with empty files (except some binary junk).
Plans
So, I got a few new plans and if you’d like to support me, you could tell me some advantages/disadvantages about them or even suggest other actions.
First, I will try the other boot options of Sidux. Probably their hardware diagnostics are good enough to get my machine to work.
If this all won’t work, I will perhaps try to unplug some hardware devices. I emphasize perhaps because, as I stated before, I really, really, really got some kind of technophobia. All this stuff is fine, I know how it works, theory is okay. But touching it? Uh — never! “Never touch a running system.”
Thank you for reading so far.
IT JUST WORKS
Wow. Sidux works when started in the ‘noapic’ mode. I can finally access all hdds and install it. End of the story.
Appendix A — Hardware details
- AMD Athlon™ 64 3000+, ACPI-PC
- HDDs (all connected as master IDE devices)
- Maxtor
- Samsung, Secondary ATA channel
- Samsung, Primary ATA channel
- two standard cd/dvd rom/ram devices
- nVidia GeForce 6600 GT
- nVidia nForce 4 Serial ATA Controller
- nVidia nForce Networking Controller
- some ACPI, DMA, ACPI, PCI stuff
Kommentieren [2]

Mirroring · 1209 Tage zuvor von stargaming
Dank Armin Ronacher (der mich auf den entscheidenden Tipp gebracht hat, Informationen einfach in einem Funktionsattribut zu speichern), ist folgendes Codeschnipselchen entstanden:
- class Mirroring(type):
- def __new__(meta, name, bases, clsdict):
- for key, value in clsdict.items():
- if hasattr(value, 'func_code') and hasattr(value, '_mirroring'):
- for mirror in value._mirroring:
- for alias in mirror[0]:
- if alias not in clsdict:
- clsdict[alias] = lambda *a, **k: value(*a, **k)
- clsdict[alias].__name__ = alias
- if mirror[1]:
- clsdict[alias].doc = mirror1
- else:
- clsdict[alias].__doc__ = \
- getattr(value, '__doc__', None)
- return type.__new__(meta, name, bases, clsdict)
- def mirror(*names, **doc):
- def wrapped(f):
- if not hasattr(f, '_mirroring'):
- f._mirroring = []
- f._mirroring.append((names, doc.get('doc', None)))
- return f
- return wrapped
Benutzt wird es in etwa so:
- class A(object):
- __metaclass__ = Mirroring
- @mirror("bar", doc="abkuerzung fuer foo")
- def foo(self):
- "irgendeine wichtige methode"
- print "hi!"
- a = A()
- a.foo() # hi!
- a.bar() # hi!
- print a.foo.__doc__ # irgendeine wichtige methode
- print a.bar.__doc__ # abkuerzung fuer foo
Mirroring muss als Metaklasse gesetzt werden, um das Injizieren der Aliase zu ermöglichen. mirror nimmt als Argumente arbiträr viele positionale Namen auf die gespiegelt wird und eine Schlüsselwortargument doc (andere werden verschluckt), welches die Dokumentation ergibt.
Nützlich ist das zum Beispiel in cmd.Cmd, wo jeder Befehl der Kommandozeile mit einer Methode do_Befehl registriert wird.
- __metaclass__ = Mirroring
- class Cmd(cmd.Cmd):
- @mirror('do_q', doc='shorthand for quit')
- def do_quit(self):
- exit()

PyPy erfindet nebenbei geile Syntax · 1216 Tage zuvor von stargaming
Das PyPy 1.0 draußen ist, dürfte ja mittlerweise die Runde gemacht haben (Jacob Hallen zu PyPy).
Jedenfalls ist mir beim Durchstöbern der Bibliotheken dort etwas Spaßiges aufgefallen:
- class __extend__(IrgendeineAndereKlasse):
- def angehangeneMethode(self):
- ...
Das Ganze geht zurück auf eine sehr schöne Metaklasse (die auf IrgendeineAndereKlasse angewendet werden muss):
- """
- class X:
- __metaclass__ = extendabletype
- ...
- # in some other file...
- class __extend__(X):
- ... # and here you can add new methods and class attributes to X
- """
- class extendabletype(type):
- """A type with a syntax trick: 'class __extend__(t)' actually extends
- the definition of 't' instead of creating a new subclass."""
- def __new__(cls, name, bases, dict):
- if name == '__extend__':
- for cls in bases:
- for key, value in dict.items():
- if key == '__module__':
- continue
- setattr(cls, key, value)
- return None
- else:
- return super(extendabletype, cls).__new__(cls, name, bases, dict)
Was es erlaubt, Klassen in anderen Dateien als der Deklarationsdatei zu “erweitern” (ja, es ginge auch über die Zuweisung Klasse.methode = ..., ist aber lange nicht so schön).
Speziell kommt das aus der Datei pypy/tool: pairtype.py.

Postfix type declarations · 1217 Tage zuvor von stargaming
Der beste Aprilscherz (abgesehen von unserem und bereits erwähnten) ist Georg Brandls Vorschlag der Unicode Postfix type declarations.
Nachtrag: Haah, Python on Planes.
Ausschnitte
Python has long suffered from the lack of explicit type declarations. [...]
Unicode makes it possible to express much more with much less characters, which is in accordance with the Zen (“Readability counts.”). Additionally, it eliminates the need for a separate type declaration statement, and last but not least, it makes Python measure up to Perl 6, which already uses Unicode for its operators. [...]
When the type declaration mode is in operation, the grammar is changed so that eachNAMEmust consist of two parts: a name and a type declarator, which is exactly one Unicode character.
The declarator uniquely specifies the type of the name, and if it occurs on the left hand side of an expression, this type is enforced: anInquisitionErrorexception is raised if the returned type doesn’t match the declared type. [...]
The mapping between types and declarators is not static. It can be completely customized by the programmer, but for convenience there are some predefined mappings for some built-in types:
| object | � | (REPLACEMENT CHARACTER) |
| int | ℕ | (DOUBLE-STRUCK CAPITAL N) |
| float | ℮ | (ESTIMATED SYMBOL) |
| bool | ✓ | (CHECK MARK) |
| tuple | ⒯ | (PARENTHESIZED LATIN SMALL LETTER T) |
| dict | ⧟ | (DOUBLE-ENDED MULTIMAP) |
| set | ∅ | (EMPTY SET) |
| function | ƛ | (LATIN SMALL LETTER LAMBDA WITH STROKE) |
The declarator for the
Nonetype is a zero-width space.
These characters should be obvious and easy to remember and type for every programmer. [...]
Since even in our modern, globalized world there are still some old-fashioned rebels who can’t or don’t want to use Unicode in their source code, and since Python is a forgiving language, a fallback is provided for those:
Instead of the single Unicode character, they can typename${UNICODE NAME OF THE DECLARATOR}$. [...]
The encoding in which the code is written is read from a standard coding cookie. There will also be an autodetection mechanism, invoked byfrom __future__ import encoding_hell.

double negation, anyone? · 1244 Tage zuvor von stargaming
While discussing the introduction of a bool keyword to Python because not is a keyword, too, we (you may consider this either as ‘we, our majesty’ or ‘we, the python folks’) came up with a funny observation: our getattribute-mechanism sucks.
Well, I just fooled you. Semantically and when in use, it’s pure ownage. But it’s speed — aww! Not as if python programmers were speed zealots (“If I uglify my source code enough, it’ll be 0.001ms faster, yeeha!”), but it’s an historic semi-issue that getattr is — because of the comfortability of python’s attribute mechanism — slow. But since no one addresses it, it’s not a real issue.
I will illustrate this with the example mentioned above, the bool discrimination and how to more or less solve it: Double negation. :-)
First, watch this:
- >>> import dis
- >>> def foo():
- ... not not 5
- ...
- >>> dis.dis(foo)
- 2 0 LOAD_CONST 1 (5)
- 3 UNARY_NOT
- 4 UNARY_NOT
- 5 POP_TOP
- 6 LOAD_CONST 0 (None)
- 9 RETURN_VALUE
- >>> def foo():
- ... bool(5)
- ...
- >>> dis.dis(foo)
- 2 0 LOAD_GLOBAL 0 (bool)
- 3 LOAD_CONST 1 (5)
- 6 CALL_FUNCTION 1
- 9 POP_TOP
- 10 LOAD_CONST 0 (None)
- 13 RETURN_VALUE
You can mostly ignore the two last lines of the disassembly because it’s just to return None — pretty interesting if you think about it. So, our first result is: Both operations take exactly the same number of opcodes (6, to be precise) to compute the same thing. bool() is getattr and call, not not is twice a unary not. Let’s go ahead.
- $ python -m timeit -n 10000000 "not not 5"
- 10000000 loops, best of 3: 0.149 usec per loop
- $ python -m timeit -n 10000000 "bool(5)"
- 10000000 loops, best of 3: 0.605 usec per loop
Oww, what’s that? Double negation is around four times faster than bool(). I’m proud to introduce the new boolean idiom to you: not not object

Snippet of the moment III · 1261 Tage zuvor von stargaming
- #!/usr/bin/env python
- # encoding: rot13
- # insert code here
Python wird dann den Quelltext direkt mit rot13 verschlüsseln/entschlüsseln (was ja bei ROT13 keinen Unterschied macht). So könnte man auf einfache — wenn auch sehr rudimentäre — Art und Weise seine Skripte verschlüsseln (vorher selbst mit ROT13 verschlüsseln und dann diese Direktive einfach oben eintragen). ;)

