Shallow Thoughts

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Fri, 05 Feb 2016

Updating Debian under a chroot

Debian's Unstable ("Sid") distribution has been terrible lately. They're switching to a version of X that doesn't require root, and apparently the X transition has broken all sorts of things in ways that are hard to fix and there's no ETA for when things might get any better.

And, being Debian, there's no real bug system so you can't just CC yourself on the bug to see when new fixes might be available to try. You just have to wait, try every few days and see if the system

That's hard when the system doesn't work at all. Last week, I was booting into a shell but X wouldn't run, so at least I could pull updates. This week, X starts but the keyboard and mouse don't work at all, making it hard to run an upgrade. has been fixed.

Fortunately, I have an install of Debian stable ("Jessie") on this system as well. When I partition a large disk I always reserve several root partitions so I can try out other Linux distros, and when running the more experimental versions, like Sid, sometimes that's a life saver. So I've been running Jessie while I wait for Sid to get fixed. The only trick is: how can I upgrade my Sid partition while running Jessie, since Sid isn't usable at all?

I have an entry in /etc/fstab that lets me mount my Sid partition easily:

/dev/sda6 /sid ext4 defaults,user,noauto,exec 0 0
So I can type mount /sid as myself, without even needing to be root.

But Debian's apt upgrade tools assume everything will be on /, not on /sid. So I'll need to use chroot /sid (as root) to change the root of the filesystem to /sid. That only affects the shell where I type that command; the rest of my system will still be happily running Jessie.

Mount the special filesystems

That mostly works, but not quite, because I get a lot of errors like permission denied: /dev/null.

/dev/null is a device: you can write to it and the bytes disappear, as if into a black hole except without Hawking radiation. Since /dev is implemented by the kernel and udev, in the chroot it's just an empty directory. And if a program opens /dev/null in the chroot, it might create a regular file there and actually write to it. You wouldn't want that: it eats up disk space and can slow things down a lot.

The way to fix that is before you chroot: mount --bind /dev /sid/dev which will make /sid/dev a mirror of the real /dev. It has to be done before the chroot because inside the chroot, you no longer have access to the running system's /dev.

But there is a different syntax you can use after chrooting:

mount -t proc proc proc/
mount --rbind /sys sys/
mount --rbind /dev dev/

It's a good idea to do this for /proc and /sys as well, and Debian recommends adding /dev/pts (which must be done after you've mounted /dev), even though most of these probably won't come into play during your upgrade.

Mount /boot

