2011-02-23

Kinesis keyboard

So now I've used the kinesis advantage keyboard fro the last couple months. Overall, I'm rather pleased with it.

Original layout

My adaptations:

  • I swapped the caps-lock and the left ctrl key. I'm an emacs user, and the position of the left and right ctrl keys are really difficult to reach. This is something I do anyway on all my keyboards, so no real difference there.
  • I made the backspace key (under the left thumb into an alt key, since I do meta commands all the time.
  • I made the delete key into a backspace key.
  • The arrow keys are re-mapped, so that they are arranged as in vi- that is, left, down, up, and right.
  • Here are some of my thoughts on the keyboard:

    • PRO: A week or two after starting to use this keyboard, my pains in my left thumb disappeared.
    • PRO: After three weeks, my typing speed was almost as quick as it was before. That being said, I still (after three months) do not type quite as quickly as I do on a regular non-ergonomic keyboard.
    • CON: The position of the enter and space keys on the right makes it difficult to reach using the left hand. This isn't usually a problem, but when I use the mouse with the right hand and I want to hit a space (or enter) at a position, its annoying.
    • CON: The function keys are smaller than the normal ones. This forces me to look and search for the key when I want to use them. Annoying.

    Overall, I really like the keyboard. Besides the fact that my nascent RSI has disappeared, it's actually a pleasure to write- it just feels.. good.

    2011-02-06

    emacs daemon, terminal and X-windows

    One of the things I really liked most about emacs23 was it's daemon. In earlier incarnations of emacs I used emacs-server, which was nice, but didnt really do it all. Among other things, if I started one session in X, then I couldn't reach it when I started a client using the -nw flag.

    All that changed with emacs23. I could leave my emacs session running at my work computer, with all these buffers, then when I got home I could just ssh in to the machine and start emacs client in a terminal and pick up where I left off in the same buffers.

    The problem, I noticed, was that some of my old modifications in my .emacs tree failed to run when I started emacs in the terminal- the gtk toolbar killer for one.

    I like my emacs as minimal as possible, so no menu bar, no scroll bars, and definitely no gtk buttons at the top of the screen. Earlier, in pre-emacs23 days, I rarely started emacs in a terminal- I would VNC in instead, to get to my buffers. Now, I found that some configs failed and blocked emacs from running if I started it in the terminal.

    So I decided to look around, and found a nice hook which fit the bill- after-make-frame-functions. This variable contains a list of functions which will all be run after a new emacs frame is shown. The functions must take one param- the frame itself. Very nice.

    Some of the settings in the hook below don't necessarily have to be in this hook, but I felt that since they all have to do with the new frame, they would fit nicely together there...

    (defun setup-frame-hook (frame)
      "This function will be applied to all new emacs frames."
      (set-frame-parameter frame 'alpha '(95 95)) ; translucency                                                                                                                      
      (mouse-avoidance-mode 'cat-and-mouse) ; avoid mouse                                                                                                                             
      (fringe-mode 5)                       ; make fringes smaller                                                                                                                    
      (tool-bar-mode 0)                     ; no toolbar                                                                                                                                
      (menu-bar-mode 0)                     ; no menubar                                                                                                                              
      (scroll-bar-mode 0)                   ; no scrollbar                                                                                                                            
      (set-frame-parameter (selected-frame) 'alpha '(95 95)) ; translucency                                                                                                           
      )
    (add-hook 'after-make-frame-functions 'setup-frame-hook)
    

    The last function (add-hook) prepends the function setup-frame-hook to the list.

    2010-11-07

    Built-in functions in emacs

    For the last couple days I've being trying to add advice (http://bit.ly/9khTDk) to execute-extended-command (Aka M-x). What I wanted to do was have a function executed directly after execute-extended-command, which keeps track of what commands I use, which I then can study to see what I could add a key-binding to.

    The thing is, it didnt run. Damn irritating.

    First, I thought it was a variable scope issue. Perhaps the hash I wrote to from the advice wasnt the one I declared? To see if it was actually run, I made the function output a message to the *Message* buffer, which it never did when I ran M-x foo.

    So then I thought 'hmm, perhaps the advice never triggered?', so I looked in the variable ad-advised-functions, where my advice showed up. Ok, so its in the list of advices to be run.

    So I went and asked uncle google, and after a little fiddling with search terms, I found this: http://aaronhawley.livejournal.com/26901.html

    You dont have to follow that link, I'll summarize: You can advise almost all functions in emacs. To be more specific, you can advise functions written in emacs-lisp, but not the ones written in C.

    execute-extended-command is written in C. And so Aaron S. Hawley re-wrote it, in elisp. Rather pretty code, but also complex, implying that there could be a bug lurking there.

    Now the question I'm asking myself is- shall I replace my built-in execute-extended-command with his elisp variant, or write a wrapper function which I can then bind to M-x?

    2010-04-17

    Sorting all A-records in region

    So, you've got a lot of A-records in your DNS zone file, and for one reason or the other you dont want to sort all the records in ascending order by IP. It could be that you have each A-record followed by TXTs or CNAMEs, or whatever.

    I often want to know what IPs are free. By sorting them I can easily see which ones are not in use.

    (defun sort-A-records (start-pos end-pos)
      "Given a DNS buffer containing a bunch of A-records, this
    function finds all records inside a region and sorts them by ip
    address. The output is placed in a temporary buffer called
    'sorted-ips'.
    
    Todo someday: support the GENERATE directive"
      (interactive "r")
    
      ;; --------------------------------------------------
      ;; Helper functions
      (defun eq-octet (a b index)
        (= (string-to-number (nth index a))
           (string-to-number (nth index b))))
    
      (defun lt-octet (a b index)
        (< (string-to-number (nth index a))
                        (string-to-number (nth index b))))
    
    
      (defun sort-hash-by-ip (hashtable)
        (let (mylist)
          (setq mylist         ;; Create a list of ip-hostname pairs
                (let (mylist)
                  (maphash
                   (lambda (kk vv)
                     (setq mylist (cons (list kk vv) mylist))) hashtable)
                  mylist
                  ))
          (sort mylist         ;; sort them by ip
                (lambda (y z)
                  (setq y (split-string  (car y) "\\."))
                  (setq z (split-string  (car z) "\\."))
    
                  (if (eq-octet y z 0)
                      (if (eq-octet y z 1)
                          (if (eq-octet y z 2)
                              (lt-octet y z 3)
                            (lt-octet y z 2))
                        (lt-octet y z 1))
                    (lt-octet y z 0))
                  )
                )
          )
        )
    
    
    
      ;; --------------------------------------------------
      ;; Main body starts here
      (let (iphash)
        ;; create hash
        (setq iphash (make-hash-table :test 'equal))
    
        ;; if no region selected, just grab all A-records from point.
        (setq end-pos (if (= (point) (mark)) (end-of-buffer)))
        (if (> (point) (mark)) (exchange-point-and-mark))
    
        (while (search-forward-regexp
                "^\\([[:alnum:]\.-]+\\).*?[ ''\t'']A[ ''\t'']+.*?\\([[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\\)" end-pos 1)
          (puthash (match-string 2) (match-string 1) iphash)
          )
    
        (with-output-to-temp-buffer "sorted-ips"
          (let (item mylist)
            (setq mylist (sort-hash-by-ip iphash))
            (while (setq item (pop mylist))
              (princ (format "%s\t%s\n" (car item) (cadr item)))
              )
            )
          )
        )
      )
    

    Emacs lisp

    These last couple days I've been fiddling more and more with emacs lisp, aka elisp. Its nice to finally have the time to program for fun. I haven't done any lisp-like programming since Uni, and I've missed it.

    Heres a little function I wrote a couple months ago which solves something which bugged me for a long time. At work, we work with DNS zone files alot, and we make heavy use of the $include directive. This means that one zone file is spread out among anything between one to dozens of files.

    When opening one of these files, emacs looks through the syntax and decides that the contents of the buffer should be in DNS mode, and sets the major-mode accordingly. And with normal one-file zonefiles this wouldn't be a problem. In multi-file zonefiles, this becomes a pain, since it tries to help by incrementing the serial number in the SOA-record when saving.

    In multi-file zonefiles all but one of the files (the first one, which $includes all the others) lack a SOA post. So emacs refuses to save complaining that it "Cannot locate SOA record".

    So I wrote a very small and nice piece of advice which is called just before calling the soa serial increment function.

    The thing is, we don't specify a Serial number at all- that is taken care of by the Makefile which does all the syntax checks, zone transfers, etc for us. So... we want to avoid incrementing the serial if

    1. There is no SOA post
    2. There is a SOA post, but a serial spaceholder is there too, namely '@SERIAL@'.
    ;; auto-activated if we're in dns-mode.
    (defadvice dns-mode-soa-maybe-increment-serial (before maybe-set-increment)
      "if there is a dns soa post and no @SERIAL@, increment it. Otherwise, do nothing"
      (save-excursion
        (goto-char (point-min))
        (setq dns-mode-soa-auto-increment-serial
              (and (search-forward-regexp "IN[ ''\t'']+SOA" nil t)
                   (not (search-forward-regexp "@SERIAL@" nil t))))
        )
      )
    (ad-activate 'dns-mode-soa-maybe-increment-serial)
    

    2009-09-20

    Modifying gnome-terminal to understand Spotify URIs

    My primary tool on my Debian box (asides from emacs) is gnome-terminal. I use mutt for email, and irssi for irc.

    And since I'm an avid user of Spotify, and trade links to music with my friends and collegues, I've been irritated about the fact that I cant click on Spotify URIs in the terminal like I can with mailto: and http: tags.

    So I fixed it. Its a rather simple fix, but very useful. Here's how I did it. Oh and btw, since Lenny's version of gnome-terminal is rather old, this fix works only on gnome-terminal version 2.22.3- the version which comes with Lenny.

    Anyway, quick summary of what we'll do. We download the source for gnome-terminal, apply a little patch to it, compile the code, and register the spotify: URI with gnome.

    1. Download and unpack the source code
      $ wget  http://ftp.acc.umu.se/pub/gnome/sources/gnome-terminal/2.22/gnome-terminal-2.22.3.tar.gz
      $ tar zxvf gnome-terminal-2.22.3.tar.gz
      $ cd gnome-terminal-2.22.3/
    2. Apply patch
      $ cat > gnome-terminal-spotify.diff <<EOF
      87c87,88
      <   FLAVOR_EMAIL
      ---
      >   FLAVOR_EMAIL,
      >   FLAVOR_SPOTIFY
      314c315
      < #define SCHEME    "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)"
      ---
      > #define SCHEME    "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:|spotify:)"
      332a334,337
      >                            "\\<(spotify:)[^<>\ \t\n\r]*\\>",
      >                            FLAVOR_SPOTIFY);
      > 
      >   terminal_widget_match_add (screen->priv->term,
      1438a1444,1446
      >     case FLAVOR_SPOTIFY:
      >       url = g_strdup (orig_url);
      >       break;
      EOF
      $ patch src/terminal-screen.c gnome-terminal-spotify.diff
    3. Compile the code
      $ ./configure
      $ make
      $ sudo make install
    4. Register the spotify: URI
      $ gconftool-2 --set --type=string /desktop/gnome/url-handlers/spotify/command " wine 'c:\Program Files\Spotify\Spotify.exe' '-uri' '%s'"
      $ gconftool-2 --set --type=bool /desktop/gnome/url-handlers/spotify/enabled true
      $ gconftool-2 --set --type=bool /desktop/gnome/url-handlers/spotify/need-terminal false

    Remember that all the different gnome-terminals run under the same process, so when testing you'll want to spawn one as a separate process:

    /usr/local/bin/gnome-terminal --disable-factory

    All done!

    2009-07-11

    Pain upgrading the iPhone to 3.0 under Virtualbox

    Edit: I was informed by neh that all this was unnecessary, as you can get Vbox to auto-connects devices. Thanks Nathan!

    Long story short: An upgrade to iphone version 3.0 under virtualbox and Debian as host system is possible, but it has to be done just right.

    What you need to know before upgrading:

    • During the upgrade, the iPhone changes USB ID twice.

    Yep thats about it. What you do is this.

    1. Jack in your iPhone to your linux box.
    2. Verify that it has been connected by running the command 'lsusb' in a terminal. You should see something like this:
      $ lsusb | grep -i apple
      Bus 001 Device 006: ID 05ac:1292 Apple, Inc. 
      $
      
    3. Now start virtualbox. In the settings for your Windows guestOS, under USB: check that your iPhone is visible and selected.
    4. Start the guestOS. Your iPhone should be autodetected and iTunes should start up.
    5. Tell iTunes to start the upgrade. (I have to admit I dont remember if iTunes prompted me to upgrade or if I somehow chose to. Click around till you get to upgrade.)
    6. Once it starts to upgrade, you'll notice that an icon at the bottom of the vbox window (dont run full screen!) looks kind of like a usb stick. Hover your mouse over it, and you should see a popup with a string like "Apple Iphone".
    7. Here's the tricky part. Once it is ready to upgrade, the iPhone drops into 'recovery mode', and it changes USB ID. When it changes USB ID it VirtualBox will
      1. Detect that the old usb device (Apple Inc. iPhone) has disappeared.
      2. not automatically present the new device which your linux machine has detected.
    8. Turn off your guestOS (even if you need to SIGKILL it).
    9. Start up Virtualbox again.
    10. In the Settings for USB, look for the new device. It should be called something like "iPhone recovery device" or something.
    11. Make sure that both your original iPhone device and the new device are visible in your list of USB devices. Only the recovery device need be checked.
    12. Start up your guestOS.
    13. Once started, check that the Recovery USB device is actually activated, by hovering over the USB icon at the bottom of the vbox window. If it doesn't show the name of the recovery device in bold, right click the icon and select it to activate it.
      For me, this happened a number of times. There seems to be a timer involved- if you dont re-activate the device in time, you'll have to start again from the previous bullet. You'll get an error message- I think it was error 1604. Like I said, just restart the guestOS, and you should be fine.
      Note: I had to restart my hostOS as well once, since I uncleanly killed the virtualbox process, leaving a tainted kernel module which refused to work properly.
    14. After a while, the process reverses itself- that is, the recovery device is not considered necessary anymore, and it disappears from the list of USB devices. Instead, you'll need to actively select the regular iPhone device. The normal timer rule applies.
    15. After a few more activating devices manually, you should be told by iTunes that the upgrade is complete. Now you'll need to re-activate the iphone device one last time for the final sync, to get all your precious data back into your system.

    Thats about it!