So, das Jahr läuft ja wieder. Kurzer Rückblick auf den Kongress: Was mich interessiert habe ich im Wesentlichen gesehen. Besonders gefallen haben mir "Packets in Packets" von Travis Goodspeed, "The Science of Insecurity" von Meredith Patterson und "Cellular protocol stacks for Internet" von Harald Welte.
Unterhaltsam (und sehr zu empfehlen, wenn man von dem Thema noch nichts im Detail gehört hat) ist der Vortrag zum Staatstrojaner.
Etwas, das mir bisher durch die Lappen gegangen war, ist das Nick Farr Bullshit Bingo das kurz vor dem "Security Nightmares" talk ablief. Spassig.
Die Videos sind praktisch vollständig auf youtube, sowie in höherer Videoqualität auf den üblichen Quellen beim CCC, zu sehen.
Kurz erwähnt sei noch, daß das FEM dieses Jahr einen super Job bei den Streams gemacht hat. Daumen hoch, für alle die da mitgearbeitet haben. Auf die Leistung darf man auch ruhig mal stolz sein.
Heute noch schnell "Stephanus steinigen" und schon geht morgen der diesjährige Chaoscongress los.
Wie immer interessiert einen natürlich nicht alles. "A Brief History of Plutocracy" juckt mich zum Beispiel jedenfalls nicht besonders. Auf andere Veranstaltungen habe ich dagegen jede Menge Lust:
Tag 1 (27.12.2011)
- The Atari 2600 Video Computer System: The Ultimate Talk (12:45, Saal 3) Um. Yay! So eine Kiste war das erste Computerspielsystem für mich.
- Der Staatstrojaner (16:00, Saal 1)
- 802.11 Packets in Packets (18:30, Saal 1) Physical-Layer Attacken für den geneigten Nachrichtentechniker
- Black Ops of TCP/IP 2011 (23:00, Saal 1) Bin nicht so richtig sicher, was das hier werden soll. Aber den Vortrag gab's wohl schon auf der Defcon und der BlackHat; und Dan Kaminsky ist eigentlich imm für einen zumindest sehr unterhaltsamen Vortrag gut...
Tag 2 (28.12.2011)
- Reverse Engineering USB Devices (14:00, Saal 2) Wieder ein Hardwarevortrag für den Nachrichtentechniker in mir.
- The Science of Insecurity (16:00, Saal 1) Bei dem Ding bin ich mir wieder mal nicht sicher was das geben soll, aber die Beschreibung klingt interessant genug, daß ich hier definitiv genauer hinsehen werde.
- Hacking MFPs, Part 2 - Postscript: Um, you've been hacked (17:15, Saal 1) Allein die versprochene Einführung in die Sprache wird mich diesen Vortrag schauen lassen.
- Reverse Engineering a Qualcomm baseband (20:30, Saal 3) Wieder was Hardware-nahes. (Vielleicht sollte ich mir vorher nochmal den "All your Baseband are belong to us" Vortrag vom letzten Jahr ansehen...)
- Apple vs. Google Platforms (How you end up being the victim) (21:45, Saal 1)
Tag 3 (29.12.2011)
- TRESOR: Festplatten sicher verschlüsseln (14:30, Saal 2) Benutzt ein Debugging Register vom x86-64 um den Schlüssel abzulegen? Okay.
- Cellular protocol stacks for Internet (17:15, Saal 1) ...dieses Jahr ist eine Menge dabei, was in die Nachrichtentechnik fällt. I approve.
- Behind the scenes of a C64 demo (21:45, Saal 3) Demo-scene-lastiger Talk aufm C64. (Fabian, ließt du das hier? *g*)
Tag 4 (30.12.2011)
- bup: Git for backups (13:15, Saal 2) Eigentlich bin ich ja der Meinung, daß git dafür nicht direkt perfekt geeignet ist. Aber vielleicht werde ich ja eines Besseren Belehrt.
Tja, der letzte Tag ist etwas dünn besetzt für meinen Geschmack. Aber egal. Neben dem Genannten gibt's natürlich die Alle-Jahre-Wieder Nummern wie "Jahresrückblick", "FNORD Newsshow", "Hacker Jeopardy", "Security Nightmares" etc., die sich normalerweise auch lohnen.
Werde wohl nicht alles live schauen können, aber es gibt sicher wieder Aufnahmen von fast allen Veranstaltungen, die man sich dann auf langeren Zugfahrten geben kann.
Mein Kumpel Fabian weist mich auf etwas bizarres hin. Ich wette, daß ist nicht das erste Mal, daß das jemandem auffällt, aber es ist zu schön um es nicht zu verbloggen...
Wenn man nicht aus dem schönen Deutschland am Internet teilnimmt, dann kennt man das Problem vielleicht gar nicht. Schon bei den lieben Nachbarn in Östereich greifen die Maßnahmen, die hier zu Hause so vielen auf die Nerven gehen, nämlich nicht.
Die Situation ist immer die gleiche: Man hört von einem Künstler und will mal bei youtube reinhören, ob man in Geld in ein neues, oder auch altes, Werk investieren soll. Bei uns bekommt man da aber immer häufiger folgendes:
Das, nebenbei, auch in offiziellen Band- oder Labelkanälen.
Offenbar ist es schmerzhaft genug sich mit der Gesellschaft auseinander zu setzen, daß die Labels hingehen und sich ihr eigenes youtube zurecht schrauben. Was!? Nein, wirklich. Das Video, das mir youtube verwehren will darf ich bei universalmusic.com schauen so oft ich will:
Wer den Laden der für die lustigen youtube Vorenthalte zuständig ist noch nicht so richtig kennt, der überfliege mal den entsprechenden Wikipedia Artikel. Insbesondere den "Kritik" Abschnitt.
Und aus gegebenen Anlaß schaue ich mir nun eine Nummer der Band "Eure Mütter" an (die Mütter sind eh gut - man klicke ruhig mal weiter!). In diesem Sinne. Rinnjehaun.
Post Scriptum: Nein, ich kaufe keinen Godsmack Tonträger. Keine Sorge.
Ich mag den Original-Film ja sehr. Und diese Version ist auch großartig:
Evil Dead, in 60 Sekunden. Mit... Knete. - Oh yeah.
I just released version 4.0 of arename, your friendly neighbourhood audio file batch renaming application.
The highlights of this release are a new audio file handling backend, which allows for many more supported file formats, a new template parser which implements a much more powerful template syntax and an rewritten output system with clearer semantics and support for colourful output (which can be deactivated if so desired). In other words, the three most integral parts of the program have been entirely redone. This could not be done, without breaking some backward compatibility. This is why this release took so long and is a major version update.
I've gone into some detail about those before, so I won't do it again.
I've let arename v4.0 run across my 170GiB of audio files and it behaved exactly as expected. If you should run into any problems, then you'll be happy to hear that this is also the first release with an enabled bug tracker.
Here are a number of direct links to help you along:
- Version 4.0 release tarball
- UPGRADING document - required reading
- CHANGES, the user's changelog
- The git repository at github
- the bug tracker at github
If Maximilian finds the time, then - who knows - maybe this release will hit Debian and Ubuntu servers soon. They're currently stuck with version `3.1'.
[-Epilogue-]
I have already merged the latest work (the `extensions' branch) into the `master' branch of the repository. It implements extensions as Perl modules and is supposed to streamline the idea of minimising the changes to the core module `ARename.pm'. So, if you're interested in that, try the master branch.
It'll let you do the following in your `hooks' file to enable replacing spaces with underscores, for example:
use ARename::RemoveSpaces;
ARename::RemoveSpaces::register();
I've been going on about arename version four for a while now. Like in "it'll be the best thing since sliced bread" kind-of preaching. It won't be that good, obviously. But it will deal with a few smaller or bigger problems that version three had.
The biggest problem with arename is, that it started out as a quick hack. I just wanted to keep the names of my music library in line and there was virtually nothing out there that could do it. And when there was something promising featurewise, it was always obscure enough that I wouldn't trust my whole library to it. After all having to re-rip all my audio CDs would be a major undertaking.
Anyway. The point is, that I never had planed to add so many features. With version 1.0, I was sure it was feature-complete; same for 2.0. After that I realised, I would have to restructure things a little. To give you an idea: I was running out of decent single-letter options. So I needed to break backwards compatibility. Which is why version 3.0 happened less than a year after 2.0.
And 4.0 is (or rather, will be) much of the same. I wanted support for more file types and wanted to get rid of a lot of the ugly glue to hide the differences between the backends I used, so I had to switch to a different, more capable, backend: Audio::Scan.
A new backend surely meant breaking backward-compatibility - again. There was no way around that. So I figured "In for the penny, in for the pound...", and decided, I should rewrite the template parser, too.
The old one was a pretty naive approach at expanding the template. It's actually possible to send the code into an endless loop with properly contructed tag-values. And that's obviously a-bad-thing[tm].
I wouldn't just rewrite the parser into something sane, no, I would also extend its features. So there goes backward compatibility (yeah... again). Most old templates will still work as they used to, however. You'd need to have fairly twisted things in there for the behaviour to change... but still.
Then, kind of as a last-minute thing, I completely rewrote the old output system (the `--verbose', `--quiet', `--uber-quiet' mess). So that breaks compatibility, too. Albeit, I tried to be reasonable here and not throw errors here, but replicate the old behaviour as much as possible and deprecate the old options (they definitely will be removed at a later point).
After all that compatibility breakage, what is the new stuff in arename4 capable of doing?
First of all, there are a lot more supported file types. It used to be `mp3', `ogg' (ogg vorbis, that is) and `flac'. Now the list looks like this:
- AAC: aac
- APE: ape, apl (Monkey Audio)
- ASF: wma, wmv, asf
- FLAC: flc, flac, fla
- MP3: mp3, mp2
- MP4: mp4, m4a, m4b, m4p, m4v, m4r, k3g, skm, 3gp, 3g2, mov
- MPC: mpc, mpp, mp+ (Musepack)
- OGG: ogg, oga
- WAV: wav, aif, aiff
- WV: wv (WavPack)
And that's all thanks to Audio::Scan, which also unifies the meta-data reading process, so all file-type specific processing (esp. hooks) is gone now.
Also, like I said, the output system was completely rewritten. For the user, on the one hand that means: the level of verbosity is handled by exactly one option: `--verbosity'. On the other hand, there are colours now. Yes, arename4 output looks like this now:
If you're one of those guys, who think colours are made in hell, you can turn them off by doing the following in your shell setup:
ARENAME_SUPPRESS_COLOURS=1
export ARENAME_SUPPRESS_COLOURS
And finally, templates are now vastly more powerful. Let me show you. The plain old template still may look just like this:
&artist - &album - &tracknumber - &tracktitle
If you're like me, and define a lot of templates directly on the command line, that sucks because it's a lot to type. If you enable the `template_aliases' option in your configuration, you can do the same like this:
&ar - &al - &tn - &tt
Now, say you got a few tracks in your library that lack a proper album name. Back in the olden days, you'd hack up a `pre_expand_template' hook that does something about that. And indeed such a hook is still included in the `arename.hooks' example file.
But if you'd just like to insert a "" for missing albums you can now do:
&ar - &{al:<noAlbum>} - &tn - &tt
The "&{foo:bar}" form inserts `bar' if the `foo' tag is not available in the current file. Nice, huh? Now say, you'd just like to drop the album and tracknumber parts entirely if the album tag is missing. You'd do this:
&ar - &{al?&al - &tn - !}&tt
The &{foo?bar!baz} form inserts `bar' if `foo' is set and `baz' if it is unset. On top of that, you can nest these expansions as much as you'd like. That means that both `bar' and `baz' will be expanded just as a normal template string would be. That is why we can just use "&al" etc. in the `bar' part in the example above.
Here are those examples in action:
That's most of the major user-visible changes in version 4.
Code-wise, I think the new release will look a lot more pleasant than any arename before. Feature-wise, I think (for real, this time) arename can do everything anyone could ever want, since special needs can be handled in user-defined hooks. And I'd rather add more hooks than adding any more core features.
Roadmap-wise, the plan looks like this: release 4.0 soon-ish. And fix bugs as they come in. Then, after a year or two, remove all the deprecated stuff and release a further cleaned-up version 5, with which I'd like t conclude arename's active development any switch the project into maintenance only mode.
Needless to say, you're welcome to try arename v4.0-rc2 today. Clone the repository from github, generate the scripts and documentation and finally run the test-suite:
% git clone git://github.com/ft/arename.git
% cd arename
% make genperlscripts
% make doc
% make prepare-test-data
% make test
% sudo make install install-doc
You'll need a few things to run the test-suite (`prepare-test-data' and `test'). See the TESTING file for details. If you have all the prerequisites in place, none of the above should fail. If it does, please report.
If you find anything else that is off, please report. There is also a REPORTING_BUGS file now.
That's it for now. Give arename4-rc2 a spin and tell me if it misbehaves. Use the `--dryrun' (short: `-d') option to see what would be done before leaving it out.
A while back when I finished rewriting arename's meta-data-reading code, I ran some tests to measure the performance of the new code compared to the old one.
The new code uses Audio::Scan to read data from input files, while the old code used multiple backend modules: MP3::Tag, Ogg::Vorbis::Header and Audio::FLAC::Header. The idea behind changing such an integral part of arename was to remove a lot of the layer that was hiding the differences between the different backends, to get support for more file types and to get significantly improved performance.
To see whether the latter part was achieved, I did the following:
This compares the performance of arename version 3 to the one of version 4.
The test was done on the following OS:
% uname -srm
Linux 2.6.32-5-686 i686
% /lib/libc.so.6
GNU C Library (Debian EGLIBC 2.11.2-7) stable release version 2.11.2,
by Roland McGrath et al.
[...]
Compiled by GNU CC version 4.4.5.
Compiled on a Linux 2.6.32 system on 2010-10-31.
The computer, that was used, is an IBM T60 laptop, equipped with 2GiB of RAM, a 1.66GHz Intel Single Core CPU (1MiB of Cache) and a Fujitsu MHZ2160B SATA harddisk (5400rpm).
The shell used here is zsh. The array `$files[]' is a list of 7495 audio files (mostly .mp3 and .ogg), created using:
% files=(**/*.(#i)(mp3|flac|ogg)(.))
The Linux version used doesn't have a maximum size for external commands, so this works without xargs or other tricks. The total size of the files is about 40GiB.
Using the array defeats the need to produce a file list before actually running arename. Arename is also run in very quiet and dry-run mode.
The audio files reside in a AES-256 encrypted ext2 partition.
The "cold cache" situation was created by using
% sync; echo 3 > /proc/sys/vm/drop_caches
with appropriate privileges.
The v4 times were produced using the code from this commit:
e9f672d3132e1a15607e1a3d62fdde06022a4695
The v3 times are based on code from this commit:
5be0e68ffcd407b643759084e07c305581f4052f
Here are the version three times:
Cold cache:
% arename -dQ "${files[@]}" > /dev/null 2>&1
33.07s user 3.58s system 14% cpu 4:18.06 total
Warm cache:
% arename -dQ "${files[@]}" > /dev/null 2>&1
18.67s user 1.04s system 88% cpu 22.178 total
And in comparison, the version four times are as follows:
Cold cache:
% arename -dQ "${files[@]}" > /dev/null 2>&1
9.23s user 2.70s system 5% cpu 3:46.39 total
Warm cache:
% arename -dQ "${files[@]}" > /dev/null 2>&1
4.87s user 0.51s system 87% cpu 6.151 total
The `total' values in warm cache fluctuate a little, but the v4 times are settling down at just under four times the speed of the v3 times. The cold cache times have not improved quite as impressively. But here, hard-disk performance is the likely bottleneck.
I found myself doing the same thing all the time and wanted to automate the task. What it was? Well, I was selecting internet addresses with the mouse in X11, opening a new tab in firefox and then pasted the uri into the newly created tab, which makes firefox load the URI. Then I was clicking something else to clear the selection buffer again, to avoid accidental pastes into my IRC client.
Doing that manually over and over again sucks, so a script had to be written. That's easy enough and I got a script going which uses either `xsel' or `xclip' to manipulate the X11 selection buffer and does stuff according to what's in that buffer - all that is configurable, obviously. One such handler would be to do "firefox -new-tab $thatURI".
Now the do-something part was quite straight-forward and easy. Surprisingly, the hard part was to clear the buffer afterwards. You'd say that "xsel -c" will do the trick, but when you can still hit the middle-mouse button to paste text back into xterm, then something is off.
Here's what's going on: X11 has multiple selection buffers: Actual selection buffers (primary and secondary), the clipboard buffer and finally (and most annoyingly) cut-buffers, of which there are eight by default.
Most applications I know use the primary selection. Some use the clipboard buffer, too, like applications in which you can select `Cut' or `Copy' from context menus and such. I've never seen anything use the secondary selection.
And the cut-buffers... well, cut buffers are the older, limited brothers of selections and as jwz put it so aptly in his X Selections text:
Cut Buffers: Obsolete. Never, ever, ever use them. Ever.
And so, I didn't think anything used that stuff anymore. But some do... Like `xterm', which is the terminal emulator of my choice. By default it puts stuff into the primary selection buffer and into the first cut-buffer. To take a look at cut-buffers, you can use the `xcb' application.
But I really don't want to fiddle with these things. I want to follow jwz's advise and just leave them be. So I told `xterm' to stop being an idiot by adding the following to my ~/.Xresources file:
!! Do NOT use cut buffers in xterm. They are evil and obsolete.
*VT100*translations: #override \n\
~Shift~Ctrl<Btn2Up>: insert-selection(PRIMARY) \n\
Shift~Ctrl<Btn2Up>: insert-selection(CLIPBOARD) \n\
<BtnUp>:select-end(PRIMARY)
That tells the terminal to select to the primary selection when selecting text with the left mouse button - and not into anything else. And it also tells it, to insert the primary selection when the middle mouse button is pressed and to insert the clipboard buffer when Shift is held along with the middle mouse button (in case I need to access it because some application feels like using it).
There. My world just got a little saner again. \o/
Ever misplaced a stash in git? Like, you accidentally entered "git stash drop" instead of "pop"? Or you did pop, but then went ahead and thoughtlessly did a "git reset --hard"?
If there just went a day's work, you'll be pissed. At yourself mostly, but still. You'll try "git reflog", as always when you've screwed up. However this time, it doesn't help. Things are screwed six ways till Sunday, you're in tears, co-workers laugh at you and your boss threatens to can your sorry ass. But wait, there is help. Unless you've also "git prune"d your repository...
Using "git fsck --unreachable" you can have a list of stuff that's still there, but "unreachable" from the usual tree. You can still say "git show -p $id" to take a look at the unreachable stuff, though. And that's where the magic is. Now, depending on your workflow, there could potentially be a lot output from said command. So let's just throw a bit of Perl at it to run through all the lines one by one:
#!/usr/bin/perl use warnings; use strict; my ($dat, $line, $y); $y = 0; open $dat, "git fsck --unreachable |" or die "Couldn't run `git-fsck': $!\n"; LINE: while ($line = <$dat>) { chomp $line; my ($u, $type, $id) = split / +/, $line; next LINE unless ($type eq 'commit'); print "\n Showing `$id'\n\n"; system(( "git", "show", "--patch", "$id" )); print "\n Has this been the commit you were looking for? (y/N) "; my $ans = <STDIN>; chomp $ans; if ($ans eq 'y' || $ans eq 'Y') { $y = 1; print "\n The chosen commit's id is: `$id'\n\n"; last LINE; } } if ($y != 1) { print "\n Sorry, I couldn't help you it would seem.\n\n"; } close $dat;
Throw that into an executable file "git-unreachable" somewhere in your path and you'll be able to call it like a regular git sub-command: "git unreachable"
If this has been helpful to you, flattr me. Oh wait. You can't. Send beer and pizza.
Here's a nugget: In the lab, we're quite regularly using UART-to-USB converters to connect hardware designs to standard desktop computers. Once connected, the devices appear as serial devices in the host's OS. That is rather nice, because you can immediately exchange bytes with the connected board or even hook a terminal program such as minicom or putty to it.
While that's all nice and cheap, we ran into a peculiar issue with windows xp as the host OS: Normally, when you want to open such a device from C or any other programming environment, you're opening a pseudo-file called "COM1" to open, well, the device registered as "COM1". That's almost all you need to do (well, there's some more but that's not relevant here). Now a colleague connected a board which was registered as "COM10". One piece of software in the lab scans for available com ports, but failed to detect "COM10". It found other hardware at "COM1" and "COM2" but not at 10. The colleague was also sure that the software did find a board registered as "COM9" just moments ago.
I had a hunch, so I googled for "windows comXX file names" - note the double "X". Shortly after that, I arrived at a microsoft support page, which explains the issue - or rather, it details a workaround:
HOWTO: Specify Serial Ports Larger than COM9
[...]
CreateFile(
"\\\\.\\COM10", // address of name of the communications device
So, you got to use "\\.\COMXX" as the new magic file name for extended happiness. That technique also works with "COM1" through "COM9", so that's the universal way you want to use.
Even though our software is back to working as expected, this left me with that familiar "The Fuck!?" look on my face. Again.
Mein Freund Jens weist mich darauf hin, daß die EXIT Initiative bei einem Nazi-Musik-Festival einen wunderbaren Hack mit einem Haufen T-Shirts gebracht hat. Erst etwas Social-Engineering indem sie sich als sympathisierende Nazis ausgaben, die eine Kleiderspende machen wollten. Eben den Haufen Shirts. Und die sahen dann auch entsprechend aus. Mit Totenkopf und Text, bei dem sich jeder Nazi vor Freude einnässt...
Dann überlegene Technik, denn nach einer Wäsche in der Waschmaschine wechselte das Motiv auf dem Shirt. Nun prangt dort in großen Lettern "Was dein T-Shirt kann, kannst du auch". Ich hoffe mal, daß die stolzen Besitzer erkennen, daß "Ändern" gemeint ist, was das Shirt konnte.
Schöne Aktion.
EXIT selbst hat auch einen Artikel dazu.
So, mika started a little pet project called zsh-pony, which aims at telling zsh-newcomers about how to facilitate many of zsh's advanced features in their own setups (which by the way, I'm considering to be a way better approach of getting starters into zsh than telling them "Here, clone this github-repo and be happy" - which only helps until the zsh-padawan hits the first issue in that repo - at which point, he/she is screwed).
One of the things mika lists is `auto_cd' as "switching directories for lazy people". I don't agree. Never liked that option. It makes stuff at the command position even more ambiguous than it already is. Sure, it may sound nice to be able to type "foo<RET>" to go a directory "foo" in the current directory. But what if the directory is called "git"? "git<RET>", huh? Yeah, well. That'll execute `git' the version control's main command. Of course, you'll scream at me, that you'll just "./git<RET>". Because that's so much simpler than "cd git<RET>". Especially on - say - german keyboards, where `/' is "Shift-7".
Also, you don't get the special completion for the `cd' builtin. It's nice to have it not complete stuff like files or "lost+found/" or "CVS/".
The one and only thing in `auto_cd', that seems worthwhile to me, is "..<RET>" to go up a directory level. But then, what to do to go up two levels? "../..<RET>"? I think not.
A friend of mine (hey Fabian!) asked me a while back if I could come up with a feature that would let him go up levels like he did in his amiga shell. Apparently, you could enter a forward-slash to go up a level. That is useful. So, what my setup does is if upon hitting "<RET>" and the command buffer is made up of just dots, it will convert that into "cd ../..". One ".."-level for each dot in the buffer.
So, ".<RET>" gets me up one directory. "..<RET>" two levels. And so on. There is no arbitrary limit, so if I input a hundert dots my shell will try to go up a hundert levels.
How to do that, well here's how:
function ft_accept_line_cd_up() {
setopt local_options extended_glob
local -a cmdline
cmdline=( ${(z)BUFFER} )
if (( ${#cmdline} == 1 )) && [[ ${cmdline[1]} == .# ]] ; then
BUFFER='cd '
for (( i = 1; i <= ${#${cmdline[1]}}; i++ )); do
BUFFER="${BUFFER}../"
done
BUFFER=${BUFFER%/}
fi
zle ".$WIDGET"
}
zle -N accept-line ft_accept_line_cd_up
After that the following
% ...<RET>
will turn into
% cd ../../..<RET>
But what about "../../<TAB>"? I hear you ask. Well, my setup does that too. I can just do this:
% ..<TAB>
...and that will behave as if I did this:
% cd ../../<TAB>
Here's a simple way to get that going:
function ft_complete_with_dots() {
setopt local_options extended_glob
local -a cmdline
cmdline=( ${(z)BUFFER} )
if (( ${#cmdline} == 1 )) && [[ ${cmdline[1]} == .# ]] ; then
BUFFER='cd '
for (( i = 1; i <= ${#${cmdline[1]}}; i++ )); do
BUFFER="${BUFFER}../"
done
CURSOR=${#BUFFER}
fi
zle ".$WIDGET"
}
zle -N complete-word ft_complete_with_dots
# if you don't do this already...
bindkey '^I' complete-word
You could factor the turn-dots-into-cd code into its own function to avoid the code duplication with the previous snippet, but that's basically it.
Take that for laziness.
(Oh yeah. If you're a big big fan of `auto_cd', use it by all means. The above snippets also work if that option is enabled, so you can have both.)


