Shallow Thoughts : : linux
Akkana's Musings on Open Source Computing, Science, and Nature.
Sat, 12 May 2012
University of Chicago Press has a
Carl Zimmer book,
A Planet of Viruses, as their free monthly e-book.
I know Zimmer is a good writer. but the ebook, despite being free, is
encumbered with Adobe's version of DRM, which unlocks via a Windows
or Mac program. I use Linux, and wanted to read the book on a Nook.
Was I out of luck?
Happily, the instruction page they sent when I signed up
for the book helpfully included a section for Linux users. Hooray,
U. Chicago! It said Adobe Digital Editions will run under Wine,
the Windows emulator.
I'd been meaning to try that anyway, and a Carl Zimmer book seemed
like the perfect excuse.
And overall, it worked pretty well, with only a few snags.
Here are the steps I had to follow:
Authorizing a book using Adobe Digital Editions in Linux on Wine
Install wine (on Ubuntu, I used apt-get install wine).
Download the Adobe Digital Editions setup.exe
Run:
wine setup.exe
(this should install ADE inside your .wine directory)
Copy the file, e.g. URLLink.acsm, into .wine/drive_c/My\ Documents/
Don't bother trying to open it with ADE -- the program won't open
anything except PDF and epub. Curiously, the only ways to open the
file from ADE are to drag the file onto the ADE window or to pass
it as a commandline argument:
wine start .wine/drive_c/My\ Documents/URLLink.acsm
Now ADE should download your book and display it.
You can read it there, if you want. But you won't want to -- it's not
a good reading interface.
Authorizing a device with Adobe Digital Editions under Wine
Now how do you get it into your ebook reader?
ADE running under Wine doesn't recognize devices such as ebook readers.
so nothing will be copied automatically. But you can copy it manually.
- Plug in your ebook reader.
- Mount the device wherever you like -- /media/nook, /nook or whatever.
- With ADE not running (quit it if it's running),
map a drive letter to the mount point:
- Run winecfg
- Click the Drives tab
- Click Add...
- Choose a drive letter (I chose D:)
- Under Path: type in the mount point, like /nook
- Click Show Advanced
- Set the Type: to Floppy disk
- Click OK to save it
- Now the drive is mapped. Re-run ADE:
wine .wine/drive_c/Program\ Files/Adobe/Adobe\ Digital\ Editions/digitaleditions.exe
ADE should now see the device and ask you if you want to authorize it.
- In ADE, drag the chosen book onto the left sidebar entry for the device.
- umount the reader ... and now your new book should show up in the library.
In theory, the drive letter should stay mapped, so you should be able
to use it for opening future books.
Just remember to mount your device to the same location before
running ADE under wine.
Tags: ebook, DRM, tablet
[ 10:03 May 12, 2012
More linux |
permalink to this entry |
comments
]
Wed, 18 Apr 2012
My new toy: a Samsung Galaxy Player 5.0!
So far I love it. It's everything my old
Archos 5
wanted to be when it grew up, except the Archos never grew up.
It's the same size, a little lighter weight, reliable hardware
(no random reboots), great battery life, fast GPS, modern Android 2.3,
and the camera is even not too bad (though it certainly wouldn't tempt
me away from my Canon).
For the record, Dave got a Galaxy Player 4.0, and it's very nifty too,
and choosing between them was a tough choice -- the 4-inch is light and
so easy to hold, and it uses replaceable batteries, while the 5-inch's
screen is better for reading and maps.
USB-storage devices don't register
I love the Galaxy ... but there's one thing that bugs me about it.
When I plug it in to Linux, dmesg reports two new storage devices, one for
main storage and one for the SD card. Just like most Android devices, so far.
The difference is that these Samsung devices aren't fully there.
They don't show up in /proc/partitions or in /dev/disk/by-uuid,
dmesg doesn't show sizes for them, and, most important,
they can't be mounted by UUID from an fstab entry, like
UUID=62B0-C667 /droidsd vfat user,noauto,exec,fmask=111,shortname=lower 0 0
That meant I couldn't mount it as myself -- I had to become root,
figure out where it happened to show up this time (/dev/sdf or
wherever, depending on what else might be plugged in),
mount it, then do all my file transfers as root.
I found that if I mounted it explicitly using the device pathname --
mount /dev/sdf /mnt -- then subsequently the device shows
up normally, even after I unmount it. So I could check dmesg to find
the device name, mount it as root, unmount as root, then mount it
again as myself using my fstab entry. What a pain!
A kernel expert I asked thought it looked like the Samsung is pretending
to be a removable device, but only "plugging in" when the system
actually tries to access it. Annoying. So how do you get Linux to
"access" it?
Udev: still an exercise in frustration
The obvious solution is a udev rule. Some scrutiny of
/lib/udev/rules.d/60-persistent-storage.rules found some
rules that did this intriguing thing:
IMPORT{program}="ata_id --export $tempnode".
Naturally, this mysterious ata_id is undocumented.
It's hidden in /lib/udev/ata_id, and I found
this tiny ata_id
man page online since there's none available in Ubuntu.
Running ata_id /dev/sdf seemed to do what I needed:
it made the device show up in /proc/partitions and
/dev/disk/by-uuid, and after that, I could mount it without
being root.
I created a file named /etc/udev/rules.d/59-galaxy.rules, with
the rule:
KERNEL=="sd[b-g]", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04e8", SYMLINK+="galaxy-%k-%n", IMPORT{program}="ata_id --export $tempnode"
When I tested it with udevadm test /block/sdf, not only did
the rule trigger correctly, but it actually ran ata_id and the device
became visible -- even though udevadm test states clearly
no programs will be run. How do I love udev -- let me count the ways.
But a reboot revealed that udev was not actually running the rule when
I actually plugged the Galaxy in -- the devices did not become visible.
Did I mention how much I love udev?
Much simpler: a shell alias
But one thing I'd noticed in all this: side by side with
/dev/disk/by-uuid is a directory called /dev/disk/by-id.
And the Samsung devices did show up there, with names like
usb-Android_UMS_Composite_c197022a2b41c1ae-0:0.
Faced with the prospect of spending the rest of the day trying random
udev rules, rebooting each time since that's the only way to test udev,
I decided to cheat and find another way. I made a shell alias:
alias galaxy='sudo sh -c "for d in /dev/disk/by-id/usb-Android*; do /lib/udev/ata_id --export \$d; done"'
Typing galaxy will now cause the Samsung to register
both devices; and from then on I can mount and unmount them without
needing root, using my normal fstab entries.
Update: This works for the Nook's main storage, too -- just add
x/dev/disk/by-id/usb-B_N_Ebook_Disk* to the list -- but it
doesn't work reliably for the Nook's SD card. The SD card does show
up in /dev/disk/by-id along with main storage; but running ata_id
on it doesn't make its UUID appear. I may just change my fstab entry
to refer to the /dev/disk/by-id device directly.
Tags: android, linux, udev
[
12:43 Apr 18, 2012
More linux/kernel |
permalink to this entry |
comments
]
Sat, 24 Mar 2012
A thread on the Ubuntu-devel-discuss mailing list last month asked
about how
to find out what processes are making outgoing network connectsion
on a Linux machine. It referenced Ubuntu
bug
820895: Log File Viewer does not log "Process Name", which is
specific to Ubuntu's iptables logging of apps that are already blocked
in iptables ... but the question goes deeper.
Several years ago, my job required me to use a program -- never mind
which one -- from a prominent closed-source company. This program was
doing various annoying things in addition to its primary task --
operations that got around the window manager and left artifacts
all over my screen, operations that potentially opened files other
than the ones I asked it to open -- but in addition, I noticed that
when I ran the program, the lights on the DSL modem started going crazy.
It looked like the program was making network connections, when it had
no reason to do that. Was it really doing that?
Unfortunately, at the time I couldn't find any Linux command that would
tell me the answer. As mentioned in the above Ubuntu thread, there are
programs for Mac and even Windows to tell you this sort of information,
but there's no obvious way to find out on Linux.
The discussion ensuing in the ubuntu-devel-discuss thread tossed
around suggestions like apparmor and selinux -- massive, complex ways
of putting up fortifications your whole system. But nobody seemed to
have a simple answer to how to find information about what apps
are making network connections.
Well, it turns out there are a a couple ofsimple way to get that list.
First, you can use ss:
$ ss -tp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 ::1:58466 ::1:ircd users:(("xchat",1063,43))
ESTAB 0 0 192.168.1.6:57526 140.211.166.64:ircd users:(("xchat",1063,36))
ESTAB 0 0 ::1:ircd ::1:58466 users:(("bitlbee",1076,10))
ESTAB 0 0 192.168.1.6:54253 94.125.182.252:ircd users:(("xchat",1063,24))
ESTAB 0 0 192.168.1.6:52167 184.72.217.144:https
users:(("firefox-bin",1097,47))
-t shows only TCP connections (so you won't see all the interprocess
communication among programs running on your machine). -p prints the
process associated with each connection.
ss can do some other useful things, too, like show all the programs
connected to your X server right now, or show all your ssh connections.
See man ss for examples.
Or you can use netstat:
$ netstat -A inet -p
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 imbrium.timochari:51800 linuxchix.osuosl.o:ircd ESTABLISHED 1063/xchat
tcp 0 0 imbrium.timochari:59011 ec2-107-21-74-122.:ircd ESTABLISHED 1063/xchat
tcp 0 0 imbrium.timochari:54253 adams.freenode.net:ircd ESTABLISHED 1063/xchat
tcp 0 0 imbrium.timochari:58158 s3-1-w.amazonaws.:https ESTABLISHED
1097/firefox-bin
In both cases, the input is a bit crowded and hard to read. If all you
want is a list of processes making connections, that's easy enough to do
with the usual Unix utilities like grep and sed:
$ ss -tp | grep -v Recv-Q | sed -e 's/.*users:(("//' -e 's/".*$//' | sort | uniq
$ netstat -A inet -p | grep '^tcp' | grep '/' | sed 's_.*/__' | sort | uniq
Finally, you can keep an eye on what's going on by using watch to run
one of these commands repeatedly:
watch ss -tp
Using watch with one of the pipelines to print only process names is
possible, but harder since you have to escape a lot of quotation marks.
If you want to do that, I recommend writing a script.
And back to the concerns expressed on the Ubuntu thread,
you could also write a script to keep logs of which processes made
connections over the course of a day. That's definitely a tool I'll
keep in my arsenal.
Tags: net, linux, networking, cmdline
[
11:28 Mar 24, 2012
More linux |
permalink to this entry |
comments
]
Tue, 03 Jan 2012
Like most Linux users, I use virtual desktops. Normally my browser
window is on a desktop of its own.
Naturally, it often happens that I encounter a link I'd like to visit
while I'm on a desktop where the browser isn't visible. From some apps,
I can click on the link and have it show up. But sometimes, the link is
just text, and I have to select it, change to the browser desktop,
paste the link into firefox, then change desktops again to do something
else while the link loads.
So I set up a way to load whatever's in the X selection in firefox no
matter what desktop I'm on.
In most browsers, including firefox, you can tell your existing
browser window to open a new link from the command line:
firefox http://example.com/ opens that link in your
existing browser window if you already have one up, rather than
starting another browser. So the trick is to get the text you've selected.
At first, I used a program called xclip. You can run this command:
firefox `xclip -o` to open the selection. That worked
okay at first -- until I hit my first URL in weechat that was so long
that it was wrapped to the next line. It turns out xclip does odd things
with multi-line output; depending on whether it thinks the output is
a terminal or not, it may replace the newline with a space, or delete
whatever follows the newline. In any case, I couldn't find a way to
make it work reliably when pasted into firefox.
After futzing with xclip for a little too long, trying to reverse-engineer
its undocumented newline behavior, I decided it would be easier just to
write my own X clipboard app in Python. I already knew how to do that,
and it's super easy once you know the trick:
mport gtk
primary = gtk.clipboard_get(gtk.gdk.SELECTION_PRIMARY)
if primary.wait_is_text_available() :
print primary.wait_for_text()
That just prints it directly, including any newlines or spaces.
But as long as I was writing my own app, why not handle that too?
It's not entirely necessary on Firefox: on Linux, Firefox has some
special code to deal with pasting multi-line URLs, so you can copy
a URL that spans multiple lines, middleclick in the content area and
things will work. On other platforms, that's disabled, and some Linux
distros disable it as well; you can enable it by going to
about:config and searching for single,
then setting the preference
editor.singlelinepaste.pasteNewlines to 2.
However, it was easy enough to make my Python clipboard app do the
right thing so it would work in any browser. I used Python's re
(regular expressions) module:
#!/usr/bin/env python
import gtk
import re
primary = gtk.clipboard_get(gtk.gdk.SELECTION_PRIMARY)
if not primary.wait_is_text_available() :
sys.exit(0)
s = primary.wait_for_text()
# eliminate newlines, and any spaces immediately following a newline:
print re.sub(r'[\r\n]+ *', '', s)
That seemed to work fine, even on long URLs pasted from weechat
with newlines and spaces, like that looked like
http://example.com/long-
url.html
All that was left was binding it so I could access it from anywhere.
Of course, that varies depending on your desktop/window manager.
In Openbox, I added two items to my desktop menu in menu.xml:
<item label="open selection in Firefox">
<action name="Execute"><execute>sh -c 'firefox `xclip -o`'</execute></action>
</item>
<item label="open selection in new tab">
<action name="Execute"><execute>sh -c 'firefox -new-tab `xclip -o`'</execute></action>
</item>
I also added some code in rc.xml inside
<context name="Desktop">, so I can middle-click
or control-middle-click on the desktop to open a link in the browser:
<mousebind button="Middle" action="Press">
<action name="Execute">
<execute>sh -c 'firefox `pyclip`'</execute>
</action>
</mousebind>
<mousebind button="C-Middle" action="Press">
<action name="Execute">
<execute>sh -c -new-tab 'firefox `pyclip`'</execute>
</action>
</mousebind>
I set this up maybe two hours ago and I've probably used it ten or
fifteen times already. This is something I should have done long ago!
Tags: tech, firefox, linux, cmdline
[
21:37 Jan 03, 2012
More linux |
permalink to this entry |
comments
]
Sun, 18 Dec 2011
A friend had a fun problem: she had some XML files she needed to
import into GNUcash, but the program that produced them left names
in all-caps and she wanted them more readable. So she'd have a file
like this:
<STMTTRN>
<TRNTYPE>DEBIT
<DTPOSTED>20111125000000[-5:EST]
<TRNAMT>-22.71
<FITID>****
<NAME>SOME COMPANY
<MEMO>SOME COMPANY ANY TOWN CA 11-25-11 330346
</STMTTRN>
and wanted to change the NAME and MEMO lines to read
Some Company and Any Town. However, the tags, like <NAME>,
all had to remain upper case, and presumably so did strings like DEBIT.
How do you change just the NAME and MEMO lines from upper case to title case?
The obvious candidate to do string substitutes is sed.
But there are several components to the problem.
Addresses
First, how do you ensure the replacement only happens on lines with
NAME and MEMO?
sed lets you specify address ranges for just that purpose.
If you say sed 's/xxx/yyy/' sed will change all xxx's
to yyy; but if you say sed '/NAME/s/xxx/yyy/'
then sed will only do that substitution on lines containing NAME.
But we need this to happen on lines that contain either NAME or MEMO.
How do you do that? With \|, like this:
sed '/\(NAME\|MEMO\)/s/xxx/yyy/'
Converting to title case
Next, how do you convert upper case to lower case?
There's a
sed
command for that: \L. Run
sed 's/.*/\L&/' and type some upper and lower case
characters, and they'll all be converted to lower-case.
But here we want title case -- we want most of each word converted
to lowercase, but the first letter should stay uppercase.
That means we need to detect a word and figure out which is the
first letter.
In the strings we're considering, a word is a set of letters A through Z
with one of the following characteristics:
- It's preceded by a space
- It's preceded by a close-angle-bracket, >
So the pattern /[ >][A-Z]*/ will match anything we consider a word
that might need conversion.
But we need to separate the first letter and the rest of the word,
so we can treat them separately. sed's \( \) operators will let us do that.
The pattern \([ >][A-Z]\) finds the first letter of a word (including
the space or > preceding it), and saves that as its first matched
pattern, \1.
Then \([A-Z]*\) right after it will save the rest of the word as \2.
So, taking our \L case converter, we can convert to title case like this:
sed 's/\([ >][A-Z]\)\([A-Z]*\)/\1\L\2/g
Starting to look long and scary, right? But it's not so bad if you build
it up gradually from components. I added a g on the end to tell sed
this is a global replace: do the operation on every word it finds in
the line, otherwise it will only make the substitution once, on the
first word it sees, then quit.
Putting it together
So we know how to seek out specific lines, and how to convert to
title case. Put the two together, and you get the final command:
sed '/\(NAME\|MEMO\)/s/\([ >][A-Z]\)\([A-Z]*\)/\1\L\2/g'
I ran it on the test input, and it worked just fine.
For more information on sed, a good place to start is the
sed
regular expressions manual.
Tags: regexp, cmdline, sed
[
13:13 Dec 18, 2011
More linux/cmdline |
permalink to this entry |
comments
]
Tue, 13 Dec 2011
One of the distros I'm trying on my Dell Latitude 2120 laptop is Arch Linux.
I like a lot of things about Arch; I had to stop using it on my previous
laptop because something broke in the wi-fi drivers, but I always regretted
giving it up. And it seems to work quite well on the Dell, with one
exception: the system beep (which other distros don't support at all)
was ear-shatteringly loud, far too loud to consider being able to use
this laptop in a public space. Clearly that needed to be fixed.
The usual approach to system beeps, unloading or blacklisting the
pcspkr module, had no effect. xset b off turned the beep
off in X; I could also set its pitch and duration to change it to a
nice quiet click, though I wasn't able to change the volume that way.
I actually do like having a system beep, as long as it's fairly quiet
and won't disturb people nearby. Unfortunately, xset b only affects
the bell while in X; it didn't have any effect on the deafening sound
Arch gave upon shutdown or reboot.
It turns out that on some laptops, including this Dell, the system beep
goes not through the old-style pcspkr driver, but through the
normal sound card. And the sound card has a separate channel for the
system beep, so even if you have your volume turned down, the beep
may still be at 100%. All I needed to do was run alsamixer
and find out what the channel was called: "Beep".
Given that, I could use the amixer program to ensure the beep volume
will be sane when I log in. I added the following to .zlogin
(for zsh; obviously, adjust for your own shell):
amixer -q -c 0 set Beep 5
That gave me a nice quiet beep. If I need to turn it off completely,
amixer can do that too: amixer -q -c 0 set Beep mute
(curiously, amixer -q -c 0 set Beep 0 doesn't actually
set the volume to zero, just sets it very low).
That volume setting applies to the shutdown beep, too, fortunately.
Though what I'd really like is to have quiet beeps while I'm running, but no
shutdown beep at all. I don't understand the purpose of the shutdown beep;
obviously I know when I've told my machine to shut down or reboot, so
why do I need an audible reminder? But I've been unable to find anything
explaining what's causing this beep. I tried adding a
amixer -q -c 0 set Beep mute to /etc/rc.local.shutdown,
but it didn't help; apparently the shutdown beep is called before that
file is run. Which strongly suggests it is being run by Arch Linux,
not by something in the BIOS. But nobody I've asked had any suggestions
as to its source, or how to change it. Another enduring Linux mystery ...
Update: I mentioned xset b as a way to adjust beeps inside X -- in
addition to turning beeps totally off, you can also set pitch, duration,
and sometimes volume though the volume part didn't work for me.
But outside X, you can make similar adjustments
with setterm, e.g. setterm -bfreq 400 -blength 50.
Thanks to Mikachu for the tip!
Tags: linux, archlinux, alsa
[
11:05 Dec 13, 2011
More linux |
permalink to this entry |
comments
]
Sun, 11 Dec 2011
Need your Ubuntu clock to stay in sync with a dual-boot Windows install?
It seems to have changed over the years, and google wasn't finding any
pages for me offering suggestions that still worked.
Turns out, in Ubuntu Oneiric Ocelot,
it's controlled by the file /etc/default/rcS: set
UTC=no.
Apparently it's also possible to get Windows to understand a
UTC
system clock using a registry tweak.
Ironically, that page, which I found by searching for
windows system clock utc, also has the answer for setting
Ubuntu to local time. So if I'd searched for Windows in the first
place, I wouldn't have had to puzzle out the Ubuntu solution myself.
Go figure!
[
12:56 Dec 11, 2011
More linux |
permalink to this entry |
comments
]
Thu, 24 Nov 2011
A few days ago, I wrote about
how to
set up and configure extlinux (syslinux) as a bootloader.
But on Debian or Ubuntu,
if you make changes to files like /boot/extlinux/extlinux.conf
directly, they'll be overwritten.
The configuration files are regenerated by a program
called extlinux-update, which runs automatically every time you
update your kernel. (Specifically, it runs from the postinst script of
the linux-base package:
you can see it in /var/lib/dpkg/info/linux-base.postinst.)
So what's a Debian user to do if she wants to customize the menus,
add a splash image or boot other operating systems?
First, if you decide you really don't want Debian overwriting your
configuration files, you can change disable updates
by editing /etc/default/extlinux.
Just be aware you won't get your boot menu updated when you install new
kernels -- you'll have to remember to update them by hand.
It might be worth it: the automatic update is nearly as annoying as
the grub2 updater: it creates two automatic entries for every kernel
you have installed. So if you have several distros installed, each
with a kernel or two in your shared /boot,
you'll get an entry to boot Debian Squeeze with the
Ubuntu Oneiric kernel, one for Squeeze with the Natty kernel,
one for Squeeze with the Fedora 16 kernel ... as well as entries
for every kernel you have that's actually owned by Debian.
And then for each of these, you'll also get a second entry,
to boot in recovery mode. If you have several distros installed,
it makes for a very long and confusing boot menu!
It's a shame that the auto-updater doesn't restrict itself to kernels
managed by the packaging system, which would be easy enough to do.
(Wonder if they would accept a patch?)
You might be able to fudge something that works right by setting up
symlinks so that the only readable kernels actually live on the root
partition, so Debian can't read the kernels from the other
distros. Sounds a bit complicated and I haven't tried it.
For now, I've turned off automatic updating on my system.
But if your setup is simpler --
perhaps just one Debian or one Ubuntu partition plus some non-Linux
entries such as BSD or Windows -- here's how to set up Debian-style
automatic updating and still keep all your non-Linux boot entries
and your nice menu customizations.
Debian automatic updates and themes
First, take a quick look at /etc/default/extlinux and customize
anything there you might need, like the names of the kernels, kernel
boot parameters or timeout.
See man extlinux-update for details.
For configuring menu colors, image backgrounds and such, you'll need to
make a theme. You can see a sample theme by installing the package
syslinux-themes-debian -- but watch out.
If you haven't configured apt not to pull in suggested packages, that
may bring back grub or grub-legacy, which you probably don't want.
You can make a theme without needing that package, though.
Create a directory /usr/share/syslinux/themes/mythemename
(the extlinux-update man page claims you can put a theme anywhere and
specify it by its full path, but it lies). Create a directory called
extlinux inside it, and make a file with everything you want
from extlinux.conf. For example:
default 0
prompt 1
timeout 50
ui vesamenu.c32
menu title Welcome to my Linux machine!
menu background mysplash.png
menu color title 1;36 #ffff8888 #00000000 std
menu color unsel 0 #ffffffff #00000000 none
menu color sel 7 #ff000000 #ffffff00 none
include linux.cfg
menu separator
include themes/mythemename/other.cfg
Note that last line: you can include other files from your theme.
For instance, you can create a file called other.cfg
with entries for other partitions you want to boot:
label oneiric
menu label Ubuntu Oneiric Ocelot
kernel /vmlinuz-3.0.0-12-generic
append initrd=/initrd.img-3.0.0-12-generic root=UUID=c332b3e2-5c38-4c50-982a-680af82c00ab ro quiet
label fedora
menu label Fedora 16
kernel /vmlinuz-3.1.0-7.fc16.i686
append initrd=/initramfs-3.1.0-7.fc16.i686.img root=UUID=47f6b1fa-eb5d-4254-9fe0-79c8b106f0d9 ro quiet
menu separator
LABEL Windows
KERNEL chain.c32
APPEND hd0 1
Of course, you could have a debian.cfg, an ubuntu.cfg,
a fedora.cfg etc. if you wanted to have multiple distros
all keeping their kernels up-to-date. Or you can keep the whole
thing in one file, theme.cfg. You can make a theme as complex
or as simple as you like.
Tags: linux, boot, extlinux, syslinux, debian, ubuntu
[
11:26 Nov 24, 2011
More linux/install |
permalink to this entry |
comments
]