Posterous
Paul is using Posterous to post everything online. Shouldn't you?
Unknown35
 

Paul’s posterous

Analyst & metaphysician.

Entrance

Upgrading my laptop to Karmic went with only two hitches. The first was the return of the abhorrent NetworkManager. I had to reinstall wicd via a thumb drive. The second was the return of KDM.

Since I avowed in a previous post that I use KDE for lack of a better choice, I tried out E17 again (as I do from time to time) and found that it had improved to the point where I was comfortable using it full-time. (I may write something soon about how I got it working.) I also switched to Entrance, the Enlightenment login manager—easily done with BUM. But Karmic substitutes a new init system, Upstart, which renders BUM useless.

Upstart keeps its configuration in /etc/init, in a series of .conf files, including one for KDM. The syntax is fairly simple, so I combined the useful parts of kdm.conf with the useful parts of the /init.d/entrance script and came up with an entranced.conf that seems to work.

 

# entranced - Launch Entrance Display Manager # Based on kdm.conf from Ubuntu Karmic.
description "Enlightenment Login Manager"

# configuration variables env DAEMON=/opt/e17/sbin/entranced

# let upstart handle PID expect fork

start on (filesystem
and started hal
and tty-device-added KERNEL=tty7
and (graphics-device-added or stopped udevtrigger))
stop on runlevel [016]

emits starting-dm

respawn

script

# kernel command-line inhibitor? for ARG in $(cat /proc/cmdline); do
case "${ARG}" in
text|-s|s|S|single)
exit 0
;;
esac
done

if [ -r /etc/default/locale ]; then
. /etc/default/locale
export LANG LANGUAGE
elif [ -r /etc/environment ]; then
. /etc/environment
export LANG LANGUAGE
fi

# fail on error set -e

# does daemon exist? test -x $DAEMON || exit 0

echo -n "Becoming entranced: entrance"
initctl emit starting-dm DM=entranced

esd &
exec $DAEMON

end script

/opt/e17/sbin/entranced is the location used by Easy_e17.sh. If you installed E17 otherwise, substitute the appropriate location.

Put this in /etc/init/entranced.conf, move /etc/init/kdm.conf to /etc/init/kdm.dont (anything not ending in .conf is skipped), and Entrance works perfectly.

That was really much easier than I thought it would be.

Filed under  //   e17   karmic   linux   ubuntu   upstart  
Posted November 21, 2009
// 0 Comments

DRVSPACE.000

I recently got one of these nifty devices to transfer some files off a decrepit old computer. I wanted to do a trial run before using it on the important stuff. Fortunately I had a handy stack of old hard drives. (I always pull the hard drive before I throw a computer away.) So I get an old laptop hard drive, connect it up, and voilá! It works!

Except that on this ~1G hard drive there is only one real file: 800M of DRVSPACE.000.

In the old days, the dark DOS days, the dim *32.exe days, when we ran out of room we had two choices. We could go on a deleting spree—sometimes (no names) accidentally deleting critical system files and disabling the computer. Or we could compress the hard drive—that is, put the entire thing inside of a compressed file with a program called DriveSpace.

I could have moved on to another drive but that would be gutless. So I hit Google. I found a lot of other people with the same problem, but no solutions. No recent version of Windows will actually mount the drive. No utilities exist to let modern systems, Windows, Linux, or otherwise, extract the data. As far as the Internet is concerned the only solution is to hunt up a computer running Windows 95 or 98 with an empty drive bay.

But there is a way! It is called DOSEMU. If you run DOS programs you probably know DOSBox, an very fast, effective DOS emulator. DOSEMU is much heavier—it is not an emulator, but a virtual machine. You can use it to boot a DOS partition *inside Linux*.

So here it is, step by step, in the imperative mood.

  1. Plug in the hard drive. Wait for it to automount.
  2. Open a terminal.
  3. Run mount and note the device name of the hard drive, /dev/sdb1 in my case. (Be careful to get the right partition if the drive has more than one.)
  4. Unmount the drive—assuming the mountpoint is /media/disk/, the command is sudo umount /media/disk.
  5. (Or, sans automount, just tail /var/log/syslog.)

  6. Install DOSEMU—in Ubuntu, sudo aptitude install dosemu.
  7. Edit /etc/dosemu/dosemu.conf (as root). Uncomment $_hdimage and set it to equal the device name of the DOS partition followed by a local directory. I.e. $_hdimage = "/dev/sdb1 /home/salcher/".
  8. Run dosemu as root. A window will appear, white on black, that old familiar font.
  9. Shiver.
  10. When Starting Windows 95... comes up, press F8 for a menu. Choose Command prompt only.
  11. The compressed drive should now be C: and the local directory you supplied should be D:. If you were ever a heavy DOS user, take a moment to savor the nostalgia (or to be thankful for bash), then cd to the directory containing the files you want and run xcopy /S *.* D:\.
  12. Wait.
  13. Close DOSEMU, disconnect. You're done.

