Skip to main content

skip to main content

developerWorks  >  Linux  >

Cultured Perl: Fun with the Ion window manager

A simple but powerful way to manage your windows

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Teodor Zlatanov (tzz@bu.edu), Programmer, Gold Software Systems

29 Sep 2004

Take a look at the Ion windows manager, a powerful and simple program that manages the windows that applications bring up on your desktop. Ion isn't flashy, but once you get used to it, it can greatly enhance your productivity and make you wonder why you ever used those other window managers.

In this column, you'll get a feel for the Ion window manager for the X Window System. X Window managers are programs that manage the windows that applications bring up. For instance, if you've ever run an XTerm or a Web browser on an X terminal, chances are a window manager was running in the background, helping you control the windows that popped up.

In Microsoft® Windows®, the window manager is very tightly integrated with the rest of the operating system. It's hard to imagine a Windows machine without Explorer windows all over the desktop.

In UNIX®, and in Linux™ specifically, the evolution of the desktop has taken a different course due to a variety of cultural and technological reasons. UNIX adopted X as its window system of choice, and X Window managers were typical UNIX utilities: small, fast, and configurable. Window managers such as twm appealed to minimalists, while the elaborate machinery of the Enlightenment window manager could show off graphics as pretty as anything you've seen. (For information on Ion in MacOS X, see the Resources section.)

Modern UNIX desktops generally have tighter integration between the window manager and the rest of the desktop machinery (CDE, KDE, and Gnome all do this) than ever before, but it's still entirely possible to run with a different window manager than the one your desktop expects.

This article is intended for users comfortable with switching and configuring their window manager (commonly abbreviated to WM). If you are not such a user, beware. Ion is not a gentle WM, and you absolutely need the ability to dig yourself out if you misconfigure Ion or X in such a way that one or the other won't start. Consider yourself warned!

Enter Ion

Ion is a tiling window manager. There are others like it (see the links on the Ion home page listed in the Resources) but, in my opinion, Ion has the best balance of speed, features, extensibility, and configurability. Ion is just 150 kilobytes in size (plus 160 kilobytes in modules as of version 2, in Debian Linux). It is fast.

The full story

Ion actually can do overlapping windows. I hope you learn instead to use the tiling windows, but you can fall back on overlapping-window ("PWM" or "floating") workspaces. They are called PWM workspaces because Ion's predecessor, PWM, did only traditional overlapping window management. These workspaces are also called "floating" because windows appear to float on the screen. The tiling workspaces are generally called Ion workspaces because they have always been in Ion, unlike floating workspaces.

First, a definition. Tiling window managers don't let windows overlap. This may seem strange to you, until you realize that window overlap is one of the main things that hide content from the user. In terms of navigation, tiling window managers are very efficient because there is no z-plane (depth) to the windows they manage. Thus, the user need manage only two dimensions. (see The full story).

One question comes immediately to mind. What happens if there are more windows than will fit on the workspace, especially if you don't want to shrink them to be unmanageably tiny? Here, Ion's other great feature besides tiling comes in: tabs. Tabs are the z-plane of Ion, except that only one tab can ever be visible. Thus, if a window frame has tabs A, B, and C, only one of those can be seen. The other tabs and the windows that belong to them are hidden. Remember this, because it's essential if you want to use Ion well! Many applications today support tabs, so you are probably aware of how they work even if you have not used Ion before.

You can take a look at the Ion home page (see Resources) for screenshots of Ion's tiling behavior and tabs. The screenshots don't look glamorous because Ion isn't glamorous -- but it is (incredibly) functional. Its only object is to get work done, and to that end, bells and whistles like themes are not used. I used Enlightenment before Ion and I must confess that the lack of themes made Ion very unappealing at first, but in the end Ion let me concentrate on what was inside the windows, not their decorations. I recommend that if you try Ion, give it at least a day. The first impression is so jarring that you may be turned away from Ion for the very thing that makes it a good window manager: its simplicity.

One group of users who will find Ion very useful are those who don't like to use the mouse for any reason. Ion makes every function available through a keyboard interface, and using the mouse in Ion is not necessary. Those who want to use the mouse, can; it's just that doing things with the keyboard is easier and faster once you learn the keystrokes.