Finally, on my multi-boot system, I have one shared /boot partition with kernels for Jessie, Sid and any other distros I have installed on this system. (That's somewhat hard to do using grub2 but easy on Debian though you may need to turn off auto-update and Debian is making it harder to use extlinux now.) Anyway, if you have a separate /boot partition, you'll want it mounted in the chroot, in case the update needs to add a new kernel. Since you presumably already have the same /boot mounted on the running system, use mount --bind for that as well.

So here's the final set of commands to run, as root:

mount /sid
mount --bind /proc /sid/proc
mount --bind /sys /sid/sys
mount --bind /dev /sid/dev
mount --bind /dev/pts /sid/dev/pts
mount --bind /boot /sid/boot
chroot /sid

And then you can proceed with your apt-get update, apt-get dist-upgrade etc. When you're finished, you can unmount everything with one command:

umount --recursive /sid

Some helpful background reading:

Tags: , , ,
[ 11:43 Feb 05, 2016    More linux/install | permalink to this entry | comments ]

Sun, 31 Jan 2016

Setting mouse speed in X

My mouse died recently: the middle button started bouncing, so a middle button click would show up as two clicks instead of one. What a piece of junk -- I only bought that Logitech some ten years ago! (Seriously, I'm pretty amazed how long it lasted, considering it wasn't anything fancy.)

I replaced it with another Logitech, which turned out to be quite difficult to find. Turns out most stores only sell cordless mice these days. Why would I want something that depends on batteries to use every day at my desktop?

But I finally found another basic corded Logitech mouse (at Office Depot). Brought it home and it worked fine, except that the speed was way too fast, much faster than my old mouse. So I needed to find out how to change mouse speed.

X11 has traditionally made it easy to change mouse acceleration, but that wasn't what I wanted. I like my mouse to be fairly linear, not slow to start then suddenly zippy. There's no X11 property for mouse speed; it turns out that to set mouse speed, you need to call it Deceleration.

But first, you need to get the ID for your mouse.

$ xinput list| grep -i mouse
⎜   ↳ Logitech USB Optical Mouse                id=11   [slave  pointer  (2)]

Armed with the ID of 11, we can find the current speed (deceleration) and its ID:

$ xinput list-props 11 | grep Deceleration
        Device Accel Constant Deceleration (259):       3.500000
        Device Accel Adaptive Deceleration (260):       1.000000

Constant deceleration is what I want to set, so I'll use that ID of 259 and set the new deceleration to 2:

$ xinput set-prop 11 259 2

That's fine for doing it once. But what if you want it to happen automatically when you start X? Those constants might all stay the same, but what if they don't?

So let's build a shell pipeline that should work even if the constants aren't.

First, let's get the mouse ID out of xinput list. We want to pull out the digits immediately following "id=", and nothing else.

$ xinput list | grep Mouse | sed 's/.*id=\([0-9]*\).*/\1/'
11

Save that in a variable (because we'll need to use it more than once) and feed it in to list-props to get the deceleration ID. Then use sed again, in the same way, to pull out just the thing in parentheses following "Deceleration":

$ mouseid=$(xinput list | grep Mouse | sed 's/.*id=\([0-9]*\).*/\1/')
$ xinput list-props $mouseid | grep 'Constant Deceleration'
        Device Accel Constant Deceleration (262):       2.000000
$ xinput list-props $mouseid | grep 'Constant Deceleration' | sed 's/.* Deceleration (\([0-9]*\)).*/\1/'
262

Whew! Now we have a way of getting both the mouse ID and the ID for the "Constant Deceleration" parameter, and we can pass them in to set-prop with our desired value (I'm using 2) tacked onto the end:

$ xinput set-prop $mouseid $(xinput list-props $mouseid | grep 'Constant Deceleration' | sed 's/.* Deceleration (\([0-9]*\)).*/\1/') 2

Add those two lines (setting the mouseid, then the final xinput line) wherever your window manager will run them when you start X. For me, using Openbox, they go in .config/openbox/autostart. And now my mouse will automatically be the speed I want it to be.

Tags: , ,
[ 13:42 Jan 31, 2016    More linux | permalink to this entry | comments ]

Wed, 13 Jan 2016

Snow hiking

[Akk on snowshoes crossing the Jemez East Fork]

It's been snowing quite a bit! Radical, and fun, for a California ex-pat. But it doesn't slow down the weekly hiking group I'm in. When the weather turns white, the group switches to cross-country skiing and snowshoeing.

A few weeks ago, I tried cross-country skiing for the first time. (I've downhill skied a handful of times, so I know how, more or less, but never got very good at it. Ski areas are way too far away and way too expensive in Californian.) It was fun, but I have a chronic rotator cuff problem, probably left over from an old motorcycle injury, and found my shoulder didn't deal well with skiing. Well, the skiing was probably fine. It was probably more the falling and trying to get back up again that it didn't like.

So for the past two weeks I've tried snowshoes instead. That went just fine. It doesn't take much learning: it's just like hiking, except a little bit harder work remembering not to step on your own big feet. "Bozo goes hiking!" Dave called it, but it isn't nearly as Bozo-esque as I thought it would be.

Last week we snowshoed from a campground out to the edge of Frijoles Canyon, in a snowstorm most of the way, and ice fog -- sounds harsh when described like that, but it was lovely, and we were plenty warm when we were moving. This week, we followed the prettiest trail in the area, the East Fork of the Jemez River. In summer, it's a vibrantly green meadow with the sparkling creek snaking through it. In winter, it turns into a green and sparkling white forest. Someone took a photo of me snowshoeing across one of the many log bridges spanning the East Fork. You can't see any hint of the river itself -- it's buried in snow.

But if you hike in far enough, there's a warm spring: we're on the edge of the Valles Caldera, an old supervolcano that still has plenty of low-level geothermal activity left. The river is warm enough here that it's still running even in midwinter ... and there was a dipper there. American dippers are little birds that dive into creeks and fly under the water in search of food. They're in constant motion, diving, re-emerging, bathing, shaking off, and this dipper went about its business fifteen feet from where we were standing watching it. Someone had told me that he saw two dippers at this spot yesterday, but we were happy to get such a good look at even one.

We had lunch in a sunny spot downstream from the dipper, then headed back to the trailhead. A lovely way to spend a winter day.

Tags: ,
[ 19:01 Jan 13, 2016    More misc | permalink to this entry | comments ]

Wed, 06 Jan 2016

Speaking at SCALE 14x

I'm working on my GIMP talk for SCALE 14x, the Southern California Linux Expo in Pasadena.

[GIMP] My talk is at 11:30 on Saturday, January 23: Stupid GIMP tricks (and smart ones, too).

I'm sure anyone reading my blog knows that GIMP is the GNU Image Manipulation Program, the free open-source photo and image editing program which just celebrated its 20th birthday last month. I'll be covering an assortment of tips and tricks for beginning and intermediate GIMP users, and I'll also give a quick preview of some new and cool features that will be coming in the next GIMP release, 2.10.

I haven't finished assembling the final talk yet -- if you have any suggestions for things you'd love to see in a GIMP talk, let me know. No guarantees, but if I get any requests I'll try to accommodate them.

Come to SCALE! I've spoken at SCALE several times in the past, and it's a great conference -- plenty of meaty technical talks, but it's also the most newbie-friendly conference I've been to, with talks spanning the spectrum from introductions to setting up Linux or introductory Python programming all the way to kernel configuration and embedded boot systems. This year, there's also an extensive "Ubucon" for Ubuntu users, including a keynote by Mark Shuttleworth. And speaking of keynotes, the main conference has great ones: Cory Doctorow on Friday and Sarah Sharp on Sunday, with Saturday's keynote yet to be announced.

In the past, SCALE been held at hotels near LAX, which is about the ugliest possible part of LA. I'm excited that the conference moving to Pasadena this year: Pasadena is a much more congenial place to be, prettier, closer to good restaurants, and it's even close to public transportation.

And best of all, SCALE is fairly inexpensive compared to most conferences. Even more so if you use the promo-code SPEAK for a discount when registering.

Tags: , , , ,
[ 16:32 Jan 06, 2016    More conferences | permalink to this entry | comments ]

Thu, 31 Dec 2015

Weather musing, and poor insulation

It's lovely and sunny today. I was just out on the patio working on some outdoor projects; I was wearing a sweatshirt, but no jacket or hat, and the temperature seemed perfect.

Then I came inside to write about our snowstorm of a few days ago, and looked up the weather. NOAA reports it's 23°F at Los Alamos airport, last reading half an hour ago. Our notoriously inaccurate (like every one we've tried) outdoor digital thermometer says it's 26°.

Weather is crazily different here. In California, we were shivering and miserable when the temperature dropped below 60°F. We've speculated a lot on why it's so different here. The biggest difference is probably that it's usually sunny here. In the bay area, if the temperature is below 60°F it's probably because it's overcast. Direct sun makes a huge difference, especially the sun up here at 6500-7500' elevation. (It feels plenty cold at 26°F in the shade.) The thin, dry air is probably another factor, or two other factors: it's not clear what's more important, thin, dry, or both.

We did a lot of weather research when we were choosing a place to move. We thought we'd have trouble with snowy winters, and would probably want to take vacations in winter to travel to warmer climes. Turns out we didn't know anything. When we were house-hunting, we went for a hike on a 17° day, and with our normal jackets and gloves we were fine. 26° is lovely here if you're in the sun, and the rare 90° summer day, so oppressive in the Bay Area, is still fairly pleasant if you can find some shade.

But back to that storm: a few days ago, we had a snowstorm combined with killer blustery winds. The wind direction was whipping around, coming from unexpected directions -- we never get north winds here -- and it taught us some things about the new house that we hadn't realized in the nearly two years we've lived here.

[Snow coming under the bedroom door] For example, the bedroom was cold. I mean really cold. The windows on the north wall were making all kinds of funny rattling noises -- turned out some of them had leaks around their frames. There's a door on the north wall, too, that leads out onto a deck, and the area around that was pretty cold too, though I thought a lot of that was leakage through the air conditioner (which had had a cover over it, but the cover had already blown away in the winds). We put some towels around the base of the door and windows.

Thank goodness for lots of blankets and down comforters -- I was warm enough overnight, except for cold hands while reading in bed. In the morning, we pulled the towel away from the door, and discovered a small snowdrift inside the bedroom.

We knew the way that door was hung was fairly hopeless -- we've been trying to arrange for a replacement, but in New Mexico everything happens mañana -- but snowdrifts inside the room are a little extreme.

We've added some extra weatherstripping for now, and with any luck we'll get a better-hung door before the next rare north-wind snowstorm. Meanwhile, I'm enjoying today's sunshine while watching the snow melt in the yard.

Tags: ,
[ 11:28 Dec 31, 2015    More nature | permalink to this entry | comments ]

Sun, 27 Dec 2015

Extlinux on Debian Jessie

Debian "Sid" (unstable) stopped working on my Thinkpad X201 as of the last upgrade -- it's dropping mouse and keyboard events. With any luck that'll get straightened out soon -- I hear I'm not the only one having USB problems with recent Sid updates. But meanwhile, fortunately, I keep a couple of spare root partitions so I can try out different Linux distros. So I decided to switch to the current Debian stable version, "Jessie".

The mouse and keyboard worked fine there. Except it turned out I had never fully upgraded that partition to the "Jessie"; it was still on "Wheezy". So, with much trepidation, I attempted an apt-get update; apt-get dist-upgrade

After an interminable wait for everything to download, though, I was faced with a blue screen asking this:

No bootloader integration code anymore.
The extlinux package does not ship bootloader integration anymore.
If you are upgrading to this version of EXTLINUX your system will not boot any longer if EXTLINUX was the only configured bootloader.
Please install GRUB.
<Ok>

No -- it's not okay! I have good reasons for not using grub2 -- besides which, extlinux on exact machine has been working fine for years under Debian Sid. If it worked on Wheezy and works on Sid, why wouldn't it work on the version in between, Jessie?

And what does it mean not to ship "bootloader integration", anyway? That term is completely unclear, and googling was no help. There have been various Debian bugs filed but of course, no explanation from the developers for exactly what does and doesn't work.

My best guess is that what Debian means by "bootloader integration" is that there's a script that looks at /boot/extlinux/extlinux.conf, figures out which stanza corresponds to the current system, figures out whether there's a new kernel being installed that's different from the one in extlinux.conf, and updates the appropriate kernel and initrd lines to point to the new kernel.

If so, that's something I can do myself easily enough. But what if there's more to it? What would actually happen if I upgraded the extlinux package?

Of course, there's zero documentation on this. I found plenty of questions from people who had hit this warning, but most were from newbies who had no idea what extlinux was or why their systems were using it, and they were advised to install grub. I only found one hit from someone who was intentionally using extlinux. That person aborted the install, held back the package so the potentially nonbooting new version of extlinux wouldn't be installed, then updated extlinux.conf by hand, and apparently that worked fine.

It sounded like a reasonable bet. So here's what I did (as root, of course):

It worked fine. I booted into jessie with the kernel I had specified. And hooray -- my keyboard and mouse work, so I can continue to use my system until Sid becomes usable again.

Tags: , ,
[ 17:28 Dec 27, 2015    More linux/install | permalink to this entry | comments ]

Sun, 20 Dec 2015

Christmas Bird Count

Yesterday was the Los Alamos Christmas Bird Count.

[ Mountain chickadee ] No big deal, right? Most counties have a Christmas Bird Count, a specified day in late December when birders hit the trails and try to identify and count as many birds as they can find. It's coordinated by the Audubon Society, which collects the data so it can be used to track species decline, changes in range in response to global warming, and other scientific questions. The CBC has come a long way from when it split off from an older tradition, the Christmas "Side Hunt", where people would hit the trails and try to kill as many animals as they could.

But the CBC is a big deal in Los Alamos, because we haven't had one since 1953. It turns out that to run an official CBC, you have to be qualified by Audubon and jump through a lot of hoops proving that you can do it properly. Despite there being a very active birding community here, nobody had taken on the job of qualifying us until this year. There was a lot of enthusiasm for the project: I think there were 30 or 40 people participating despite the chilly, overcast weather.

The team I was on was scheduled to start at 7. But I had been on the practice count in March (running a practice count is one of the hoops Audubon makes you jump through), and after dragging myself out of bed at oh-dark-thirty and freezing my toes off slogging through the snow, I had learned that birds are mostly too sensible to come out that early in winter. I tried to remind the other people on the team of what the March morning had been like, but nobody was listening, so I said I'd be late, and I met them at 8. (Still early for me, but I woke up early that morning.)

[ Two very late-season sandhill cranes ] Sure enough, when I got there at 8, there was disappointment over how few birds there were. But actually that continued all day: the promised sun never came out, and I think the birds were hoping for warmer weather. We did see a good assortment of woodpeckers and nuthatches in a small area of Water Canyon, and later, a pair of very late-season sandhill cranes made a low flyover just above where we stood on Estante Way; but mostly, it was disappointing.

In the early afternoon, the team disbanded to go home and watch our respective feeders, except for a couple of people who drove down the highway in search of red-tailed hawks and to the White Rock gas station in search of rock pigeons. (I love it that I'm living in a place where birders have to go out of their way to find rock pigeons to count.)

I didn't actually contribute much on the walks. Most of the others were much more experienced, so mostly my role was to say "Wait, what's that noise?" or "Something flew from that tree to this one" or "Yep, sure enough, two more juncos." But there was one species I thought I could help with: scaled quail. We've been having a regular flock of scaled quail coming by the house this autumn, sometimes as many as 13 at a time, which is apparently unusual for this time of year. I had Dave at home watching for quail while I was out walking around.

When I went home for a lunch break, Dave reported no quail: there had been a coyote sniffing around the yard, scaring away all the birds, and then later there'd been a Cooper's hawk. He'd found the hawk while watching a rock squirrel that was eating birdseed along with the towhees and juncos: the squirrel suddenly sat up and stared intently at something, and Dave followed its gaze to see the hawk perched on the fence. The squirrel then resumed eating, having decided that a Cooper's hawk is too small to be much danger to a squirrel.

[ Scaled quail ] But what with all the predators, there had been no quail. We had lunch, keeping our eyes on the feeder area, when they showed up. Three of them, no, six, no, nine. I kept watch while Dave went over to another window to see if there were any more headed our way. And it turns out there was a whole separate flock, nine more, out in the yard. Eighteen quail in all, a record for us! We'd suspected that we had two different quail families visiting us, but when you're watching one spot with quail constantly running in and out, there's no way to know if it's the same birds or different ones. It needed two people watching different areas to get our high count ot 18. And a good thing: we were the only bird counters in the county who saw any quail, let alone eighteen. So I did get to make a contribution after all.

I carried a camera all day, but my longest regular lens (a 55-250 f/4-5.6) isn't enough when it comes to distant woodpeckers. So most of what I got was blurry, underexposed "record shots", except for the quail, cranes, and an obliging chickadee who wasn't afraid of a bunch of binocular-wielding anthropoids. Photos here: Los Alamos Christmas Bird Count, White Rock team, 2015.

Tags: ,
[ 14:21 Dec 20, 2015    More nature/birds | permalink to this entry | comments ]

Sat, 12 Dec 2015

Emacs rich-text mode: coloring and styling plain text

I use emacs a lot for taking notes, during meetings, while watching lectures in a MOOC, or while researching something.

But one place where emacs falls short is highlighting. For instance, if I paste a section of something I'm researching, then I want to add a comment about it, to differentiate the pasted part from my added comments, I have to resort to horrible hacks like "*********** My comment:". It's like the stuff Outlook users put in emails because they can't figure out how to quote.

What I really want is a simple rich-text mode, where I can highlight sections of text by changing color or making it italic, bold, underlined.

Enter enriched-mode. Start it with M-x enriched-mode and then you can apply some styles with commands like M-o i for italic, M-o b for bold, etc. These styles may or may not be visible depending on the font you're using; for instance, my font is already bold and emacs isn't smart enough to make it bolder, the way some programs are. So if one style doesn't work, try another one.

Enriched mode will save these styles when you save the file, with a markup syntax like <italic>This text is in italic.</italic> When you load the file, you'll just see the styles, not the markup.

Colors

But they're all pretty subtle. I still wanted colors, and none of the documentation tells you much about how to set them.

I found a few pages saying that you can change the color of text in an emacs buffer using the Edit menu, but I hide emacs's menus since I generally have no use for them: emacs can do everything from the keyboard, one of the things I like most about it, so why waste space on a menu I never use? I do that like this:

(tool-bar-mode 0)
(menu-bar-mode 0)

It turns out that although the right mouse button just extends the selection, Control-middleclick gives a context menu. Whew! Finally a way to change colors! But it's not at all easy to use: Control-middleclick, mouse over Foreground Color, slide right to Other..., click, and the menu goes away and now there's a prompt in the minibuffer where you can type in a color name.

Colors are saved in the file with a syntax like: <x-color><param>red</param>This text is in red.</x-color>

All that clicking is a lot of steps, and requires taking my hands off the keyboard. How do I change colors in an easier, keyboard driven way? I drew a complete blank with my web searches. A somewhat irritable person on #emacs eventually hinted that I should be using overlays, and I eventually figured out how to set overlay colors ((overlay-put (make-overlay ...)) turned out to be the way to do that) but it was a complete red herring: enriched-mode doesn't pay any attention to overlay colors. I don't know what overlays are useful for, but it's not that.

But in emacs, you can find out what's bound to a key with describe-key. Maybe that works for mouse clicks too? I ran describe-key, held down Control, clicked the middle button -- the context menu came up -- then navigated to Foreground Color and Other... and discovered that it's calling (facemenu-set-foreground COLOR &optional START END).

Binding to keys

Finally, a function I can bind to a key! COLOR is just a string, like "red". The documentation implies that START and END are optional, and that the function will apply to the selected region if there is one. But in practice, if you don't specify START and END, nothing happens, so you have to specify them. (region-beginning) and (region-end) work if you have a selected region.

Similarly, I learned that Face->italic from that same menu calls (facemenu-set-italic), and likewise for bold, underline etc. They work on the selected region.

But what if there's no region defined? I decided it might be nice to be able to set styles for the current line, without selecting it first. I can use (line-beginning-position) and (line-end-position) for START and END. So I wrote a wrapper function. For that, I didn't want to use specific functions like (facemenu-set-italic); I wanted to be able pass a property like "italic" to my wrapper function.

I found a way to do that: (put-text-property START END 'italic). But that wasn't quite enough, because put-text-property replaces all properties; you can't make something both italic and bold. To add a property without removing existing ones, use (add-text-properties START END (list 'face 'italic)).

So here's the final code that I put in my .emacs. I was out of excuses to procrastinate, and my enriched-mode bindings worked fine for taking notes on the project which had led to all this procrastination.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Text colors/styles. You can use this in conjunction with enriched-mode.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; rich-style will affect the style of either the selected region,
;; or the current line if no region is selected.
;; style may be an atom indicating a rich-style face,
;; e.g. 'italic or 'bold, using
;;   (put-text-property START END PROPERTY VALUE &optional OBJECT)
;; or a color string, e.g. "red", using
;;   (facemenu-set-foreground COLOR &optional START END)
;; or nil, in which case style will be removed.
(defun rich-style (style)
  (let* ((start (if (use-region-p)
                    (region-beginning) (line-beginning-position)))
                    
         (end   (if (use-region-p)
                    (region-end)  (line-end-position))))
    (cond
     ((null style)      (set-text-properties start end nil))
     ((stringp style)   (facemenu-set-foreground style start end))
     (t                 (add-text-properties start end (list 'face style)))
     )))

(defun enriched-mode-keys ()
  (define-key enriched-mode-map "\C-ci"
    (lambda () (interactive)    (rich-style 'italic)))
  (define-key enriched-mode-map "\C-cB"
    (lambda () (interactive)    (rich-style 'bold)))
  (define-key enriched-mode-map "\C-cu"
    (lambda () (interactive)    (rich-style 'underline)))
  (define-key enriched-mode-map "\C-cr"
    (lambda () (interactive)    (rich-style "red")))
  ;; Repeat for any other colors you want from rgb.txt

  (define-key enriched-mode-map (kbd "C-c ")
    (lambda () (interactive)    (rich-style nil)))
  )
(add-hook 'enriched-mode-hook 'enriched-mode-keys)

Tags: ,
[ 14:48 Dec 12, 2015    More linux/editors | permalink to this entry | comments ]