Filed under  //   dos   linux   windows  
Posted November 17, 2009
// 0 Comments

Shame

I had to; I couldn't take it.

 
(define-key view-mode-map (kbd "j") '(lambda ()
(interactive) (scroll-up 1)))
(define-key view-mode-map (kbd "k") '(lambda ()
(interactive) (scroll-down 1)))

I'm so ashamed.

Filed under  //   emacs   vi  
Posted November 14, 2009
// 0 Comments

Hinting in Opera

As far as I'm concerned link hinting is the best idea in browsing since tabs. How unfortunate then that Opera, the browser that introduced 
tabs, has no implementation of hinting—or so I thought. In fact, a perfectly adequate hinting system has been available for Opera for over 
a year as part of vimperopera.  I have no interest in the rest of it, but the hinting code is easy to lift and add to an existing keyboard layout. The sun is shining. Birds are singing.

Filed under  //   browser   hinting   opera  
Posted October 31, 2009
// 0 Comments

Karmic

I know better than this. You give these things time. You let them work
the kinks out before you jump in. But then it had been in beta for a
while, yes? And it felt overdue. So I went ahead. I'm not going to go
into the joys of the (initramfs)$ prompt. I just want it
in writing: I know better.

Filed under  //   confession   karmic koala   linux   ubuntu  
Posted October 31, 2009
// 0 Comments

Patrons Mode

[[2009-10-17 Sat] Don't use this, use shadowfile.el instead.  Just (setq shadow-noquery t) and run

(add-hook 'after-save-hook
          '(lambda ()
             (shadow-copy-file
              (assoc buffer-file-name shadow-files-to-copy)))
          nil t)

On the file to get the same effect.]

The Emacs way, as I understand it, is that when you need a feature, you implement it, and if it works, you share it. Needing a feature that doesn't already exist in Emacs doesn't happen very often, but it happened to me recently. It may not be a useful feature for anybody else, but it seemed general enough to be worth implementing as a minor mode, and just within my Elisp abilities.

The circumstances were these. I was working on a local copy of a website. The machine I was working on didn't have a server running, so every time I wanted to test something I would write-other-file to the production server with tramp. (Obviously there are much better methods to sync active projects, but this was an old project that just needed a little sprucing up and I didn't want to bother.) This wasn't just awkward but confusing: I had two copies of everything open. So I wrote a version of write-other-file that didn't visit the file. But having to write out the file name every time was annoying and unhackerly. So I wrote a couple of functions that let me set a "slave file" and write over it every time I saved the "master."

But why not allow multiple slave files? Why not make them persistent? Thus Patron Mode. (Writing slave, slave, slave was creeping me out—I live in the South, after all—so I decided on "patron" and "client" instead of "master" and "slave".)

The (overambitious) idea is a kind of virtual inside-Emacs cross-file-system symlink.

N. B. I deliberately didn't implement the obvious feature of autoloading Patrons Mode for patron files. It could go very wrong if your .patrons file is under version control and shows up on multiple systems. This is my first minor mode. My Lisp is novice level. I really don't want to be responsible for destroying anyone's files.