Finally, I should note that there are many X Window managers, and Ion may not be the one for you. Other window managers similar to Ion are in the Links section of the Ion home page. Look carefully into the ones available for your platform, and choose based on what you like in a window manager. Do try Ion, though. I think you will be glad you did.



Back to top


Ion's history

Throughout its history, Ion has been developed by a Finnish hacker named Tuomo Valkonen. Preceding Ion was the PWM window manager, by the same author. Tuomo is the sole owner of the Ion project, even though Ion as a software package is under the Lesser GNU Public License. Fairly recently, Tuomo put the latest version of Ion in a Subversion repository; instructions for using that repository to get the latest Ion version are on the Ion home page.

Ion has three distinct versions as of July 2004. Ion 1 was the original Ion, written in C. It had a simple configuration format, similar in spirit to the classic UNIX window managers. Ion 1 had no floating (overlapping windows) workspaces, and few features. Nevertheless, Ion 1 was revolutionary in its minimalist, streamlined, and very functional approach. Ion 1 may not have been the first to use tiling workspaces (the idea is hardly new), but it certainly did a good job of it, thanks to tabbing. Tabbing is essential to the success of Ion's tiling approach, and to my knowledge no window manager before PWM had this feature -- or if they did, none used it to such an extent as Ion, which tabs even terminal windows.

Ion 2 was a rewrite of most of Ion. It was still in C, and it cleaned up the object hierarchy to organize the Ion code better. The big changes with Ion 2 were the addition of the optional floating workspaces and the Lua scripting language, which became to Ion what Lisp is to Emacs -- an essential vehicle for customization and extension.

Currently under development, Ion 3 is not a major update to Ion 2 in terms of user-visible features as of now (even though some nifty features are already being tested: session management support, mod_autows, a nicer dock, a scratchpad, and so on). See the Ion 3 repository for more information on these features if you are adventurous.

Ion 3 simplifies many of the features Ion 2 introduced, adds better modules for extending Ion, and is a minor internal rewrite of Ion (although from the scripting side, it has changed quite a bit to reflect lessons learned from Ion 2). Make sure you check the status of Ion 3 before you decide to use it. Ion 3 is a bleeding-edge release with little documentation as of this writing.



Back to top


My Ion configuration

While you can certainly get started with Ion using the default key bindings, you may find them awkward. Wordstar or vi users may find the default keystrokes easy, but if you have spare function keys on your keyboard, you may want to change key bindings from the default. I will show my personal configuration using Ion 2, which sets up some alternate key bindings.

Note that you can keep the default key bindings and install new ones. This is probably the safest option for new users.

I need to explain my key bindings first, before I show them. My keyboard use is almost entirely Emacs and vi (programming), shell interaction, and e-mail (using the Emacs gnus mail- and news-reader). I use all the F keys (F1 through F12 bare or with Control or with Shift) for Emacs programming. I leave Alt-F1 through Alt-F12 for Ion. The extra keys on my Logitech, Sun, and Memorex keyboards are used for launching applications, and I'll explain in a moment how that works with xmodmap.

The most unusual part of my setup might be the keypad. I use the keypad only for Ion navigation. I don't need to press any modifier (Control, Alt, or Shift) keys to use the keypad, the way I have it set up. That way, when I'm typing on the keyboard, I can access all Ion navigation by just shifting my right hand to the keypad. This is, in my experience, a very efficient setup and you should consider trying it. The keypad is entirely replicated elsewhere on the keyboard so you don't need it for anything (in 99 percent of cases). The remaining 1 percent must have the keypad, so they should map my setup to other keys or maybe to the keypad with the Alt modifier pressed.

If you think you absolutely need the keypad, take a moment and think about it. What do you use on the keypad? How often do your hands land on it? How often, on the other hand (no pun intended), do you move your hand to the mouse to arrange windows on the screen? You'll probably find that the keypad is not essential to your daily computer use. As proof, consider laptop computers. If you have used one for a few days, you probably noticed there is no separate keypad. That does not bother most users, and they rarely use the common laptop "overlay keypad."

The Ion 2 configuration is written in a language called Lua. The Ion home page has links to documentation on using Lua for configuring Ion (see Resources). The object hierarchy introduced in Ion 2 is manipulated through Lua, so you should take a look at the Ion 2 documentation that shows the object hierarchy if you plan to customize any part of Ion 2 beyond the simplest changes in key bindings.

My Ion 2 configuration consists of several files. There's ion.lua, which controls the global Ion 2 options. For Ion tiling workspaces, I use ionws.lua (which has just keybindings right now). For global key bindings, I use tzz-ion-bindings.lua. Because I don't use the PWM (floating) workspaces in Ion, my customization does not include PWM key bindings. The default PWM bindings that come with Ion 2 should be sufficient; if you want them to be as simple as the keypad-oriented bindings for Ion workspaces, you'll need to think about what the keypad can do in floating workspaces. You'll probably find the mouse indispensable with floating windows (which is the reason why I don't like to use them).

You may wonder what I have against mice. They are fine pointing devices, but their extended use is suspected of being a cause for Carpal Tunnel Syndrome (CTS) and Repetitive Stress Injuries (RSI), common computer user afflictions. My experience was that cutting back on mouse usage made my wrists feel better (I nearly got CTS myself, years ago), but I am not a doctor, so you should consult one if you are concerned about CTS and RSI. Most experts recommend using the mouse less when possible, but of course overuse of the keyboard can be just as bad for your health (especially if your posture is bad). Chording (striking two or more keys at once) is particularly bad and should be avoided when possible. My setup, which is presented here, specifically avoids chording for the most-commonly used navigation tasks of moving between tabs and frames in Ion.

Using the mouse less will also improve your productivity if you type a lot, since you won't have to move your hands between the keyboard and the mouse as much. Remember, the best thing you can do to ensure healthy, productive use of the computer is to take frequent 5-minute breaks.

Here is my ion.lua configuration file. Lua is a pretty complicated language, but you should see right away that "--" indicates the beginning of a comment.


Listing 1. ion.lua
--
-- Ion main configuration file
--

-- Modules.
load_module("query")
load_module("menu")
load_module("ionws")
load_module("floatws")
load_module("dock")

-- Set default modifier. Alt should usually be mapped to Mod1 on
-- XFree86-based systems. The flying window keys are probably Mod3
-- or Mod4; see the output of 'xmodmap'.
DEFAULT_MOD = "Mod1+"

-- Maximum delay between clicks in milliseconds to be considered a
-- double click.
--set_dblclick_delay(250)

-- For keyboard resize, time (in milliseconds) to wait after latest
-- key press before automatically leaving resize mode (and doing
-- the resize in case of non-opaque move).
--set_resize_delay(1500)

-- Opaque resize?
enable_opaque_resize(true)

-- Movement commands warp the pointer to frames instead of just
-- changing focus. Enabled by default.
enable_warp(true)

-- Kludges to make apps behave better.
include("kludges")

-- Make some bindings.
include("tzz-ion-bindings")

-- Define some menus (menu module required to actually use them)
include("ion-menus")

-- How to shorten window titles when the full title doesn't fit in
-- the available space? The first-defined matching rule that succeeds
-- in making the title short enough is used.
add_shortenrule("(.*) - Mozilla(<[0-9]+>)", "$1$2$|$1$<...$2")
add_shortenrule("(.*) - Mozilla", "$1$|$1$<...")
add_shortenrule("XMMS - (.*)", "$1$|...$>$1")
add_shortenrule("[^:]+: (.*)(<[0-9]+>)", "$1$2$|$1$<...$2")
add_shortenrule("[^:]+: (.*)", "$1$|$1$<...")
add_shortenrule("(.*)(<[0-9]+>)", "$1$2$|$1$<...$2")
add_shortenrule("(.*)", "$1$|$1$<...")

-- List of directories to look for manuals in the F1 man page query.
query_man_    "/usr/man",
    "/usr/share/man",
    "/usr/X11R6/man",
    "/usr/local/man"
}

Lua has been around for about ten years, but it isn't widely known yet. It is unlike any other scripting language I know, and I'm not the only Ion user that finds it somewhat difficult. I've heard it's very rewarding once you get used to it.

If you compare the setup in Listing 1 to the default ion.lua that comes with Ion 2, you won't notice much of a difference. My ion.lua is mainly a place to load the subsequent Lua files I have customized, and which we will meet later.

My draw.lua file, which controls the drawing options in Ion 2, is entirely copied from the default look-clean.lua that comes with Ion, so it's not worth discussing here. The look-clean.lua file is well commented so you should look through it if you want to customize the colors and appearance of Ion. The only change I make in my draw.lua file is to make the frame title font larger, since I like a large font everywhere (you should use the largest font you find usable to give your eyes a break).