(I hate it when modes that use tramp try to connect without being told to so Patrons Mode doesn't do this by default but that can be customized.)

I need the opinion of people more experienced in Emacs and Elisp before I even think about uploading this to the wiki or adding it to ELPA.

Here goes:

(require 'tramp)

(defgroup patrons nil
  "Copy visited file to a list of other files every time it is saved."
  :group 'data)

(defcustom patrons-file (concat user-emacs-directory ".patrons")
  "Name of file that records patrons-list. "
  :type 'file
  :group 'patrons)

(defcustom patrons-add-to-history t
  "Whether to add client files to file name history."
  :type 'boolean
  :group 'patrons)

(defcustom patrons-try-tramp nil
  "Whether to automatically connect to client files with Tramp names."
  :type 'boolean
  :group 'patrons)

(defvar patrons-list nil
  "List of files in patron-client relation.
This list is saved between sessions.")

(defvar patrons-file-loaded nil
  "Non-nil means `patrons-file' has been loaded.")

(defvar patrons-client-list nil
  "List of clients for this buffer.")
(make-variable-buffer-local 'patrons-client-list)

(defconst patrons-utility-buffer-name " *Patrons*"
  "Buffer name to use for patrons file operations.")

(defconst patrons-report-buffer-name " *Clients*"
  "Buffer name to use for reporting client writes.")

(defun patrons-load-file ()
  "Load list of patrons and clients from file."
  (if (not patrons-file-loaded)
      (let ((file (expand-file-name patrons-file))
            (buf (get-buffer-create patrons-utility-buffer-name))
            (version-control 'never))
        (unwind-protect
                (with-current-buffer buf
                  (erase-buffer)
                  (insert-file-contents file)
                  (goto-char (point-min))
                  (setq patrons-list
                        (car (read-from-string
                              (buffer-substring (point-min)
                                                (point-max)))))
                  (setq patrons-file-loaded t))
          (kill-buffer buf)))))

(defun patrons-client-list-to-list ()
  "Update a file's entry in patrons-list."
  (if patrons-client-list
      (progn (setq patrons-list
                   (delq (assoc buffer-file-name patrons-list)
                         patrons-list))
             (setq patrons-list
                   (cons
                    (cons buffer-file-name patrons-client-list)
                    patrons-list)))))

(defun patrons-list-to-file ()
  "Save list of patrons and clients between sessions."
  (let ((file (expand-file-name patrons-file))
        (buf (get-buffer-create patrons-utility-buffer-name))
        (coding-system-for-write 'utf-8)
        (version-control 'never))
    (unwind-protect
        (with-current-buffer buf
          (erase-buffer)
          (insert ";;; -*- coding: utf-8 -*-\n")
          (let ((print-length nil)
                (print-level nil))
            (print patrons-list (current-buffer)))
          (write-file file nil))
      (kill-buffer buf))))

(defun patrons-add-client ()
  "Add a new client for this file."
  (interactive)
  (let (filename)
    (condition-case quit
        (progn
          (setq filename (read-file-name "Client file:"))
          (add-to-list 'patrons-client-list filename))
      (quit (or filename)))
    (or filename)))

(defun patrons-load-client-list ()
  "Get the client list for this file and setup Patrons Mode hooks.
If this file has no clients, prompt for one."
  (or patrons-file-loaded
      (patrons-load-file))
  (if (catch 'break
        (progn
          (or
           (setq patrons-client-list (cdr (assoc buffer-file-name patrons-list)))
           (or
            (patrons-add-client)
            (progn
              (patrons-mode 0)
              (throw 'break nil))))))
      (progn
       (add-hook 'after-save-hook 'patrons-write-client-files nil t)
       (add-hook 'kill-buffer-hook 'patrons-save-client-list-or-exit nil t))
    (progn
      (message "This file has no clients.")
      (patrons-mode 0))))

(defun patrons-save-client-list-or-exit ()
  "Record this file's clients for future sessions."
  (if patrons-file-loaded
      (progn
        (patrons-client-list-to-list)
        (patrons-list-to-file)
        (remove-hook 'after-save-hook 'patrons-write-client-files t))))

(defun patrons-write-client-files ()
  "Copy the visited file (\"patron\") to an list of other files (\"clients\") every time it is saved."
  (with-help-window patrons-report-buffer-name
    (mapc
     '(lambda (filename)
        (cond
         ((and (not patrons-try-tramp)
               (tramp-tramp-file-p filename)
               (not (tramp-get-connection-process
                     (tramp-dissect-file-name filename))))
          (print (format "Didn't write client file %s: connection not open." filename)))
         ((not (file-directory-p (file-name-directory filename)))
          (print (format "Didn't write client file %s: directory not available." filename)))
         ((not (file-writable-p filename))
          (print (format "Didn't write client file %s: file not writable." filename)))
         (t
          (let ((version-control 'never))
            (progn
              (copy-file
               (buffer-file-name)
               filename
               t)
              (print (format "Wrote client file %s." filename))
              (and patrons-add-to-history
                   (add-to-history 'file-name-history filename)))))))
     patrons-client-list)))

(defun patrons-remove-client ()
  "Remove one of this file's clients."
  (interactive)
  (setq patrons-client-list
        (delete
         (completing-read
          "Remove client: " patrons-client-list nil t)
         patrons-client-list))
  (when (eq patrons-client-list nil)
    (patrons-drop-clients)))

(defun patrons-drop-clients ()
  "Remove this file as a patron."
  (interactive)
  (setq patrons-client-list nil)
  (setq patrons-list
        (delq (assoc buffer-file-name patrons-list)
              patrons-list))
  (patrons-mode 0))

(define-minor-mode patrons-mode
  "Toggle client file mode.
     With no argument, this command toggles the mode.
     Non-null prefix argument turns on the mode.
     Null prefix argument turns off the mode.
"
  :lighter " Patron"
  (if patrons-mode
      (patrons-load-client-list)
    (patrons-save-client-list-or-exit)))

(provide 'patrons-mode)

Posted October 15, 2009
// 2 Comments

Delete blank lines

One of the commands I use most often in Emacs, especially when editing code, is delete-blank-lines (C-x C-o). Documentation:

On blank line, delete all surrounding blank lines, leaving just one.
On isolated blank line, delete that one.
On nonblank line, delete any immediately following blank lines.

Very nice. But I want it do more. I want it to fix up the indentation after it removes, and I want it to join lines. It seems silly to me that calling it once removes all but one blank line, calling it twice removes the last blank lines, and calling it thrice—does nothing. It should join the lines.

The source code for the function is pretty straightforward. It sets two variables, thisblank and nextblank, and behaves according to their values. So I wrote an advice.

(defadvice delete-blank-lines (around salcher/delete-blank-lines-indent-or-join activate compile)
  "After removing blank lines, indent; without blank lines, join."
  (let (thisblank nextblank)
    (progn
      (save-excursion
        (beginning-of-line)
        (setq thisblank (looking-at "[ \t]*$"))
        (setq nextblank (progn
                          (forward-line)
                          (beginning-of-line)
                          (looking-at "[ \t]*$"))))
      (cond
       ;; if this and next are blank, do it then indent
       ((and thisblank nextblank)
        (progn
          ad-do-it
         (unless (eq comment-start nil)
           (progn
             (indent-according-to-mode)))))
       ;; if this isn't blank but next is, do it then indent the next line.
       ((and (not thisblank) nextblank)
        (progn
          ad-do-it
         (unless (eq comment-start nil)
           (progn
             (save-excursion
               (forward-line)
               (indent-according-to-mode))))))
       ;; join if no blank lines
       ((and (not thisblank) (not nextblank))
        (join-line 1))
       (t ad-do-it)))))

This is probably the only piece of Elisp I've written that I use almost every day.

(I know, I overuse progn.  I don't have a feel for it yet.)

(This was a test of how Posterous handles code formatted by htmlize.  It failed the first time—stripped the <pre> tags from the email.  Had to paste it in by hand.)

Filed under  //   elisp   emacs  
Posted October 12, 2009
// 0 Comments

5 ways to save battery power in Ubuntu

(Finally.  I've always wanted to write a blog post with N ways to do something.)

To begin with, I reject two obvious steps: run a different, lighter distro; and don't use KDE.

 I use Ubuntu on my laptop for one overriding reason: hardware compatibility. Slackware was my first distro, and I loved it. I love it still. On my desktop it worked fine. On my laptop—it didn't. I spent insane amounts of time—months—trying to make X work on that laptop. I learned a lot about Linux. I learned so much about Linux that my next distro was… Cygwin.

 I never ever want to go through that again. I never ever even want to be reminded of that experience again. On a desktop, I am willing to try other distros. Never on a laptop.

 As for KDE: this is my caprice. I just like KDE better than GNOME or Xfce. It just seems better thought out. Take a simple example: shutdown scripts. It's easy enough in any desktop environment to create scripts to run on startup.  Only KDE provides a straightforward facility to run scripts on shutdown. (This saves me having to explicitly kill the Emacs daemon every time I shut down.)

 (To be honest, KDE4 has been severely testing my patience, but they seem to have their act together now. I rarely have to switch to a virtual console and pkill -9 kscreenlocker anymore.)

 (I know there's a whole world of tiling window manager's out there, but they strike me as gimmicky, like most efforts to Emacsify things that aren't Emacs. I love Emacs. I'm writing this in Emacs.  But anything beyond readline compatibility just crosses my wires—frustrates me with false expectations.  I want all of Emacs or nothing.)

 Anyway, there were supposed to be instructions.

 I assume you know the basics: turn your modem off when you're not using it, lower the screen brightness, leave the sound off, etc.

 The first way to save power: turn off the Flash plugin. This isn't Ubuntu-specific, but it's the best place to start. Just having the flash plugin on—without having any Flash video playing—accounts for half the processor activity on the machine.

 (In Opera you can toggle plugins on & off with two keystrokes: <f12> u. I assume there are ways to do this in Firefox. Google it.)

 The second way to save power: lower the swappiness. Swappiness weights how likely the kernel is to use swap. The default for Ubuntu is 60—absurdly high. On a laptop you never, ever want to use swap. The performance penalty of not using swap is always preferable to the battery drain of requiring the hard disk to mimic RAM. You can try this out:

 sudo bash 
echo 10 > /proc/sys/vm/swappiness

 (You could set it to 0 but this might screw things up if you run something very demanding, which you shouldn't do, but you might do without meaning to. I keep it at 10 and the machine never uses swap.)

 (sudo bash in the above is a gutless root shell. You could sudo su root or sudo -i too but this won't work with your usual sudo make -blt sandwich approach.)

 To make this permanent put vm.swappiness = 20 in sysctl.conf

 The third way: mount /tmp as a ramdisk. This is as simple as adding a line to the end of your /etc/fstab:

  
tmpfs /tmp tmpfs defaults,nosuid,size=1g,mode=1777 0 0

 N.B. Whenever you are watching Flash video, the video is being written to /tmp. If you must use Flash on battery power, this makes it a lot easier on the battery.

 (You could also write a autostart script to create a series of folders in /tmp & symlink all your browser cache folders to them. Exercise for the reader.)

 The fourth and fifth ways: powertop and laptop-mode. Powertop is a neato program that analyzes processor activity and show you what's hogging cycles (like Flash). Laptop-mode (included but deactivated in Ubuntu) is a neato kernel feature that spools and spaces out writes to the disk. They come together in this list because although Powertop will suggest and execute changes to your system, it can't make any of these changes permanent. Laptop-mode lets you do that. First run powertop. Write down all of its suggestions. Then go to /etc/laptop-mode/conf.d/ and start poking around. All of the changes laptop-mode suggests can made permanent by altering the appropriate configuration files here.

 (And turn laptop-mode on: in /etc/laptop-mode/laptop-mode.conf set ENABLE_LAPTOP_MODE_ON_BATTERY=1.)

And that's five. With just these five changes I actually get the battery life (under normal use) that the ad said I would.

 

 

Filed under  //   battery   emacs   kde   laptop   linux   powersaving   ubuntu  
Posted October 11, 2009
// 0 Comments

Gnus & Gmail

I read email with Gnus from Gmail via IMAP, using a Labs feature that 
makes Gmail behave more like a standard IMAP server. One very nice
behavior is that mail splitting in Gnus creates corresponding labels in
Gmail without my having to do anything else.

But some things are still weird. I stumbled over one yesterday. If you
tell Gnus to split a message into a group that has the same name as an
existing label in Gmail, & if you haven't told Gmail to make that label
visible in IMAP, the message disappears from Gmail—at least temporarily.
This happened to me yesterday. I thought it was gone—it wasn't in All
Mail or Trash or anywhere—but now it's back, and in the correct group.
My guess would be that Gnus still had it cached and added it back.
Weird.

Filed under  //   emacs   gmail   gnus  
Posted October 4, 2009
// 0 Comments

svn:ignore

To my grave annoyance Subversion's svn:ignore property is not recursive.
This means that I either have to remember to repeat svn propset
ignore
for every directory every time I create one, or I have to
run:

svn propset -R svn:ignore . -F svn-ignores 

Which recursively sets the ignore property but makes for a change that 
has to be committed on every single directory. This gets very confusing
when working with the same project on more than one machine: if I set
the ignore property on a directory, try to check in, realize I have to
update, update, and check in again, the ignore property changes back
without my realizing it. Obnoxious is the word, rather than confusing.
I try to maintain an svn-ignores file in the base directory &
only set ignore properties by reading it  in, which mostly 
prevents these kinds of mistakes, but there has to be a better way.

Filed under  //   subversion   svn  
Posted October 3, 2009
// 0 Comments