The global key bindings live in tzz-ion-bindings.lua. If your particular keyboard doesn't have the symbols in the same places as mine, you may need to remap them. For me, the keys assigned to workspaces 0 through 6, for instance, make a 3/4 circle around the numbers of the keypad. You can use the xev program to find the name of a key for remapping.

Remember that DEFAULT_MOD is Mod1, which on normal Linux (and most UNIX) systems is the Alt key. The Alt key is also known as the Meta key, but of course in Emacs you can access Meta with the Esc key, (while in Solaris, the Meta key looks like a diamond and the Alt key is just Alt). If you could follow the last sentence, you have my sympathies!


Listing 2. tzz-ion-bindings.lua
-- Load a library to create common queries.
include("querylib")
-- Load a library to create menu display callbacks.
include("menulib")

global_bindings{
-- use the keys *around* the numbers on the keypad to switch
-- to workspaces 0 through 6
    kpress("KP_Divide", function(s) s:switch_nth(0) end),
    kpress("KP_Multiply", function(s) s:switch_nth(1) end),
    kpress("KP_Subtract", function(s) s:switch_nth(2) end),
    kpress("KP_Add", function(s) s:switch_nth(3) end),
    kpress("KP_Enter", function(s) s:switch_nth(4) end),
    kpress("KP_Decimal", function(s) s:switch_nth(5) end),
    kpress("KP_0", function(s) s:switch_nth(6) end),

-- convenient Ion control functionality
    kpress(DEFAULT_MOD..KEYF11, querylib.query_restart),
    kpress(DEFAULT_MOD..KEYF12, querylib.query_exit),

-- sometimes I need to "walk" through workspaces, instead
-- of switching to specific ones
    kpress(DEFAULT_MOD.."Shift+Left", WScreen.switch_prev),
    kpress(DEFAULT_MOD.."Shift+Right", WScreen.switch_next),

-- these are assigned with xmodmap to keys on my Logitech keyboard
    kpress("XF86Mail", make_exec_fn("emacs -name gnus -f gnus")),
    kpress("XF86Standby", make_exec_fn("xlock -mode matrix")),
    kpress("XF86AudioMute", make_exec_fn("aumix.sh")),
    kpress("XF86AudioRaiseVolume", make_exec_fn("/usr/bin/aumix -v+3")),
    kpress("XF86AudioLowerVolume", make_exec_fn("/usr/bin/aumix -v-3")),
    kpress("Shift+XF86AudioRaiseVolume", make_exec_fn("/usr/bin/aumix -v+1")),
    kpress("Shift+XF86AudioLowerVolume", make_exec_fn("/usr/bin/aumix -v-1")),
    kpress("XF86AudioPlay", make_exec_fn("xmms --play")),
    kpress("XF86AudioStop", make_exec_fn("xmms --pause")),
    kpress("XF86AudioPrev", make_exec_fn("xmms --rew")),
    kpress("XF86AudioNext", make_exec_fn("xmms --fwd")),

-- I run a lot of terminals, so this is a way to make sure that no
-- matter what X resources are loaded, I get a consistent look to my
-- terminals.
    kpress("XF86PowerOff", make_exec_fn("Eterm -f yellow --shade 100
	--term-name xterm --double-buffer -L 500000 --font
	-misc-fixed-bold-r-normal--14-130-75-75-c-70-iso10646-1")),
    kpress("Mod1+XF86PowerOff", make_exec_fn("xterm -bg black
	-fg yellow -fn -misc-fixed-bold-r-normal--14-130-75-75-c-70-iso10646-1
	-cr blue -geometry 80x50 -name term")),

-- essential programs for me
    kpress("XF86Start", make_exec_fn("emacs")),
    kpress("XF86Search", make_exec_fn("mozilla")),

-- miscellaneous menus
    kpress("Print", make_bigmenu_fn("mainmenu")),
    mpress("Button2", make_pmenu_fn("windowlist")),
    mpress("Button3", make_pmenu_fn("mainmenu")),
}

mplex_bindings{
    kpress_waitrel(DEFAULT_MOD.."Return",
                   make_mplex_clientwin_fn(WClientWin.toggle_fullscreen)),
-- Alt+W is short and sweet, yet hard to press accidentally
    kpress_waitrel(DEFAULT_MOD.."W", WMPlex.close_sub_or_self),
}

genframe_bindings{
    -- Tag an object
    kpress(DEFAULT_MOD.."Shift+A", WGenFrame.attach_tagged),
    -- Tag viewed object
    kpress(DEFAULT_MOD.."T", make_mplex_sub_fn(WRegion.toggle_tag)),
-- 6 and 4 on the keypad go back and forth between tabs.
-- this is very essential to my setup.  I couldn't use Ion without
-- these key bindings.
    kpress("KP_6", WGenFrame.switch_next),
    kpress("KP_4", WGenFrame.switch_prev),

-- miscellaneous frame-oriented bindings
    kpress(DEFAULT_MOD.."A", querylib.query_attachclient),
    kpress(DEFAULT_MOD.."G", querylib.query_gotoclient),
    kpress(DEFAULT_MOD.."F3", querylib.query_exec),
    kpress(DEFAULT_MOD.."F4", querylib.query_ssh),
    kpress(DEFAULT_MOD.."F5", querylib.query_editfile),
    kpress(DEFAULT_MOD.."F6", querylib.query_runfile),
    kpress(DEFAULT_MOD.."F7", querylib.query_lua),
    kpress(DEFAULT_MOD.."F9", querylib.query_workspace),
    kpress(DEFAULT_MOD.."M", make_menu_fn("ctxmenu")),
    mpress("Button3", make_pmenu_fn("ctxmenu"),"tab"),
}

Finally, my Ion tiling workspace bindings. These are also keypad-oriented, of course.


Listing 3. ionws.lua
ionws_bindings{
-- I seldom have more than 2 vertical splits in an Ion workspace, so
-- I don't need dedicated keys to moving left and right between
-- them.  Since 6 and 4 were taken for tab navigation, I use the keypad
-- 5 to go to the next split to the left.  I can always go right with
-- Alt+Tab.
    kpress("KP_5" WIonWS.goto_left),
    kpress(DEFAULT_MOD.."Tab" WIonWS.goto_right),
-- horizontal splits are more frequent for me, so it's convenient to
-- move between them with the up/down (8 and 2) keypad keys.
    kpress("KP_Down", WIonWS.goto_below),
    kpress("KP_Up", WIonWS.goto_above),
}

ionframe_bindings{
-- these bindings left me make new splits in Ion.  They all use
-- the Pause key, because it's not used for anything else.
    kpress(DEFAULT_MOD.."Pause", function(frame) frame:split_empty("bottom") end),
    kpress("Pause", function(frame) frame:split_empty("right") end),
    kpress("Shift+Pause", function(frame) frame:close("right") end),
-- standard Ion functions to use the mouse when necessary
    mclick("Button1", WGenFrame.p_switch_tab, "tab"),
    mdblclick("Button1", WIonFrame.toggle_shade, "tab"),
    mdrag("Button1", WGenFrame.p_tabdrag, "tab"),
    mdrag("Button1", WGenFrame.p_resize, "border"),

    mclick("Button2", WGenFrame.p_switch_tab, "tab"),
    mdrag("Button2", WGenFrame.p_tabdrag, "tab"),

    mdrag(DEFAULT_MOD.."Button3", WGenFrame.p_resize),
}

ionframe_moveres_bindings{
-- resizing keys.  As much as I use Ion without the mouse,
-- I find it very convenient for resizing as opposed to the keyboard.
-- Your mileage may vary.
    kpress("AnyModifier+Escape", WIonFrame.cancel_resize),
    kpress("AnyModifier+Return", WIonFrame.end_resize),

    kpress("Left", function(f) f:do_resize( 1, 0, 0, 0) end),
    kpress("Right",function(f) f:do_resize( 0, 1, 0, 0) end),
    kpress("Up",   function(f) f:do_resize( 0, 0, 1, 0) end),
    kpress("Down", function(f) f:do_resize( 0, 0, 0, 1) end),
    kpress("F",    function(f) f:do_resize( 1, 0, 0, 0) end),
    kpress("B",	   function(f) f:do_resize( 0, 1, 0, 0) end),
    kpress("P",    function(f) f:do_resize( 0, 0, 1, 0) end),
    kpress("N",    function(f) f:do_resize( 0, 0, 0, 1) end),

    kpress("Shift+Left", function(f) f:do_resize(-1, 0, 0, 0) end),
    kpress("Shift+Right",function(f) f:do_resize( 0,-1, 0, 0) end),
    kpress("Shift+Up",   function(f) f:do_resize( 0, 0,-1, 0) end),
    kpress("Shift+Down", function(f) f:do_resize( 0, 0, 0,-1) end),
    kpress("Shift+F",    function(f) f:do_resize(-1, 0, 0, 0) end),
    kpress("Shift+B",    function(f) f:do_resize( 0,-1, 0, 0) end),
    kpress("Shift+P",    function(f) f:do_resize( 0, 0,-1, 0) end),
    kpress("Shift+N",    function(f) f:do_resize( 0, 0, 0,-1) end),
}

Note that ionws.lua is loaded automatically when you load the ionws module in ion.lua. That's why there's no explicit "require ionws" in my ion.lua file.



Back to top


Conclusion

Variety is the spice of life, and I hope you get plenty of spice from this article. Ion is an unorthodox window manager that will prove itself if you give it a chance. These days, when I look at Windows and other floating-window desktop environments, I wonder how much more efficient all of their users would be without the distraction of floating windows. This is not to say floating windows are always bad, only that in most situations they waste time and screen space when they overlap, and the user needs to move them around.

The Ion home page has many links and explanations of Ion's philosophy and development. You should visit it for the screenshots too. Just remember that Ion's beauty is that it's simple and unobtrusive, so just because you don't see fancy window frames and animated backgrounds doesn't mean Ion is not working hard to make your computing environment better.



Resources

  • The home page of the Ion window manager is essential for anyone interested in Ion. The site includes downloads, documentation, discussion lists, links, and screen shots of Ion in action.

  • See also How to Run the Ion Window Manager on OSX if you're an OSX user.

  • X.org is the foundation behind the X Window System.

  • CDE is an historically important manager, but not used widely anymore. It uses DTWM by default.

  • KDE is one of the premier UNIX desktop environments today. It uses KWin by default.

  • Gnome is another premier UNIX desktop environment today. It uses the Metacity WM by default.

  • Enlightenment is a great manager when you need all the bells and whistles. Other impressive-looking window managers include fvwm and icewm (this latter one is actually quite compact, in addition to being fancy).

  • In addition to Ion, other lightweight window managers include LarsWM, TrsWM, and Ratpoison. The last of these, Ratpoison, is based on GNU screen, and also lets you do away with mice. See also this discussion of GNU screen, Ratpoison, and other minimal window managers.

  • Ion uses the 10-plus year old Lua configuration and scripting language. There are many places to learn more about Lua: the book Programming in Lua (Ingram/Bertram Books, 2003) is available online; there is an active lua-users mailing list; and the lua-users wiki has links to tutorials and an unofficial FAQ.

  • The classic resource on key remapping is Jamie Zawinksi's XKey Caps page; see also the xmodmap help page from MIT.

  • Read all of Ted's Perl articles in the "Cultured Perl" series on developerWorks.

  • For an overview of XFree86 and a tutorial on getting it up and running, read Introduction to XFree86 4.x (developerWorks, October 2001).

  • Ted talks more about the Enlightenment window manager as part of an optimized Perl developer's environment in Cultured Perl: A programmer's Linux-oriented setup (developerWorks, March 2001).

  • Find more resources for Linux developers in the developerWorks Linux zone.

  • Browse for books on these and other technical topics.

  • Download no-charge trial versions of IBM products that run on Linux, including WebSphere® Studio Site Developer, WebSphere SDK for Web services, WebSphere Application Server, DB2® Universal Database Personal Developers Edition, Tivoli® Access Manager, and Lotus® Domino Server, from the Speed-start your Linux app section of developerWorks. For an even speedier start, help yourself to a product-by-product collection of how-to articles and tech support.


About the author

Author photo

Teodor Zlatanov graduated with an M.S. in computer engineering from Boston University in 1999. He has worked as a programmer since 1992, using Perl, Java, C, and C++. His interests are in open source work, Perl, text parsing, 3-tier client-server database architectures, and UNIX system administration. Suggestions and corrections are welcome over e-mail; you can contact him at tzz@bu.edu.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top